encre_css/plugins/background/background_image/
mod.rs1#![doc = include_str!("README.md")]
2#![doc(alias("background", "bg", "gradient"))]
3use std::borrow::Cow;
4
5use crate::prelude::build_plugin::*;
6
7const INTERPOLATION_MODES: &[&str] = &[
8 "srgb",
9 "hsl",
10 "oklab",
11 "oklch",
12 "longer",
13 "shorter",
14 "increasing",
15 "decreasing",
16];
17
18#[derive(Debug)]
19pub(crate) struct PluginDefinition;
20
21impl Plugin for PluginDefinition {
22 fn can_handle(&self, context: ContextCanHandle) -> bool {
23 match context.modifier {
24 Modifier::Builtin { value, .. } => [
25 "none",
26 "gradient-to-t",
27 "gradient-to-tr",
28 "gradient-to-r",
29 "gradient-to-br",
30 "gradient-to-b",
31 "gradient-to-bl",
32 "gradient-to-l",
33 "gradient-to-tl",
34 ]
35 .contains(value),
36 Modifier::Arbitrary { hint, value, .. } => {
37 *hint == "image" || *hint == "url" || (hint.is_empty() && is_matching_image(value))
38 }
39 }
40 }
41
42 fn handle(&self, context: &mut ContextHandle) {
43 match context.modifier {
44 Modifier::Builtin { value, .. } => match *value {
45 "none" => context.buffer.line("background-image: none;"),
46 "gradient-to-t" => context
47 .buffer
48 .line("background-image: linear-gradient(to top in oklab, var(--en-gradient-stops));"),
49 "gradient-to-tr" => context.buffer.line(
50 "background-image: linear-gradient(to top right in oklab, var(--en-gradient-stops));",
51 ),
52 "gradient-to-r" => context
53 .buffer
54 .line("background-image: linear-gradient(to right in oklab, var(--en-gradient-stops));"),
55 "gradient-to-br" => context.buffer.line(
56 "background-image: linear-gradient(to bottom right in oklab, var(--en-gradient-stops));",
57 ),
58 "gradient-to-b" => context.buffer.line(
59 "background-image: linear-gradient(to bottom in oklab, var(--en-gradient-stops));",
60 ),
61 "gradient-to-bl" => context.buffer.line(
62 "background-image: linear-gradient(to bottom left in oklab, var(--en-gradient-stops));",
63 ),
64 "gradient-to-l" => context
65 .buffer
66 .line("background-image: linear-gradient(to left in oklab, var(--en-gradient-stops));"),
67 "gradient-to-tl" => context.buffer.line(
68 "background-image: linear-gradient(to top left in oklab, var(--en-gradient-stops));",
69 ),
70 _ => unreachable!(),
71 },
72 Modifier::Arbitrary { value, .. } => {
73 context
74 .buffer
75 .line(format_args!("background-image: {value};"));
76 }
77 }
78 }
79}
80
81#[derive(Debug)]
82pub(crate) struct PluginLinearDefinition;
83
84impl Plugin for PluginLinearDefinition {
85 fn can_handle(&self, context: ContextCanHandle) -> bool {
86 match context.modifier {
87 Modifier::Builtin { value, .. } => {
88 let (gradient_type, interpolation_mode) = if let Some(index) = value.find('/') {
89 let (before, after) = value.split_at(index);
90 (before, &after[1..])
91 } else {
92 (*value, "oklab")
93 };
94
95 ([
96 "to-t", "to-tr", "to-r", "to-br", "to-b", "to-bl", "to-l", "to-tl",
97 ]
98 .contains(&gradient_type)
99 || gradient_type.parse::<usize>().is_ok())
100 && INTERPOLATION_MODES.contains(&interpolation_mode)
101 }
102 Modifier::Arbitrary { value, .. } => is_matching_all(value),
103 }
104 }
105
106 fn handle(&self, context: &mut ContextHandle) {
107 match context.modifier {
108 Modifier::Builtin { is_negative, value } => {
109 let (gradient_type, interpolation_mode) = if let Some(index) = value.find('/') {
110 let (before, after) = value.split_at(index);
111 (before, &after[1..])
112 } else {
113 (*value, "oklab")
115 };
116
117 let interpolation_mode = match interpolation_mode {
118 "longer" | "shorter" | "increasing" | "decreasing" => {
119 Cow::Owned(format!("oklch {interpolation_mode} hue"))
120 }
121 _ => Cow::Borrowed(interpolation_mode),
122 };
123
124 match gradient_type {
125 "none" => context.buffer.line("background-image: none;"),
126 "to-t" => context
127 .buffer
128 .line(format_args!("background-image: linear-gradient(to top in {interpolation_mode}, var(--en-gradient-stops));")),
129 "to-tr" => context.buffer.line(
130 format_args!("background-image: linear-gradient(to top right in {interpolation_mode}, var(--en-gradient-stops));"),
131 ),
132 "to-r" => context
133 .buffer
134 .line(format_args!("background-image: linear-gradient(to right in {interpolation_mode}, var(--en-gradient-stops));")),
135 "to-br" => context.buffer.line(
136 format_args!("background-image: linear-gradient(to bottom right in {interpolation_mode}, var(--en-gradient-stops));"),
137 ),
138 "to-b" => context.buffer.line(
139 format_args!("background-image: linear-gradient(to bottom in {interpolation_mode}, var(--en-gradient-stops));"),
140 ),
141 "to-bl" => context.buffer.line(
142 format_args!("background-image: linear-gradient(to bottom left in {interpolation_mode}, var(--en-gradient-stops));"),
143 ),
144 "to-l" => context
145 .buffer
146 .line(format_args!("background-image: linear-gradient(to left in {interpolation_mode}, var(--en-gradient-stops));")),
147 "to-tl" => context.buffer.line(
148 format_args!("background-image: linear-gradient(to top left in {interpolation_mode}, var(--en-gradient-stops));"),
149 ),
150 _ => {
151 let angle = value.parse::<usize>().unwrap();
152 context.buffer.line(
153 format_args!("background-image: linear-gradient({}{angle}deg in {interpolation_mode}, var(--en-gradient-stops));", if *is_negative { "-" } else { "" }),
154 );
155 },
156 }
157 }
158 Modifier::Arbitrary { value, .. } => {
159 context
160 .buffer
161 .line(format_args!("background-image: linear-gradient({value});"));
162 }
163 }
164 }
165}
166
167#[derive(Debug)]
168pub(crate) struct PluginRadialDefinition;
169
170impl Plugin for PluginRadialDefinition {
171 fn can_handle(&self, context: ContextCanHandle) -> bool {
172 match context.modifier {
173 Modifier::Builtin { value, .. } => {
174 let (gradient_type, interpolation_mode) = if let Some(index) = value.find('/') {
175 let (before, after) = value.split_at(index);
176 (before, &after[1..])
177 } else {
178 (*value, "oklab")
179 };
180
181 gradient_type.is_empty() && INTERPOLATION_MODES.contains(&interpolation_mode)
182 }
183 Modifier::Arbitrary { value, .. } => is_matching_all(value),
184 }
185 }
186
187 fn handle(&self, context: &mut ContextHandle) {
188 match context.modifier {
189 Modifier::Builtin { value, .. } => {
190 let (_, interpolation_mode) = if let Some(index) = value.find('/') {
191 let (before, after) = value.split_at(index);
192 (before, &after[1..])
193 } else {
194 (*value, "oklab")
196 };
197
198 let interpolation_mode = match interpolation_mode {
199 "longer" | "shorter" | "increasing" | "decreasing" => {
200 Cow::Owned(format!("oklch {interpolation_mode} hue"))
201 }
202 _ => Cow::Borrowed(interpolation_mode),
203 };
204
205 context
206 .buffer
207 .line(format_args!("background-image: radial-gradient(in {interpolation_mode}, var(--en-gradient-stops));"));
208 }
209 Modifier::Arbitrary { value, .. } => {
210 context
211 .buffer
212 .line(format_args!("background-image: radial-gradient({value});"));
213 }
214 }
215 }
216}
217
218#[derive(Debug)]
219pub(crate) struct PluginConicDefinition;
220
221impl Plugin for PluginConicDefinition {
222 fn can_handle(&self, context: ContextCanHandle) -> bool {
223 match context.modifier {
224 Modifier::Builtin { value, .. } => {
225 let (gradient_type, interpolation_mode) = if let Some(index) = value.find('/') {
226 let (before, after) = value.split_at(index);
227 (before, &after[1..])
228 } else {
229 (*value, "oklab")
230 };
231
232 (gradient_type.is_empty() || gradient_type.parse::<usize>().is_ok())
233 && INTERPOLATION_MODES.contains(&interpolation_mode)
234 }
235 Modifier::Arbitrary { value, .. } => is_matching_all(value),
236 }
237 }
238
239 fn handle(&self, context: &mut ContextHandle) {
240 match context.modifier {
241 Modifier::Builtin { is_negative, value } => {
242 let (gradient_type, interpolation_mode) = if let Some(index) = value.find('/') {
243 let (before, after) = value.split_at(index);
244 (before, &after[1..])
245 } else {
246 (*value, "oklab")
248 };
249
250 let interpolation_mode = match interpolation_mode {
251 "longer" | "shorter" | "increasing" | "decreasing" => {
252 Cow::Owned(format!("oklch {interpolation_mode} hue"))
253 }
254 _ => Cow::Borrowed(interpolation_mode),
255 };
256
257 if gradient_type.is_empty() {
258 context
259 .buffer
260 .line(format_args!("background-image: conic-gradient(in {interpolation_mode}, var(--en-gradient-stops));"));
261 } else {
262 let angle = value.parse::<usize>().unwrap();
263 context
264 .buffer
265 .line(format_args!("background-image: conic-gradient(from {}{angle}deg in {interpolation_mode}, var(--en-gradient-stops));", if *is_negative { "-" } else { "" }));
266 }
267 }
268 Modifier::Arbitrary { value, .. } => {
269 context
270 .buffer
271 .line(format_args!("background-image: conic-gradient({value});"));
272 }
273 }
274 }
275}