encre_css/lib.rs
1//! A TailwindCSS-compatible utility-first CSS generation library written in Rust.
2//!
3//! ## A brief introduction to utility-first CSS frameworks
4//!
5//! Traditionally, whenever you need to style something on the web, you write CSS in a dedicated
6//! file and apply the rules using classes in your HTML, like that:
7//!
8//! <div style="margin-top: 1rem; margin-bottom: 1rem;"></div>
9//!
10//! <div class="notification">
11//! <div class="notification-header">
12//! <div class="app-icon"></div>
13//! A new Javascript library has been released!
14//! </div>
15//! <div class="notification-body">
16//! The library <code>react</code> has just been released, did you know it?
17//! It is <i>a JavaScript library for creating user interfaces</i>.
18//! </div>
19//! <div class="notification-footer">
20//! <a href="#" class="dismiss-button">Dismiss</a>
21//! <a href="#" class="try-button">Try it here!</a>
22//! </div>
23//! </div>
24//!
25//! <div style="margin-top: 1rem; margin-bottom: 1rem;"></div>
26//!
27//! <style>
28//! .notification {
29//! width: 30rem;
30//! box-shadow: 1px 1px 5px 2px #e5e7eb;
31//! border-radius: 0.8rem;
32//! font-family: sans-serif;
33//! }
34//!
35//! .notification-header {
36//! padding: 0.5rem 1rem;
37//! display: flex;
38//! align-items: center;
39//! }
40//!
41//! .app-icon {
42//! background-color: rgb(37 99 235);
43//! border-radius: 50%;
44//! width: 1.2rem;
45//! height: 1.2rem;
46//! margin-right: 1rem;
47//! }
48//!
49//! .notification-body {
50//! padding: 1rem 1.5rem 1.5rem 1.5rem;
51//! }
52//!
53//! .notification-footer {
54//! display: flex;
55//! justify-content: space-between;
56//! }
57//!
58//! .dismiss-button {
59//! color: rgb(225 29 72);
60//! padding: 0.5rem 1rem;
61//! }
62//!
63//! .try-button {
64//! background-color: rgb(37 99 235);
65//! color: white;
66//! border-bottom-right-radius: 0.8rem;
67//! border-top-left-radius: 0.8rem;
68//! padding: 0.5rem 1rem;
69//! box-shadow: 1px 1px 5px 1px rgb(37 99 235);
70//! }
71//! </style>
72//
73//! <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw"><div</span> class=<span class="string">"notification"</span><span class="kw">>
74//! <div</span> class=<span class="string">"notification-header"</span><span class="kw">></span>
75//! <span class="kw"><div</span> class=<span class="string">"app-icon"</span><span class="kw">></div></span>
76//! A new Javascript library has been released!
77//! <span class="kw"></div></span>
78//! <span class="kw"><div</span> class=<span class="string">"notification-body"</span><span class="kw">></span>
79//! The library <span class="kw"><code></span>react<span class="kw"></code></span> has just been released, did you know it?
80//! It is <span class="kw"><i></span>a JavaScript library for creating user interfaces<span class="kw"></i></span>.
81//! <span class="kw"></div></span>
82//! <span class="kw"><div</span> class=<span class="string">"notification-footer"</span><span class="kw">></span>
83//! <span class="kw"><a</span> href=<span class="string">"#"</span> class=<span class="string">"dismiss-button"</span><span class="kw">></span>Dismiss<span class="kw"></a></span>
84//! <span class="kw"><a</span> href=<span class="string">"#"</span> class=<span class="string">"try-button"</span>>Try it here!<span class="kw"></a></span>
85//! <span class="kw"></div></span>
86//! <span class="kw"></div></span>
87//! </code></pre></div>
88//!
89//! However styling this way is pretty boring because you need to think of good class names and
90//! you have to repeatedly switch between several files, it could be better. Utility-first CSS
91//! frameworks takes a new approach by using minimal and pre-defined class names directly linked to
92//! its CSS rule content. The CSS file will then be generated
93//! [on-demand](https://antfu.me/posts/reimagine-atomic-css#on-demand-way) allowing the classes
94//! to be very flexible and customizable. This approach lets you quickly prototype visual HTML
95//! elements and encourages you to turn them later into components using your favorite web framework.
96//! It also makes building a responsive website easier and forces it to be closer to your design
97//! system:
98//
99//! <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw"><div</span> class=<span class="string">"w-128 text-md shadow-[1px_1px_10px_2px_#e5e7eb] rounded-xl"</span><span class="kw">>
100//! <div</span> class=<span class="string">"p-3 flex items-center"</span><span class="kw">></span>
101//! <span class="kw"><div</span> class=<span class="string">"bg-blue-500 rounded-full w-5 h-5 mr-3"</span><span class="kw">></div></span>
102//! A new Javascript library has been released!
103//! <span class="kw"></div></span>
104//! <span class="kw"><div</span> class=<span class="string">"p-6 pt-4"</span><span class="kw">></span>
105//! The library <span class="kw"><code></span>react<span class="kw"></code></span> has just been released, did you know it?
106//! It is <span class="kw"><i></span>a JavaScript library for creating user interfaces<span class="kw"></i></span>.
107//! <span class="kw"></div></span>
108//! <span class="kw"><div</span> class=<span class="string">"flex justify-between"</span><span class="kw">></span>
109//! <span class="kw"><a</span> href=<span class="string">"#"</span> class=<span class="string">"p-3 text-rose-600"</span><span class="kw">></span>Dismiss<span class="kw"></a></span>
110//! <span class="kw"><a</span> href=<span class="string">"#"</span> class=<span class="string">"p-3 bg-blue-600 text-white rounded-br-xl rounded-tl-xl shadow shadow-blue-600"</span>>Try it here!<span class="kw"></a></span>
111//! <span class="kw"></div></span>
112//! <span class="kw"></div></span>
113//! </code></pre></div>
114//!
115//! There is already a lot of utility-first frameworks like [Tailwind
116//! CSS](https://tailwindcss.com), [Windi CSS](https://windicss.org), [Twind](https://twind.dev)
117//! and [Uno CSS](https://uno.antfu.me), but `encre-css` is unique because it is written in Rust and
118//! uses a new architecture, making it **the fastest utility-first framework** (according to the
119//! benchmark [here](https://gitlab.com/encre-org/encre-css-bench) based on
120//! [Uno CSS' benchmark](https://github.com/unocss/unocss/tree/main/bench)). It is also very
121//! [customizable](crate::plugins).
122//!
123//! ## Getting started
124//!
125//! Add `encre-css` to your `Cargo.toml`:
126//!
127//! <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[dependencies]</span>
128//! encre-css = <span class="string">"0.19.1"</span></code></pre></div>
129//!
130//! Generating styles takes two steps:
131//! - You need to _configure_ the CSS generation by making a [`Config`] structure.
132//! It can be created by reading a [TOML](https://toml.io) file using
133//! [`Config::from_file`] or by using the default values with [`Config::default`];
134//! - Then, you need to _generate the styles_ based on some sources using the [`generate`]
135//! function. This function will scan the content of the sources, extract atomic classes and
136//! generate the style needed for each class.
137//!
138//! ### Example
139//!
140//! ```
141//! use encre_css::Config;
142//!
143//! let config = Config::default();
144//! let generated = encre_css::generate(
145//! [r#"<p class="w-auto bg-red-200 rounded-md">Hello world!</p>"#],
146//! &config,
147//! );
148//!
149//! assert!(generated.ends_with(".w-auto {
150//! width: auto;
151//! }
152//!
153//! .rounded-md {
154//! border-radius: 0.375rem;
155//! }
156//!
157//! .bg-red-200 {
158//! background-color: oklch(88.5% .062 18.334);
159//! }"));
160//! ```
161//!
162//! ### What to do next
163//!
164//! 1. The documentation about the composition of a class (also named selector) is [here](crate::selector).
165//! 2. The documentation about all utility classes (handled by plugins) is [here](crate::plugins).
166//! 3. The documentation about the reset CSS commonly used (also named preflight) is [here](crate::preflight).
167//!
168//! ## Command line interface
169//!
170//! A command line interface is also available. Install it using:
171//!
172//! ```bash
173//! cargo install encre-css-cli
174//! ```
175//!
176//! Then run `encrecss --help` for instructions on how to use it.
177#![doc(html_logo_url = "https://gitlab.com/encre-org/encre-css/raw/main/.assets/logo.png")]
178#![forbid(unsafe_code)]
179#![warn(
180 missing_docs,
181 missing_debug_implementations,
182 trivial_casts,
183 trivial_numeric_casts,
184 unstable_features,
185 unused_import_braces,
186 unused_qualifications,
187 unreachable_pub,
188 rustdoc::private_doc_tests,
189 rustdoc::broken_intra_doc_links,
190 rustdoc::private_intra_doc_links,
191 clippy::unnecessary_wraps,
192 clippy::too_many_lines,
193 clippy::string_to_string,
194 clippy::explicit_iter_loop,
195 clippy::unnecessary_cast,
196 clippy::missing_errors_doc,
197 clippy::pedantic,
198 clippy::clone_on_ref_ptr,
199 clippy::non_ascii_literal,
200 clippy::dbg_macro,
201 clippy::map_err_ignore,
202 clippy::use_debug,
203 clippy::map_err_ignore,
204 clippy::useless_let_if_seq,
205 clippy::verbose_file_reads,
206 clippy::panic,
207 clippy::unimplemented,
208 clippy::todo
209)]
210#![allow(clippy::module_name_repetitions, clippy::must_use_candidate)]
211
212pub mod config;
213pub mod error;
214pub mod generator;
215pub mod plugins;
216pub mod preflight;
217pub mod scanner;
218pub mod selector;
219pub mod utils;
220
221#[doc(inline)]
222pub use config::Config;
223
224#[doc(inline)]
225pub use error::{Error, Result};
226
227#[doc(inline)]
228pub use generator::generate;
229
230#[doc(inline)]
231pub use preflight::Preflight;
232
233#[doc(inline)]
234pub use scanner::Scanner;
235
236pub use toml::toml;
237
238/// Various helper preludes.
239pub mod prelude {
240 /// Prelude including all necessary structures, functions and modules used to build a new plugin.
241 ///
242 /// It should be included using:
243 ///
244 /// ```
245 /// use encre_css::prelude::build_plugin::*;
246 /// ```
247 pub mod build_plugin {
248 pub use crate::{
249 generator::{generate_at_rules, generate_class, generate_wrapper},
250 generator::{ContextCanHandle, ContextHandle},
251 plugins::Plugin,
252 selector::Modifier,
253 utils::{buffer::Buffer, color, format_negative, shadow, spacing, value_matchers::*},
254 };
255 pub use std::fmt::{self, Write};
256 }
257}