1use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum Scale {
13 Zero,
15 Fifty,
17 SeventyFive,
19 Ninety,
21 NinetyFive,
23 Hundred,
25 HundredFive,
27 HundredTen,
29 HundredTwentyFive,
31 HundredFifty,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum Rotate {
38 Zero,
40 One,
42 Two,
44 Three,
46 Six,
48 Twelve,
50 FortyFive,
52 Ninety,
54 HundredEighty,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
60pub enum Translate {
61 Zero,
63 One,
65 Two,
67 Three,
69 Four,
71 Five,
73 Six,
75 Seven,
77 Eight,
79 Nine,
81 Ten,
83 Eleven,
85 Twelve,
87 Fourteen,
89 Sixteen,
91 Twenty,
93 TwentyFour,
95 TwentyEight,
97 ThirtyTwo,
99 ThirtySix,
101 Forty,
103 FortyFour,
105 FortyEight,
107 FiftyTwo,
109 FiftySix,
111 Sixty,
113 SixtyFour,
115 SeventyTwo,
117 Eighty,
119 NinetySix,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
125pub enum Skew {
126 Zero,
128 One,
130 Two,
132 Three,
134 Six,
136 Twelve,
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
142pub enum TransformOrigin {
143 Center,
145 Top,
147 TopRight,
149 Right,
151 BottomRight,
153 Bottom,
155 BottomLeft,
157 Left,
159 TopLeft,
161}
162
163impl Scale {
164 pub fn to_class_name(&self) -> String {
165 match self {
166 Scale::Zero => "0".to_string(),
167 Scale::Fifty => "50".to_string(),
168 Scale::SeventyFive => "75".to_string(),
169 Scale::Ninety => "90".to_string(),
170 Scale::NinetyFive => "95".to_string(),
171 Scale::Hundred => "100".to_string(),
172 Scale::HundredFive => "105".to_string(),
173 Scale::HundredTen => "110".to_string(),
174 Scale::HundredTwentyFive => "125".to_string(),
175 Scale::HundredFifty => "150".to_string(),
176 }
177 }
178
179 pub fn to_css_value(&self) -> String {
180 match self {
181 Scale::Zero => "0".to_string(),
182 Scale::Fifty => "0.5".to_string(),
183 Scale::SeventyFive => "0.75".to_string(),
184 Scale::Ninety => "0.9".to_string(),
185 Scale::NinetyFive => "0.95".to_string(),
186 Scale::Hundred => "1".to_string(),
187 Scale::HundredFive => "1.05".to_string(),
188 Scale::HundredTen => "1.1".to_string(),
189 Scale::HundredTwentyFive => "1.25".to_string(),
190 Scale::HundredFifty => "1.5".to_string(),
191 }
192 }
193}
194
195impl Rotate {
196 pub fn to_class_name(&self) -> String {
197 match self {
198 Rotate::Zero => "0".to_string(),
199 Rotate::One => "1".to_string(),
200 Rotate::Two => "2".to_string(),
201 Rotate::Three => "3".to_string(),
202 Rotate::Six => "6".to_string(),
203 Rotate::Twelve => "12".to_string(),
204 Rotate::FortyFive => "45".to_string(),
205 Rotate::Ninety => "90".to_string(),
206 Rotate::HundredEighty => "180".to_string(),
207 }
208 }
209
210 pub fn to_css_value(&self) -> String {
211 match self {
212 Rotate::Zero => "0deg".to_string(),
213 Rotate::One => "1deg".to_string(),
214 Rotate::Two => "2deg".to_string(),
215 Rotate::Three => "3deg".to_string(),
216 Rotate::Six => "6deg".to_string(),
217 Rotate::Twelve => "12deg".to_string(),
218 Rotate::FortyFive => "45deg".to_string(),
219 Rotate::Ninety => "90deg".to_string(),
220 Rotate::HundredEighty => "180deg".to_string(),
221 }
222 }
223}
224
225impl Translate {
226 pub fn to_class_name(&self) -> String {
227 match self {
228 Translate::Zero => "0".to_string(),
229 Translate::One => "1".to_string(),
230 Translate::Two => "2".to_string(),
231 Translate::Three => "3".to_string(),
232 Translate::Four => "4".to_string(),
233 Translate::Five => "5".to_string(),
234 Translate::Six => "6".to_string(),
235 Translate::Seven => "7".to_string(),
236 Translate::Eight => "8".to_string(),
237 Translate::Nine => "9".to_string(),
238 Translate::Ten => "10".to_string(),
239 Translate::Eleven => "11".to_string(),
240 Translate::Twelve => "12".to_string(),
241 Translate::Fourteen => "14".to_string(),
242 Translate::Sixteen => "16".to_string(),
243 Translate::Twenty => "20".to_string(),
244 Translate::TwentyFour => "24".to_string(),
245 Translate::TwentyEight => "28".to_string(),
246 Translate::ThirtyTwo => "32".to_string(),
247 Translate::ThirtySix => "36".to_string(),
248 Translate::Forty => "40".to_string(),
249 Translate::FortyFour => "44".to_string(),
250 Translate::FortyEight => "48".to_string(),
251 Translate::FiftyTwo => "52".to_string(),
252 Translate::FiftySix => "56".to_string(),
253 Translate::Sixty => "60".to_string(),
254 Translate::SixtyFour => "64".to_string(),
255 Translate::SeventyTwo => "72".to_string(),
256 Translate::Eighty => "80".to_string(),
257 Translate::NinetySix => "96".to_string(),
258 }
259 }
260
261 pub fn to_css_value(&self) -> String {
262 match self {
263 Translate::Zero => "0px".to_string(),
264 Translate::One => "0.25rem".to_string(),
265 Translate::Two => "0.5rem".to_string(),
266 Translate::Three => "0.75rem".to_string(),
267 Translate::Four => "1rem".to_string(),
268 Translate::Five => "1.25rem".to_string(),
269 Translate::Six => "1.5rem".to_string(),
270 Translate::Seven => "1.75rem".to_string(),
271 Translate::Eight => "2rem".to_string(),
272 Translate::Nine => "2.25rem".to_string(),
273 Translate::Ten => "2.5rem".to_string(),
274 Translate::Eleven => "2.75rem".to_string(),
275 Translate::Twelve => "3rem".to_string(),
276 Translate::Fourteen => "3.5rem".to_string(),
277 Translate::Sixteen => "4rem".to_string(),
278 Translate::Twenty => "5rem".to_string(),
279 Translate::TwentyFour => "6rem".to_string(),
280 Translate::TwentyEight => "7rem".to_string(),
281 Translate::ThirtyTwo => "8rem".to_string(),
282 Translate::ThirtySix => "9rem".to_string(),
283 Translate::Forty => "10rem".to_string(),
284 Translate::FortyFour => "11rem".to_string(),
285 Translate::FortyEight => "12rem".to_string(),
286 Translate::FiftyTwo => "13rem".to_string(),
287 Translate::FiftySix => "14rem".to_string(),
288 Translate::Sixty => "15rem".to_string(),
289 Translate::SixtyFour => "16rem".to_string(),
290 Translate::SeventyTwo => "18rem".to_string(),
291 Translate::Eighty => "20rem".to_string(),
292 Translate::NinetySix => "24rem".to_string(),
293 }
294 }
295}
296
297impl Skew {
298 pub fn to_class_name(&self) -> String {
299 match self {
300 Skew::Zero => "0".to_string(),
301 Skew::One => "1".to_string(),
302 Skew::Two => "2".to_string(),
303 Skew::Three => "3".to_string(),
304 Skew::Six => "6".to_string(),
305 Skew::Twelve => "12".to_string(),
306 }
307 }
308
309 pub fn to_css_value(&self) -> String {
310 match self {
311 Skew::Zero => "0deg".to_string(),
312 Skew::One => "1deg".to_string(),
313 Skew::Two => "2deg".to_string(),
314 Skew::Three => "3deg".to_string(),
315 Skew::Six => "6deg".to_string(),
316 Skew::Twelve => "12deg".to_string(),
317 }
318 }
319}
320
321impl TransformOrigin {
322 pub fn to_class_name(&self) -> String {
323 match self {
324 TransformOrigin::Center => "center".to_string(),
325 TransformOrigin::Top => "top".to_string(),
326 TransformOrigin::TopRight => "top-right".to_string(),
327 TransformOrigin::Right => "right".to_string(),
328 TransformOrigin::BottomRight => "bottom-right".to_string(),
329 TransformOrigin::Bottom => "bottom".to_string(),
330 TransformOrigin::BottomLeft => "bottom-left".to_string(),
331 TransformOrigin::Left => "left".to_string(),
332 TransformOrigin::TopLeft => "top-left".to_string(),
333 }
334 }
335
336 pub fn to_css_value(&self) -> String {
337 match self {
338 TransformOrigin::Center => "center".to_string(),
339 TransformOrigin::Top => "top".to_string(),
340 TransformOrigin::TopRight => "top right".to_string(),
341 TransformOrigin::Right => "right".to_string(),
342 TransformOrigin::BottomRight => "bottom right".to_string(),
343 TransformOrigin::Bottom => "bottom".to_string(),
344 TransformOrigin::BottomLeft => "bottom left".to_string(),
345 TransformOrigin::Left => "left".to_string(),
346 TransformOrigin::TopLeft => "top left".to_string(),
347 }
348 }
349}
350
351impl fmt::Display for Scale {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(f, "{}", self.to_class_name())
354 }
355}
356
357impl fmt::Display for Rotate {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 write!(f, "{}", self.to_class_name())
360 }
361}
362
363impl fmt::Display for Translate {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 write!(f, "{}", self.to_class_name())
366 }
367}
368
369impl fmt::Display for Skew {
370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371 write!(f, "{}", self.to_class_name())
372 }
373}
374
375impl fmt::Display for TransformOrigin {
376 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377 write!(f, "{}", self.to_class_name())
378 }
379}
380
381pub trait ScaleUtilities {
383 fn scale(self, scale: Scale) -> Self;
384 fn scale_x(self, scale: Scale) -> Self;
385 fn scale_y(self, scale: Scale) -> Self;
386}
387
388impl ScaleUtilities for ClassBuilder {
389 fn scale(self, scale: Scale) -> Self {
390 self.class(format!("scale-{}", scale.to_class_name()))
391 }
392
393 fn scale_x(self, scale: Scale) -> Self {
394 self.class(format!("scale-x-{}", scale.to_class_name()))
395 }
396
397 fn scale_y(self, scale: Scale) -> Self {
398 self.class(format!("scale-y-{}", scale.to_class_name()))
399 }
400}
401
402pub trait RotateUtilities {
404 fn rotate(self, rotate: Rotate) -> Self;
405}
406
407impl RotateUtilities for ClassBuilder {
408 fn rotate(self, rotate: Rotate) -> Self {
409 self.class(format!("rotate-{}", rotate.to_class_name()))
410 }
411}
412
413pub trait TranslateUtilities {
415 fn translate_x(self, translate: Translate) -> Self;
416 fn translate_y(self, translate: Translate) -> Self;
417}
418
419impl TranslateUtilities for ClassBuilder {
420 fn translate_x(self, translate: Translate) -> Self {
421 self.class(format!("translate-x-{}", translate.to_class_name()))
422 }
423
424 fn translate_y(self, translate: Translate) -> Self {
425 self.class(format!("translate-y-{}", translate.to_class_name()))
426 }
427}
428
429pub trait SkewUtilities {
431 fn skew_x(self, skew: Skew) -> Self;
432 fn skew_y(self, skew: Skew) -> Self;
433}
434
435impl SkewUtilities for ClassBuilder {
436 fn skew_x(self, skew: Skew) -> Self {
437 self.class(format!("skew-x-{}", skew.to_class_name()))
438 }
439
440 fn skew_y(self, skew: Skew) -> Self {
441 self.class(format!("skew-y-{}", skew.to_class_name()))
442 }
443}
444
445pub trait TransformOriginUtilities {
447 fn transform_origin(self, origin: TransformOrigin) -> Self;
448}
449
450impl TransformOriginUtilities for ClassBuilder {
451 fn transform_origin(self, origin: TransformOrigin) -> Self {
452 self.class(format!("origin-{}", origin.to_class_name()))
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
461 fn test_scale_utilities() {
462 let classes = ClassBuilder::new()
463 .scale(Scale::Zero)
464 .scale(Scale::Fifty)
465 .scale(Scale::SeventyFive)
466 .scale(Scale::Ninety)
467 .scale(Scale::NinetyFive)
468 .scale(Scale::Hundred)
469 .scale(Scale::HundredFive)
470 .scale(Scale::HundredTen)
471 .scale(Scale::HundredTwentyFive)
472 .scale(Scale::HundredFifty)
473 .scale_x(Scale::Hundred)
474 .scale_y(Scale::Hundred)
475 .build();
476
477 let css_classes = classes.to_css_classes();
478 assert!(css_classes.contains("scale-0"));
479 assert!(css_classes.contains("scale-50"));
480 assert!(css_classes.contains("scale-75"));
481 assert!(css_classes.contains("scale-90"));
482 assert!(css_classes.contains("scale-95"));
483 assert!(css_classes.contains("scale-100"));
484 assert!(css_classes.contains("scale-105"));
485 assert!(css_classes.contains("scale-110"));
486 assert!(css_classes.contains("scale-125"));
487 assert!(css_classes.contains("scale-150"));
488 assert!(css_classes.contains("scale-x-100"));
489 assert!(css_classes.contains("scale-y-100"));
490 }
491
492 #[test]
493 fn test_rotate_utilities() {
494 let classes = ClassBuilder::new()
495 .rotate(Rotate::Zero)
496 .rotate(Rotate::One)
497 .rotate(Rotate::Two)
498 .rotate(Rotate::Three)
499 .rotate(Rotate::Six)
500 .rotate(Rotate::Twelve)
501 .rotate(Rotate::FortyFive)
502 .rotate(Rotate::Ninety)
503 .rotate(Rotate::HundredEighty)
504 .build();
505
506 let css_classes = classes.to_css_classes();
507 assert!(css_classes.contains("rotate-0"));
508 assert!(css_classes.contains("rotate-1"));
509 assert!(css_classes.contains("rotate-2"));
510 assert!(css_classes.contains("rotate-3"));
511 assert!(css_classes.contains("rotate-6"));
512 assert!(css_classes.contains("rotate-12"));
513 assert!(css_classes.contains("rotate-45"));
514 assert!(css_classes.contains("rotate-90"));
515 assert!(css_classes.contains("rotate-180"));
516 }
517
518 #[test]
519 fn test_translate_utilities() {
520 let classes = ClassBuilder::new()
521 .translate_x(Translate::Zero)
522 .translate_x(Translate::One)
523 .translate_x(Translate::Two)
524 .translate_x(Translate::Three)
525 .translate_x(Translate::Four)
526 .translate_x(Translate::Five)
527 .translate_x(Translate::Six)
528 .translate_x(Translate::Seven)
529 .translate_x(Translate::Eight)
530 .translate_x(Translate::Nine)
531 .translate_x(Translate::Ten)
532 .translate_y(Translate::Zero)
533 .translate_y(Translate::One)
534 .translate_y(Translate::Two)
535 .translate_y(Translate::Three)
536 .translate_y(Translate::Four)
537 .translate_y(Translate::Five)
538 .translate_y(Translate::Six)
539 .translate_y(Translate::Seven)
540 .translate_y(Translate::Eight)
541 .translate_y(Translate::Nine)
542 .translate_y(Translate::Ten)
543 .build();
544
545 let css_classes = classes.to_css_classes();
546 assert!(css_classes.contains("translate-x-0"));
547 assert!(css_classes.contains("translate-x-1"));
548 assert!(css_classes.contains("translate-x-2"));
549 assert!(css_classes.contains("translate-x-3"));
550 assert!(css_classes.contains("translate-x-4"));
551 assert!(css_classes.contains("translate-x-5"));
552 assert!(css_classes.contains("translate-x-6"));
553 assert!(css_classes.contains("translate-x-7"));
554 assert!(css_classes.contains("translate-x-8"));
555 assert!(css_classes.contains("translate-x-9"));
556 assert!(css_classes.contains("translate-x-10"));
557 assert!(css_classes.contains("translate-y-0"));
558 assert!(css_classes.contains("translate-y-1"));
559 assert!(css_classes.contains("translate-y-2"));
560 assert!(css_classes.contains("translate-y-3"));
561 assert!(css_classes.contains("translate-y-4"));
562 assert!(css_classes.contains("translate-y-5"));
563 assert!(css_classes.contains("translate-y-6"));
564 assert!(css_classes.contains("translate-y-7"));
565 assert!(css_classes.contains("translate-y-8"));
566 assert!(css_classes.contains("translate-y-9"));
567 assert!(css_classes.contains("translate-y-10"));
568 }
569
570 #[test]
571 fn test_skew_utilities() {
572 let classes = ClassBuilder::new()
573 .skew_x(Skew::Zero)
574 .skew_x(Skew::One)
575 .skew_x(Skew::Two)
576 .skew_x(Skew::Three)
577 .skew_x(Skew::Six)
578 .skew_x(Skew::Twelve)
579 .skew_y(Skew::Zero)
580 .skew_y(Skew::One)
581 .skew_y(Skew::Two)
582 .skew_y(Skew::Three)
583 .skew_y(Skew::Six)
584 .skew_y(Skew::Twelve)
585 .build();
586
587 let css_classes = classes.to_css_classes();
588 assert!(css_classes.contains("skew-x-0"));
589 assert!(css_classes.contains("skew-x-1"));
590 assert!(css_classes.contains("skew-x-2"));
591 assert!(css_classes.contains("skew-x-3"));
592 assert!(css_classes.contains("skew-x-6"));
593 assert!(css_classes.contains("skew-x-12"));
594 assert!(css_classes.contains("skew-y-0"));
595 assert!(css_classes.contains("skew-y-1"));
596 assert!(css_classes.contains("skew-y-2"));
597 assert!(css_classes.contains("skew-y-3"));
598 assert!(css_classes.contains("skew-y-6"));
599 assert!(css_classes.contains("skew-y-12"));
600 }
601
602 #[test]
603 fn test_transform_origin_utilities() {
604 let classes = ClassBuilder::new()
605 .transform_origin(TransformOrigin::Center)
606 .transform_origin(TransformOrigin::Top)
607 .transform_origin(TransformOrigin::TopRight)
608 .transform_origin(TransformOrigin::Right)
609 .transform_origin(TransformOrigin::BottomRight)
610 .transform_origin(TransformOrigin::Bottom)
611 .transform_origin(TransformOrigin::BottomLeft)
612 .transform_origin(TransformOrigin::Left)
613 .transform_origin(TransformOrigin::TopLeft)
614 .build();
615
616 let css_classes = classes.to_css_classes();
617 assert!(css_classes.contains("origin-center"));
618 assert!(css_classes.contains("origin-top"));
619 assert!(css_classes.contains("origin-top-right"));
620 assert!(css_classes.contains("origin-right"));
621 assert!(css_classes.contains("origin-bottom-right"));
622 assert!(css_classes.contains("origin-bottom"));
623 assert!(css_classes.contains("origin-bottom-left"));
624 assert!(css_classes.contains("origin-left"));
625 assert!(css_classes.contains("origin-top-left"));
626 }
627
628 #[test]
629 fn test_complex_transforms_combination() {
630 let classes = ClassBuilder::new()
631 .scale(Scale::HundredTen)
632 .scale_x(Scale::HundredFive)
633 .scale_y(Scale::HundredFive)
634 .rotate(Rotate::FortyFive)
635 .translate_x(Translate::Four)
636 .translate_y(Translate::Four)
637 .skew_x(Skew::Two)
638 .skew_y(Skew::Two)
639 .transform_origin(TransformOrigin::Center)
640 .build();
641
642 let css_classes = classes.to_css_classes();
643 assert!(css_classes.contains("scale-110"));
644 assert!(css_classes.contains("scale-x-105"));
645 assert!(css_classes.contains("scale-y-105"));
646 assert!(css_classes.contains("rotate-45"));
647 assert!(css_classes.contains("translate-x-4"));
648 assert!(css_classes.contains("translate-y-4"));
649 assert!(css_classes.contains("skew-x-2"));
650 assert!(css_classes.contains("skew-y-2"));
651 assert!(css_classes.contains("origin-center"));
652 }
653
654 #[test]
656 fn test_week11_transform_utilities() {
657 let classes = ClassBuilder::new()
659 .scale(Scale::Zero)
661 .scale(Scale::Fifty)
662 .scale(Scale::SeventyFive)
663 .scale(Scale::Ninety)
664 .scale(Scale::NinetyFive)
665 .scale(Scale::Hundred)
666 .scale(Scale::HundredFive)
667 .scale(Scale::HundredTen)
668 .scale(Scale::HundredTwentyFive)
669 .scale(Scale::HundredFifty)
670 .scale_x(Scale::Hundred)
671 .scale_y(Scale::Hundred)
672 .rotate(Rotate::Zero)
674 .rotate(Rotate::One)
675 .rotate(Rotate::Two)
676 .rotate(Rotate::Three)
677 .rotate(Rotate::Six)
678 .rotate(Rotate::Twelve)
679 .rotate(Rotate::FortyFive)
680 .rotate(Rotate::Ninety)
681 .rotate(Rotate::HundredEighty)
682 .translate_x(Translate::Zero)
684 .translate_x(Translate::Four)
685 .translate_y(Translate::Two)
686 .translate_y(Translate::Eight)
687 .build();
688
689 let css_classes = classes.to_css_classes();
690
691 assert!(css_classes.contains("scale-0"));
693 assert!(css_classes.contains("scale-50"));
694 assert!(css_classes.contains("scale-75"));
695 assert!(css_classes.contains("scale-90"));
696 assert!(css_classes.contains("scale-95"));
697 assert!(css_classes.contains("scale-100"));
698 assert!(css_classes.contains("scale-105"));
699 assert!(css_classes.contains("scale-110"));
700 assert!(css_classes.contains("scale-125"));
701 assert!(css_classes.contains("scale-150"));
702 assert!(css_classes.contains("scale-x-100"));
703 assert!(css_classes.contains("scale-y-100"));
704
705 assert!(css_classes.contains("rotate-0"));
707 assert!(css_classes.contains("rotate-1"));
708 assert!(css_classes.contains("rotate-2"));
709 assert!(css_classes.contains("rotate-3"));
710 assert!(css_classes.contains("rotate-6"));
711 assert!(css_classes.contains("rotate-12"));
712 assert!(css_classes.contains("rotate-45"));
713 assert!(css_classes.contains("rotate-90"));
714 assert!(css_classes.contains("rotate-180"));
715
716 assert!(css_classes.contains("translate-x-0"));
718 assert!(css_classes.contains("translate-x-4"));
719 assert!(css_classes.contains("translate-y-2"));
720 assert!(css_classes.contains("translate-y-8"));
721 }
722}