maglevcms 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/maglev/tailwind.css +123 -105
  3. data/app/assets/stylesheets/maglev/application.css +47 -3
  4. data/app/components/maglev/uikit/app_layout/sidebar_component.html.erb +1 -1
  5. data/app/components/maglev/uikit/app_layout/topbar/logo_component.html.erb +1 -1
  6. data/app/components/maglev/uikit/app_layout/topbar/page_info_component.html.erb +2 -2
  7. data/app/components/maglev/uikit/breadcrumbs/breadcrumbs_component.html.erb +2 -2
  8. data/app/components/maglev/uikit/breadcrumbs/link_component.html.erb +2 -2
  9. data/app/components/maglev/uikit/button_group_component/button_group_component.html.erb +1 -1
  10. data/app/components/maglev/uikit/collapsible/item_component.html.erb +1 -1
  11. data/app/components/maglev/uikit/dropdown_component/dropdown_controller.js +13 -2
  12. data/app/components/maglev/uikit/form/checkbox_component.html.erb +2 -2
  13. data/app/components/maglev/uikit/form/color_field_component.html.erb +3 -3
  14. data/app/components/maglev/uikit/form/combobox/list_component.html.erb +1 -1
  15. data/app/components/maglev/uikit/form/combobox/option_component.html.erb +1 -1
  16. data/app/components/maglev/uikit/form/combobox_component.html.erb +1 -1
  17. data/app/components/maglev/uikit/form/link/email_link_component.html.erb +2 -2
  18. data/app/components/maglev/uikit/form/link/page_link_component.html.erb +2 -2
  19. data/app/components/maglev/uikit/form/link/static_page_link_component.html.erb +2 -2
  20. data/app/components/maglev/uikit/form/link/url_link_component.html.erb +2 -2
  21. data/app/components/maglev/uikit/form/richtext/block_button_component.html.erb +1 -1
  22. data/app/components/maglev/uikit/form/richtext/button_component.html.erb +2 -2
  23. data/app/components/maglev/uikit/form/richtext/toolbar_component.html.erb +1 -1
  24. data/app/components/maglev/uikit/form/search_form_component.html.erb +1 -1
  25. data/app/components/maglev/uikit/form/search_form_component.rb +1 -1
  26. data/app/components/maglev/uikit/form/select_component.html.erb +1 -1
  27. data/app/components/maglev/uikit/image_library/card_component.html.erb +1 -1
  28. data/app/components/maglev/uikit/list/insert_button_component.html.erb +1 -1
  29. data/app/components/maglev/uikit/list/list_item_component.html.erb +7 -5
  30. data/app/components/maglev/uikit/list/list_item_component.rb +2 -0
  31. data/app/components/maglev/uikit/locale_switcher_component/locale_switcher_component.html.erb +1 -1
  32. data/app/components/maglev/uikit/menu_dropdown_component.rb +3 -3
  33. data/app/components/maglev/uikit/modal_component/modal_component.html.erb +3 -3
  34. data/app/components/maglev/uikit/modal_component.rb +1 -1
  35. data/app/components/maglev/uikit/page_layout_component/back_link_component.html.erb +1 -1
  36. data/app/components/maglev/uikit/page_layout_component/page_layout_component.html.erb +2 -2
  37. data/app/components/maglev/uikit/page_layout_component.rb +3 -3
  38. data/app/components/maglev/uikit/pagination_component/pagination_component.html.erb +4 -4
  39. data/app/components/maglev/uikit/section_toolbar/top_left_corner_component.html.erb +4 -4
  40. data/app/components/maglev/uikit/section_toolbar/top_right_corner_component.html.erb +3 -3
  41. data/app/helpers/maglev/application_helper.rb +6 -0
  42. data/app/views/layouts/maglev/editor/application.html.erb +1 -1
  43. data/app/views/maglev/editor/assets/index.html.erb +1 -1
  44. data/app/views/maglev/editor/pages/_preview.html.erb +3 -3
  45. data/app/views/maglev/editor/pages/_preview_empty_message.html.erb +1 -1
  46. data/app/views/maglev/editor/section_blocks/index/_tree.html.erb +3 -3
  47. data/app/views/maglev/editor/sections/_toolbar_list.html.erb +1 -1
  48. data/app/views/maglev/editor/sections/theme/_list.html.erb +4 -2
  49. data/lib/maglev/version.rb +1 -1
  50. metadata +11 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91a5ea2feecec6351e3e7042be72418ce8e95374e50108d6a798b2f179d47ee4
4
- data.tar.gz: c674bf2fb233c7aec70823875c804e7f7741df83f809a09cc670ac13eedb9d74
3
+ metadata.gz: 7b3c21664099214944c91eb07e3aa563b6043e9ab1e7af4d6a0443b0d83972a9
4
+ data.tar.gz: b2618b80cdec94c2b2574ce61845c783a0593748a1498c097107213d80c60677
5
5
  SHA512:
6
- metadata.gz: 2f3301ae182676801e8fc2baecbc6774f1c3e10e072fa509a2272185ff6b62aa64c7cdd68a92426679b6545c14a40f376e0be3f038df1cb18d78cd6e55747da1
7
- data.tar.gz: a1dce55e8a53f13e394b82f548a6726a06b2a3babe65e6e645d1ee5c00040022d10243f75c9eede599fe957e4b2bb0aafe5fd8a9becc32dfa8b35a3f4767a873
6
+ metadata.gz: 7352a60fca5460da127d428cfc52cc430d887cb794879238e8a34a545e67a4a39c2fd002dd9de79a71e48f6e4e434194ffc2309e3c4b0a3c7f64084c2226d324
7
+ data.tar.gz: 16a58a3770b2be147e894d5630837ee5c4cc6de0cfaa4d81b1cd601a887f2d3b81f2f67d01821ef453b252287a8abbd83d801df59a55059545f8650ca9dc61ee
@@ -301,6 +301,27 @@
301
301
  .inset-y-0 {
302
302
  inset-block: calc(var(--spacing) * 0);
303
303
  }
304
+ .-start-1 {
305
+ inset-inline-start: calc(var(--spacing) * -1);
306
+ }
307
+ .start-0 {
308
+ inset-inline-start: calc(var(--spacing) * 0);
309
+ }
310
+ .start-3 {
311
+ inset-inline-start: calc(var(--spacing) * 3);
312
+ }
313
+ .start-16 {
314
+ inset-inline-start: calc(var(--spacing) * 16);
315
+ }
316
+ .-end-2 {
317
+ inset-inline-end: calc(var(--spacing) * -2);
318
+ }
319
+ .end-0 {
320
+ inset-inline-end: calc(var(--spacing) * 0);
321
+ }
322
+ .end-3 {
323
+ inset-inline-end: calc(var(--spacing) * 3);
324
+ }
304
325
  .top-0 {
305
326
  top: calc(var(--spacing) * 0);
306
327
  }
@@ -319,15 +340,9 @@
319
340
  .top-16 {
320
341
  top: calc(var(--spacing) * 16);
321
342
  }
322
- .-right-2 {
323
- right: calc(var(--spacing) * -2);
324
- }
325
343
  .right-0 {
326
344
  right: calc(var(--spacing) * 0);
327
345
  }
328
- .right-3 {
329
- right: calc(var(--spacing) * 3);
330
- }
331
346
  .-bottom-0\.25 {
332
347
  bottom: calc(var(--spacing) * -0.25);
333
348
  }
@@ -337,18 +352,9 @@
337
352
  .bottom-0\.5 {
338
353
  bottom: calc(var(--spacing) * 0.5);
339
354
  }
340
- .-left-1 {
341
- left: calc(var(--spacing) * -1);
342
- }
343
355
  .left-0 {
344
356
  left: calc(var(--spacing) * 0);
345
357
  }
346
- .left-3 {
347
- left: calc(var(--spacing) * 3);
348
- }
349
- .left-16 {
350
- left: calc(var(--spacing) * 16);
351
- }
352
358
  .isolate {
353
359
  isolation: isolate;
354
360
  }
@@ -439,6 +445,27 @@
439
445
  .my-20 {
440
446
  margin-block: calc(var(--spacing) * 20);
441
447
  }
448
+ .ms-1 {
449
+ margin-inline-start: calc(var(--spacing) * 1);
450
+ }
451
+ .ms-2 {
452
+ margin-inline-start: calc(var(--spacing) * 2);
453
+ }
454
+ .ms-3 {
455
+ margin-inline-start: calc(var(--spacing) * 3);
456
+ }
457
+ .ms-5 {
458
+ margin-inline-start: calc(var(--spacing) * 5);
459
+ }
460
+ .ms-auto {
461
+ margin-inline-start: auto;
462
+ }
463
+ .me-2 {
464
+ margin-inline-end: calc(var(--spacing) * 2);
465
+ }
466
+ .me-3 {
467
+ margin-inline-end: calc(var(--spacing) * 3);
468
+ }
442
469
  .-mt-0\.5 {
443
470
  margin-top: calc(var(--spacing) * -0.5);
444
471
  }
@@ -475,12 +502,6 @@
475
502
  .-mr-1 {
476
503
  margin-right: calc(var(--spacing) * -1);
477
504
  }
478
- .mr-2 {
479
- margin-right: calc(var(--spacing) * 2);
480
- }
481
- .mr-3 {
482
- margin-right: calc(var(--spacing) * 3);
483
- }
484
505
  .-mb-5 {
485
506
  margin-bottom: calc(var(--spacing) * -5);
486
507
  }
@@ -514,18 +535,6 @@
514
535
  .ml-1 {
515
536
  margin-left: calc(var(--spacing) * 1);
516
537
  }
517
- .ml-2 {
518
- margin-left: calc(var(--spacing) * 2);
519
- }
520
- .ml-3 {
521
- margin-left: calc(var(--spacing) * 3);
522
- }
523
- .ml-5 {
524
- margin-left: calc(var(--spacing) * 5);
525
- }
526
- .ml-auto {
527
- margin-left: auto;
528
- }
529
538
  .box-content {
530
539
  box-sizing: content-box;
531
540
  }
@@ -911,6 +920,9 @@
911
920
  .gap-1 {
912
921
  gap: calc(var(--spacing) * 1);
913
922
  }
923
+ .gap-1\.5 {
924
+ gap: calc(var(--spacing) * 1.5);
925
+ }
914
926
  .gap-2 {
915
927
  gap: calc(var(--spacing) * 2);
916
928
  }
@@ -970,34 +982,6 @@
970
982
  .gap-x-8 {
971
983
  column-gap: calc(var(--spacing) * 8);
972
984
  }
973
- .space-x-0\.5 {
974
- :where(& > :not(:last-child)) {
975
- --tw-space-x-reverse: 0;
976
- margin-inline-start: calc(calc(var(--spacing) * 0.5) * var(--tw-space-x-reverse));
977
- margin-inline-end: calc(calc(var(--spacing) * 0.5) * calc(1 - var(--tw-space-x-reverse)));
978
- }
979
- }
980
- .space-x-1 {
981
- :where(& > :not(:last-child)) {
982
- --tw-space-x-reverse: 0;
983
- margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse));
984
- margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse)));
985
- }
986
- }
987
- .space-x-1\.5 {
988
- :where(& > :not(:last-child)) {
989
- --tw-space-x-reverse: 0;
990
- margin-inline-start: calc(calc(var(--spacing) * 1.5) * var(--tw-space-x-reverse));
991
- margin-inline-end: calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-x-reverse)));
992
- }
993
- }
994
- .space-x-2 {
995
- :where(& > :not(:last-child)) {
996
- --tw-space-x-reverse: 0;
997
- margin-inline-start: calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse));
998
- margin-inline-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse)));
999
- }
1000
- }
1001
985
  .space-x-4 {
1002
986
  :where(& > :not(:last-child)) {
1003
987
  --tw-space-x-reverse: 0;
@@ -1077,13 +1061,13 @@
1077
1061
  .rounded-xs {
1078
1062
  border-radius: var(--radius-xs);
1079
1063
  }
1080
- .rounded-l-2xl {
1081
- border-top-left-radius: var(--radius-2xl);
1082
- border-bottom-left-radius: var(--radius-2xl);
1064
+ .rounded-s-2xl {
1065
+ border-start-start-radius: var(--radius-2xl);
1066
+ border-end-start-radius: var(--radius-2xl);
1083
1067
  }
1084
- .rounded-r-2xl {
1085
- border-top-right-radius: var(--radius-2xl);
1086
- border-bottom-right-radius: var(--radius-2xl);
1068
+ .rounded-e-2xl {
1069
+ border-start-end-radius: var(--radius-2xl);
1070
+ border-end-end-radius: var(--radius-2xl);
1087
1071
  }
1088
1072
  .rounded-b {
1089
1073
  border-bottom-right-radius: 0.25rem;
@@ -1105,6 +1089,10 @@
1105
1089
  border-style: var(--tw-border-style);
1106
1090
  border-width: 4px;
1107
1091
  }
1092
+ .border-e {
1093
+ border-inline-end-style: var(--tw-border-style);
1094
+ border-inline-end-width: 1px;
1095
+ }
1108
1096
  .border-t {
1109
1097
  border-top-style: var(--tw-border-style);
1110
1098
  border-top-width: 1px;
@@ -1117,10 +1105,6 @@
1117
1105
  border-top-style: var(--tw-border-style);
1118
1106
  border-top-width: 4px;
1119
1107
  }
1120
- .border-r {
1121
- border-right-style: var(--tw-border-style);
1122
- border-right-width: 1px;
1123
- }
1124
1108
  .border-b {
1125
1109
  border-bottom-style: var(--tw-border-style);
1126
1110
  border-bottom-width: 1px;
@@ -1409,6 +1393,24 @@
1409
1393
  .py-24 {
1410
1394
  padding-block: calc(var(--spacing) * 24);
1411
1395
  }
1396
+ .ps-2 {
1397
+ padding-inline-start: calc(var(--spacing) * 2);
1398
+ }
1399
+ .ps-3 {
1400
+ padding-inline-start: calc(var(--spacing) * 3);
1401
+ }
1402
+ .ps-11 {
1403
+ padding-inline-start: calc(var(--spacing) * 11);
1404
+ }
1405
+ .pe-4 {
1406
+ padding-inline-end: calc(var(--spacing) * 4);
1407
+ }
1408
+ .pe-8 {
1409
+ padding-inline-end: calc(var(--spacing) * 8);
1410
+ }
1411
+ .pe-9 {
1412
+ padding-inline-end: calc(var(--spacing) * 9);
1413
+ }
1412
1414
  .pt-2 {
1413
1415
  padding-top: calc(var(--spacing) * 2);
1414
1416
  }
@@ -1424,15 +1426,6 @@
1424
1426
  .pt-32 {
1425
1427
  padding-top: calc(var(--spacing) * 32);
1426
1428
  }
1427
- .pr-4 {
1428
- padding-right: calc(var(--spacing) * 4);
1429
- }
1430
- .pr-8 {
1431
- padding-right: calc(var(--spacing) * 8);
1432
- }
1433
- .pr-9 {
1434
- padding-right: calc(var(--spacing) * 9);
1435
- }
1436
1429
  .pb-0 {
1437
1430
  padding-bottom: calc(var(--spacing) * 0);
1438
1431
  }
@@ -1454,21 +1447,15 @@
1454
1447
  .pb-16 {
1455
1448
  padding-bottom: calc(var(--spacing) * 16);
1456
1449
  }
1457
- .pl-2 {
1458
- padding-left: calc(var(--spacing) * 2);
1459
- }
1460
- .pl-3 {
1461
- padding-left: calc(var(--spacing) * 3);
1462
- }
1463
- .pl-11 {
1464
- padding-left: calc(var(--spacing) * 11);
1465
- }
1466
1450
  .text-center {
1467
1451
  text-align: center;
1468
1452
  }
1469
1453
  .text-left {
1470
1454
  text-align: left;
1471
1455
  }
1456
+ .text-start {
1457
+ text-align: start;
1458
+ }
1472
1459
  .font-nunito {
1473
1460
  font-family: var(--font-nunito);
1474
1461
  }
@@ -1867,14 +1854,14 @@
1867
1854
  width: calc(1024px * var(--page-preview-scale-ratio));
1868
1855
  }
1869
1856
  }
1870
- .group-data-\[expanded-page-layout\]\/page-layout\:left-104 {
1857
+ .group-data-\[expanded-page-layout\]\/page-layout\:start-104 {
1871
1858
  &:is(:where(.group\/page-layout)[data-expanded-page-layout] *) {
1872
- left: calc(var(--spacing) * 104);
1859
+ inset-inline-start: calc(var(--spacing) * 104);
1873
1860
  }
1874
1861
  }
1875
- .group-data-\[expanded-page-layout\]\/page-layout\:pl-88 {
1862
+ .group-data-\[expanded-page-layout\]\/page-layout\:ps-88 {
1876
1863
  &:is(:where(.group\/page-layout)[data-expanded-page-layout] *) {
1877
- padding-left: calc(var(--spacing) * 88);
1864
+ padding-inline-start: calc(var(--spacing) * 88);
1878
1865
  }
1879
1866
  }
1880
1867
  .group-data-\[focus\]\:text-white {
@@ -2046,16 +2033,16 @@
2046
2033
  display: flex;
2047
2034
  }
2048
2035
  }
2049
- .first\:rounded-l-sm {
2036
+ .first\:rounded-s-sm {
2050
2037
  &:first-child {
2051
- border-top-left-radius: var(--radius-sm);
2052
- border-bottom-left-radius: var(--radius-sm);
2038
+ border-start-start-radius: var(--radius-sm);
2039
+ border-end-start-radius: var(--radius-sm);
2053
2040
  }
2054
2041
  }
2055
- .last\:rounded-r-sm {
2042
+ .last\:rounded-e-sm {
2056
2043
  &:last-child {
2057
- border-top-right-radius: var(--radius-sm);
2058
- border-bottom-right-radius: var(--radius-sm);
2044
+ border-start-end-radius: var(--radius-sm);
2045
+ border-end-end-radius: var(--radius-sm);
2059
2046
  }
2060
2047
  }
2061
2048
  .hover\:z-10 {
@@ -2783,6 +2770,37 @@
2783
2770
  padding-inline: calc(var(--spacing) * 16);
2784
2771
  }
2785
2772
  }
2773
+ .rtl\:origin-top-right {
2774
+ &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
2775
+ transform-origin: 100% 0;
2776
+ }
2777
+ }
2778
+ .rtl\:-translate-x-\[50\%\] {
2779
+ &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
2780
+ --tw-translate-x: calc(50% * -1);
2781
+ translate: var(--tw-translate-x) var(--tw-translate-y);
2782
+ }
2783
+ }
2784
+ .rtl\:translate-x-\[50\%\] {
2785
+ &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
2786
+ --tw-translate-x: 50%;
2787
+ translate: var(--tw-translate-x) var(--tw-translate-y);
2788
+ }
2789
+ }
2790
+ .rtl\:-scale-x-100 {
2791
+ &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
2792
+ --tw-scale-x: calc(100% * -1);
2793
+ scale: var(--tw-scale-x) var(--tw-scale-y);
2794
+ }
2795
+ }
2796
+ .rtl\:group-has-checked\:-translate-x-4 {
2797
+ &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
2798
+ &:is(:where(.group):has(*:checked) *) {
2799
+ --tw-translate-x: calc(var(--spacing) * -4);
2800
+ translate: var(--tw-translate-x) var(--tw-translate-y);
2801
+ }
2802
+ }
2803
+ }
2786
2804
  .dark\:text-editor-primary {
2787
2805
  @media (prefers-color-scheme: dark) {
2788
2806
  color: var(--color-editor-primary);
@@ -2881,16 +2899,16 @@
2881
2899
  }
2882
2900
  }
2883
2901
  }
2884
- .\[\&\>\*\:first-child\]\:rounded-l-sm {
2902
+ .\[\&\>\*\:first-child\]\:rounded-s-sm {
2885
2903
  &>*:first-child {
2886
- border-top-left-radius: var(--radius-sm);
2887
- border-bottom-left-radius: var(--radius-sm);
2904
+ border-start-start-radius: var(--radius-sm);
2905
+ border-end-start-radius: var(--radius-sm);
2888
2906
  }
2889
2907
  }
2890
- .\[\&\>\*\:last-child\]\:rounded-r-sm {
2908
+ .\[\&\>\*\:last-child\]\:rounded-e-sm {
2891
2909
  &>*:last-child {
2892
- border-top-right-radius: var(--radius-sm);
2893
- border-bottom-right-radius: var(--radius-sm);
2910
+ border-start-end-radius: var(--radius-sm);
2911
+ border-end-end-radius: var(--radius-sm);
2894
2912
  }
2895
2913
  }
2896
2914
  }
@@ -32,6 +32,27 @@
32
32
  }
33
33
  }
34
34
 
35
+ /* RTL: the page-layout panel lives on the right, so it slides off to / in from the right edge */
36
+ @keyframes slide-out-rtl {
37
+ from {
38
+ transform: translateX(0%);
39
+ }
40
+
41
+ to {
42
+ transform: translateX(100%);
43
+ }
44
+ }
45
+
46
+ @keyframes slide-in-rtl {
47
+ from {
48
+ transform: translateX(100%);
49
+ }
50
+
51
+ to {
52
+ transform: translateX(0%);
53
+ }
54
+ }
55
+
35
56
  html[data-turbo-visit-direction="forward"]::view-transition-old(page-layout),
36
57
  html[data-turbo-visit-direction="back"]::view-transition-old(page-layout),
37
58
  html[data-turbo-visit-direction="forward"]::view-transition-old(expanded-page-layout),
@@ -46,6 +67,20 @@ html[data-turbo-visit-direction="back"]::view-transition-new(expanded-page-layou
46
67
  animation: 0.2s cubic-bezier(0.55, 0, 0.1, 1) both slide-in;
47
68
  }
48
69
 
70
+ html[dir="rtl"][data-turbo-visit-direction="forward"]::view-transition-old(page-layout),
71
+ html[dir="rtl"][data-turbo-visit-direction="back"]::view-transition-old(page-layout),
72
+ html[dir="rtl"][data-turbo-visit-direction="forward"]::view-transition-old(expanded-page-layout),
73
+ html[dir="rtl"][data-turbo-visit-direction="back"]::view-transition-old(expanded-page-layout) {
74
+ animation-name: slide-out-rtl;
75
+ }
76
+
77
+ html[dir="rtl"][data-turbo-visit-direction="forward"]::view-transition-new(page-layout),
78
+ html[dir="rtl"][data-turbo-visit-direction="back"]::view-transition-new(page-layout),
79
+ html[dir="rtl"][data-turbo-visit-direction="forward"]::view-transition-new(expanded-page-layout),
80
+ html[dir="rtl"][data-turbo-visit-direction="back"]::view-transition-new(expanded-page-layout) {
81
+ animation-name: slide-in-rtl;
82
+ }
83
+
49
84
  html[data-page-layout-vt-pair="already-present"]::view-transition-old(page-layout),
50
85
  html[data-page-layout-vt-pair="already-present"]::view-transition-old(expanded-page-layout),
51
86
  html[data-page-layout-vt-pair="already-present"]::view-transition-new(page-layout),
@@ -61,8 +96,12 @@ html[data-page-layout-vt-pair="already-present"]::view-transition-new(expanded-p
61
96
  z-index: 30;
62
97
  }
63
98
 
64
- ::view-transition-group(page-preview) {
65
- transform-origin: right center;
99
+ ::view-transition-group(page-preview) {
100
+ transform-origin: right center;
101
+ }
102
+
103
+ html[dir="rtl"]::view-transition-group(page-preview) {
104
+ transform-origin: left center;
66
105
  }
67
106
 
68
107
  #page-layout[data-not-expanded] {
@@ -95,7 +134,12 @@ html[data-page-layout-vt-pair="already-present"]::view-transition-new(expanded-p
95
134
 
96
135
  /* couldn't get this done in Tailwind custom classes */
97
136
  #page-preview {
98
- transform: translateX(var(--page-preview-transform-x, 0px)) scale(var(--page-preview-scale-ratio, 1));
137
+ transform: translateX(var(--page-preview-transform-x, 0px)) scale(var(--page-preview-scale-ratio, 1));
99
138
  height: calc(100% * 1 / 1 / var(--page-preview-scale-ratio, 1));
100
139
  width: var(--page-preview-width, 100%);
140
+ }
141
+
142
+ /* RTL: the expanded panel is on the right, so the canvas must shift the opposite way to clear it */
143
+ html[dir="rtl"] #page-preview {
144
+ transform: translateX(calc(-1 * var(--page-preview-transform-x, 0px))) scale(var(--page-preview-scale-ratio, 1));
101
145
  }
@@ -1,6 +1,6 @@
1
1
  <aside
2
2
  id="app-layout-sidebar"
3
- class="w-16 flex-shrink-0 flex content-center h-full border-r border-gray-200 relative z-20 bg-white"
3
+ class="w-16 flex-shrink-0 flex content-center h-full border-e border-gray-200 relative z-20 bg-white"
4
4
  >
5
5
  <nav class="flex h-full w-16 flex-col justify-between py-2">
6
6
  <ol class="flex flex-col gap-1 px-2">
@@ -1,3 +1,3 @@
1
- <%= link_to root_path, class: "w-16 h-full flex justify-center items-center border-r border-gray-200 shrink-0", data: { controller: 'prevent-same-path' } do %>
1
+ <%= link_to root_path, class: "w-16 h-full flex justify-center items-center border-e border-gray-200 shrink-0", data: { controller: 'prevent-same-path' } do %>
2
2
  <%= image_tag logo_url, class: "w-2/4", id: 'editor-logo-image', data: { turbo_permanent: true } %>
3
3
  <% end %>
@@ -5,7 +5,7 @@
5
5
  <div class="flex flex-col leading-none overflow-hidden">
6
6
  <div class="flex items-center overflow-hidden">
7
7
  <%= helpers.maglev_page_icon(page, size: '1.1rem', wrapper_class_names: 'text-gray-900 shrink-0') %>
8
- <div class="text-base font-semibold truncate ml-1 mr-3 min-w-0">
8
+ <div class="text-base font-semibold truncate ms-1 me-3 min-w-0">
9
9
  <%= page.title.presence || page.default_title %>
10
10
  </div>
11
11
 
@@ -16,7 +16,7 @@
16
16
  %>
17
17
  </div>
18
18
 
19
- <div class="text-xs text-gray-500 flex items-center space-x-1 overflow-hidden">
19
+ <div class="text-xs text-gray-500 flex items-center gap-1 overflow-hidden">
20
20
  <p class="truncate text-gray-700 min-w-0">
21
21
  <span class="text-gray-900 font-semibold">/</span><%= page_path %>
22
22
  </p>
@@ -1,9 +1,9 @@
1
1
  <nav class="flex justify-between">
2
- <ol class="inline-flex items-center space-x-0.5 text-xs text-gray-500">
2
+ <ol class="inline-flex items-center gap-0.5 text-xs text-gray-500">
3
3
  <% breadcrumbs.each_with_index do |breadcrumb, index| %>
4
4
  <%= breadcrumb %>
5
5
  <% if index < breadcrumbs.size - 1 %>
6
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1rem', class_names: 'text-gray-400') %>
6
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1rem', class_names: 'text-gray-400 rtl:-scale-x-100') %>
7
7
  <% end %>
8
8
  <% end %>
9
9
  </ol>
@@ -1,12 +1,12 @@
1
1
  <li class="flex items-center h-full">
2
2
  <% if url? %>
3
- <%= link_to url, class: 'inline-flex items-center text-xs space-x-1.5 rounded-sm hover:text-gray-900', data: { turbo_frame: '_top' } do %>
3
+ <%= link_to url, class: 'inline-flex items-center text-xs gap-1.5 rounded-sm hover:text-gray-900', data: { turbo_frame: '_top' } do %>
4
4
  <% if icon? %>
5
5
  <%= render Maglev::Uikit::IconComponent.new(name: icon, size: '0.85rem') %>
6
6
  <% end %>
7
7
  <span><%= label %></span>
8
8
  <% end %>
9
9
  <% else %>
10
- <span class="inline-flex items-center text-xs space-x-1.5 rounded-sm"><%= label %></span>
10
+ <span class="inline-flex items-center text-xs gap-1.5 rounded-sm"><%= label %></span>
11
11
  <% end %>
12
12
  </li>
@@ -1,4 +1,4 @@
1
- <div class="[&>*:first-child]:rounded-l-sm [&>*:last-child]:rounded-r-sm inline-flex items-center text-white divide-x divide-white/15">
1
+ <div class="[&>*:first-child]:rounded-s-sm [&>*:last-child]:rounded-e-sm inline-flex items-center text-white divide-x divide-white/15">
2
2
  <% buttons.each do |button| %>
3
3
  <%= button %>
4
4
  <% end %>
@@ -2,7 +2,7 @@
2
2
  <div class="flex items-center cursor-pointer select-none px-3 py-3 bg-editor-primary text-white rounded-xs" data-action="click->uikit-collapsible#toggle">
3
3
  <div class="flex items-center"><%= title %></div>
4
4
 
5
- <div class="ml-auto">
5
+ <div class="ms-auto">
6
6
  <%= render Maglev::Uikit::IconComponent.new(name: :arrow_down, size: '1.15rem', class_names: 'transition-transform duration-200 rotate-180 group-[.is-collapsed]:rotate-0') %>
7
7
  </div>
8
8
  </div>
@@ -9,10 +9,11 @@ export default class extends Controller {
9
9
  connect() {
10
10
  const button = this.buttonTarget
11
11
  const content = this.contentTarget
12
+ const placement = this.directionAwarePlacement(this.placementValue || 'bottom-start')
12
13
 
13
- this.cleanup = autoUpdate(button, content, () => computePosition(button, content, {
14
+ this.cleanup = autoUpdate(button, content, () => computePosition(button, content, {
14
15
  strategy: 'fixed',
15
- placement: this.placementValue || 'bottom-start',
16
+ placement,
16
17
  middleware: [
17
18
  flip(),
18
19
  shift(),
@@ -71,4 +72,14 @@ export default class extends Controller {
71
72
  hide() {
72
73
  this.leave()
73
74
  }
75
+
76
+ // Floating UI already flips the -start/-end alignment for RTL, but the physical
77
+ // left/right main side is direction-agnostic. Mirror it so submenus/side popovers
78
+ // open toward the reading direction (e.g. right-start -> left-start in RTL).
79
+ directionAwarePlacement(placement) {
80
+ if (getComputedStyle(this.element).direction !== 'rtl') return placement
81
+ if (placement.startsWith('left')) return placement.replace('left', 'right')
82
+ if (placement.startsWith('right')) return placement.replace('right', 'left')
83
+ return placement
84
+ }
74
85
  }
@@ -3,8 +3,8 @@
3
3
  <div class="font-semibold text-gray-800">
4
4
  <%= label %>
5
5
  </div>
6
- <div class="ml-auto group relative inline-flex w-10 shrink-0 rounded-full bg-gray-200 p-0.5 inset-ring inset-ring-gray-900/5 outline-offset-2 outline-editor-primary transition-colors duration-200 ease-in-out has-checked:bg-editor-primary has-focus-visible:outline-2">
7
- <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-4"></span>
6
+ <div class="ms-auto group relative inline-flex w-10 shrink-0 rounded-full bg-gray-200 p-0.5 inset-ring inset-ring-gray-900/5 outline-offset-2 outline-editor-primary transition-colors duration-200 ease-in-out has-checked:bg-editor-primary has-focus-visible:outline-2">
7
+ <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-4 rtl:group-has-checked:-translate-x-4"></span>
8
8
  <%= hidden_field_tag name, '0', { id: "#{dom_id}_hidden" } %>
9
9
  <%= check_box_tag name, '1', checked?, class: 'absolute inset-0 appearance-none focus:outline-hidden cursor-pointer', aria: { label: label }, data: { action: 'change->uikit-form-checkbox#change' } %>
10
10
  </div>
@@ -16,7 +16,7 @@
16
16
 
17
17
  <div class="inline-block relative">
18
18
  <%= tag.div(
19
- class: 'absolute left-3 top-2 w-6 h-6 rounded-sm border border-gray-200 group-[.is-empty]/color:bg-checkerboard group-[.is-empty]/color:bg-white!',
19
+ class: 'absolute start-3 top-2 w-6 h-6 rounded-sm border border-gray-200 group-[.is-empty]/color:bg-checkerboard group-[.is-empty]/color:bg-white!',
20
20
  style: "background-color: #{value}",
21
21
  data: {
22
22
  "uikit-form-color-field-target": "preview",
@@ -31,7 +31,7 @@
31
31
  minlength: 4,
32
32
  maxlength: 8,
33
33
  size: 9,
34
- class: 'block py-2 pl-11 pr-8 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50 placeholder-gray-500',
34
+ class: 'block py-2 ps-11 pe-8 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50 placeholder-gray-500',
35
35
  data: {
36
36
  'uikit-form-color-field-target': 'input',
37
37
  action: ['input->uikit-form-color-field#change', **input_action].join(' '),
@@ -41,7 +41,7 @@
41
41
  ) %>
42
42
 
43
43
  <% if presets? %>
44
- <div class="absolute top-1.5 right-3">
44
+ <div class="absolute top-1.5 end-3">
45
45
  <%= render Maglev::Uikit::DropdownComponent.new(placement: 'bottom-end') do |dropdown| %>
46
46
  <% dropdown.with_trigger do %>
47
47
  <%= render Maglev::Uikit::IconButtonComponent.new(
@@ -1,6 +1,6 @@
1
1
  <% options.each_with_index do |option, index| %>
2
2
  <li
3
- class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 group data-[focus]:bg-editor-primary data-[focus]:text-white"
3
+ class="relative cursor-default select-none py-2 ps-3 pe-9 text-gray-900 group data-[focus]:bg-editor-primary data-[focus]:text-white"
4
4
  role="option"
5
5
  tabindex="-1"
6
6
  data-id="<%= option.id %>"
@@ -9,7 +9,7 @@
9
9
  </span>
10
10
  <% end %>
11
11
 
12
- <span class="absolute inset-y-0 right-0 flex items-center pr-4 text-editor-primary hidden group-data-[selected]:flex group-data-[focus]:text-white">
12
+ <span class="absolute inset-y-0 end-0 flex items-center pe-4 text-editor-primary hidden group-data-[selected]:flex group-data-[focus]:text-white">
13
13
  <svg class="size-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
14
14
  <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" />
15
15
  </svg>
@@ -48,7 +48,7 @@
48
48
  }
49
49
  ) %>
50
50
 
51
- <div class="absolute top-0.5 bottom-0.5 right-3 bg-gray-100 flex items-center gap-2">
51
+ <div class="absolute top-0.5 bottom-0.5 end-3 bg-gray-100 flex items-center gap-2">
52
52
  <svg data-uikit-form-combobox-target="spinner" aria-hidden="true" class="hidden w-4 h-4 text-gray-200 animate-spin dark:text-editor-primary fill-editor-primary" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
53
53
  <path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
54
54
  <path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
@@ -3,10 +3,10 @@
3
3
  class: 'flex-1 flex items-center overflow-hidden items-center w-full h-10 px-3 rounded bg-gray-100 text-gray-800 cursor-pointer focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50',
4
4
  data: { turbo_frame: 'modal' } do %>
5
5
  <%= render Maglev::Uikit::IconComponent.new(name: "mail") %>
6
- <span class="ml-3 shrink"><%= link[:email] %></span>
6
+ <span class="ms-3 shrink"><%= link[:email] %></span>
7
7
  <% end %>
8
8
 
9
- <div class="absolute right-3 top-0 bottom-0 flex items-center pl-3">
9
+ <div class="absolute end-3 top-0 bottom-0 flex items-center ps-3">
10
10
  <%= render(Maglev::Uikit::IconButtonComponent.new(icon_name: 'eraser', data: { action: 'click->uikit-form-link#clear:prevent' })) %>
11
11
  </div>
12
12
 
@@ -3,10 +3,10 @@
3
3
  class: 'flex-1 flex items-center overflow-hidden items-center w-full h-10 px-3 rounded bg-gray-100 text-gray-800 cursor-pointer focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50',
4
4
  data: { turbo_frame: 'modal' } do %>
5
5
  <%= render Maglev::Uikit::IconComponent.new(name: "file") %>
6
- <span class="ml-3 shrink"><%= link[:link_label] %></span>
6
+ <span class="ms-3 shrink"><%= link[:link_label] %></span>
7
7
  <% end %>
8
8
 
9
- <div class="absolute right-3 top-0 bottom-0 flex items-center pl-3">
9
+ <div class="absolute end-3 top-0 bottom-0 flex items-center ps-3">
10
10
  <%= render(Maglev::Uikit::IconButtonComponent.new(icon_name: 'eraser', data: { action: 'click->uikit-form-link#clear:prevent' })) %>
11
11
  </div>
12
12
 
@@ -3,10 +3,10 @@
3
3
  class: 'flex-1 flex items-center overflow-hidden items-center w-full h-10 px-3 rounded bg-gray-100 text-gray-800 cursor-pointer focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50',
4
4
  data: { turbo_frame: 'modal' } do %>
5
5
  <%= render Maglev::Uikit::IconComponent.new(name: "file") %>
6
- <span class="ml-3 shrink"><%= link[:link_label] %></span>
6
+ <span class="ms-3 shrink"><%= link[:link_label] %></span>
7
7
  <% end %>
8
8
 
9
- <div class="absolute right-3 top-0 bottom-0 flex items-center pl-3">
9
+ <div class="absolute end-3 top-0 bottom-0 flex items-center ps-3">
10
10
  <%= render(Maglev::Uikit::IconButtonComponent.new(icon_name: 'eraser', data: { action: 'click->uikit-form-link#clear:prevent' })) %>
11
11
  </div>
12
12
 
@@ -3,10 +3,10 @@
3
3
  class: 'flex-1 flex items-center overflow-hidden items-center w-full h-10 px-3 rounded bg-gray-100 text-gray-800 cursor-pointer focus:outline-none focus:ring focus:ring-inset focus:ring-2 focus:ring-editor-primary/50',
4
4
  data: { turbo_frame: 'modal' } do %>
5
5
  <%= render Maglev::Uikit::IconComponent.new(name: "external_link") %>
6
- <span class="ml-3 shrink"><%= link[:href] %></span>
6
+ <span class="ms-3 shrink"><%= link[:href] %></span>
7
7
  <% end %>
8
8
 
9
- <div class="absolute right-3 top-0 bottom-0 flex items-center pl-3">
9
+ <div class="absolute end-3 top-0 bottom-0 flex items-center ps-3">
10
10
  <%= render(Maglev::Uikit::IconButtonComponent.new(icon_name: 'eraser', data: { action: 'click->uikit-form-link#clear:prevent' })) %>
11
11
  </div>
12
12
 
@@ -20,7 +20,7 @@
20
20
  <% end %>
21
21
  <% end %>
22
22
 
23
- <div class="flex flex-row space-x-2 py-1 px-1">
23
+ <div class="flex flex-row gap-2 py-1 px-1">
24
24
  <% choices.each do |choice| %>
25
25
  <%= tag.button(
26
26
  class: 'hover:bg-gray-100 px-2 py-1 cursor-pointer rounded-sm',
@@ -1,8 +1,8 @@
1
1
  <%= tag.button(
2
2
  class: class_names(
3
3
  'cursor-pointer px-2 py-2 bg-gray-100 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-editor-primary/50 focus:ring-inset focus:ring bg-gray-100',
4
- 'first:rounded-l-sm',
5
- 'last:rounded-r-sm',
4
+ 'first:rounded-s-sm',
5
+ 'last:rounded-e-sm',
6
6
  '[&.active]:bg-gray-600 [&.active]:hover:bg-gray-600 [&.active]:text-white'
7
7
  ),
8
8
  type: 'button',
@@ -1,4 +1,4 @@
1
- <div class="flex sticky top-0 z-10 pb-2 bg-white space-x-1 overflow-x-auto">
1
+ <div class="flex sticky top-0 z-10 pb-2 bg-white gap-1 overflow-x-auto">
2
2
  <%= render Maglev::Uikit::Form::Richtext::ButtonGroupComponent.new do |button_group| %>
3
3
  <%= render Maglev::Uikit::Form::Richtext::BlockButtonComponent.new %>
4
4
  <% end unless line_break? %>
@@ -5,7 +5,7 @@
5
5
  <%= tag.attributes(data: data) %>
6
6
  >
7
7
  <%= content if content? %>
8
- <button type="submit" class="mr-2">
8
+ <button type="submit" class="me-2">
9
9
  <%= render Maglev::Uikit::IconComponent.new(name: 'search', size: '1.25rem', class_names: 'text-gray-500') %>
10
10
  </button>
11
11
  <%= tag.input(
@@ -26,7 +26,7 @@ module Maglev
26
26
 
27
27
  def clear_button_class_names(...)
28
28
  class_variants(
29
- base: 'ml-1 text-gray-500 cursor-pointer',
29
+ base: 'ms-1 text-gray-500 cursor-pointer',
30
30
  variants: {
31
31
  invisible: 'invisible'
32
32
  }
@@ -14,6 +14,6 @@
14
14
  **input_tag_options,
15
15
  **html_options
16
16
  %>
17
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_down', size: '1.25rem', class_names: 'pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-gray-500 sm:size-4') %>
17
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_down', size: '1.25rem', class_names: 'pointer-events-none col-start-1 row-start-1 me-2 size-5 self-center justify-self-end text-gray-500 sm:size-4') %>
18
18
  </div>
19
19
  </div>
@@ -24,7 +24,7 @@
24
24
  >
25
25
  <%= button_to delete_path,
26
26
  method: :delete,
27
- form_class: 'ml-auto flex items-center',
27
+ form_class: 'ms-auto flex items-center',
28
28
  class: 'px-1 py-1 bg-white rounded-full flex items-center justify-center text-gray-900 cursor-pointer',
29
29
  data: { turbo_confirm: t('maglev.editor.image_library.confirm_destroy'), turbo_frame: 'modal-dialog' } do
30
30
  %>
@@ -1,5 +1,5 @@
1
1
  <div <%= tag.attributes(class: wrapper_classes) %>>
2
- <div class="absolute top-0 left-0 w-full justify-center flex opacity-0 group-hover/button:opacity-100 transition-opacity duration-200">
2
+ <div class="absolute top-0 start-0 w-full justify-center flex opacity-0 group-hover/button:opacity-100 transition-opacity duration-200">
3
3
  <%= link_to link_url, data: link_data, class: "h-7 w-7 flex items-center justify-center rounded-full focus:outline-none transition-colors duration-200 border-4 border-white bg-gray-500 text-gray-200 hover:bg-gray-900 hover:text-gray-100" do %>
4
4
  <%= render Maglev::Uikit::IconComponent.new(name: "add", size: "1.15rem") %>
5
5
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <%= tag.div(data: { sortable_target: sortable_target, item_id: id, item_index: index }) do %>
2
2
  <%= content_tag(wrapper_tag_name.to_sym, class: wrapper_classes) do %>
3
- <%= content if content? %>
3
+ <%= leading if leading? %>
4
4
 
5
5
  <%= tag.div(class: 'flex items-center cursor-move', data: { sortable_target: sortable_handle }) do %>
6
6
  <%= render Maglev::Uikit::IconComponent.new(name: "draggable") %>
@@ -9,7 +9,7 @@
9
9
  <% item_body = capture do %>
10
10
  <% if icon? %>
11
11
  <div class="grid grid-cols-[auto_1fr_auto] flex flex-1 items-center">
12
- <div class="mr-2">
12
+ <div class="me-2">
13
13
  <%= icon %>
14
14
  </div>
15
15
  <div class="text-gray-800 truncate"><%= title %></div>
@@ -56,9 +56,11 @@
56
56
  <% end %>
57
57
 
58
58
  <% if action? %>
59
- <div class="relative ml-auto flex items-center shrink-0 min-h-full gap-2">
59
+ <div class="relative ms-auto flex items-center shrink-0 min-h-full gap-2">
60
60
  <%= action %>
61
61
  </div>
62
62
  <% end %>
63
- <% end %>
64
- <% end %>
63
+ <% end %>
64
+
65
+ <%= content if content? %>
66
+ <% end %>
@@ -12,6 +12,8 @@ module Maglev
12
12
  renders_one :sub_title
13
13
  renders_one :title
14
14
  renders_one :action
15
+ # Inside the wrapper (e.g. radio for label wrappers). Default content stays below.
16
+ renders_one :leading
15
17
 
16
18
  attr_reader :link, :index, :options, :variant, :wrapper_tag_name
17
19
 
@@ -1,6 +1,6 @@
1
1
  <%= render(Maglev::Uikit::MenuDropdownComponent.new) do |dropdown| %>
2
2
  <% dropdown.with_trigger do %>
3
- <%= tag.button class: helpers.maglev_button_classes(color: :secondary, class: 'space-x-2'), data: { action: 'click->uikit-dropdown#toggle', 'uikit-dropdown-target': 'button' } do %>
3
+ <%= tag.button class: helpers.maglev_button_classes(color: :secondary, class: 'gap-2'), data: { action: 'click->uikit-dropdown#toggle', 'uikit-dropdown-target': 'button' } do %>
4
4
  <%= render Maglev::Uikit::IconComponent.new(name: 'global') %>
5
5
  <span class="whitespace-nowrap">
6
6
  <%= current_locale_label %>
@@ -52,7 +52,7 @@ module Maglev
52
52
  class_variants(
53
53
  base: %(
54
54
  col-span-3 grid grid-cols-subgrid
55
- flex flex-1 items-center px-2 py-3 w-full mx-1 rounded-sm text-left
55
+ flex flex-1 items-center px-2 py-3 w-full mx-1 rounded-sm text-start
56
56
  transition-colors duration-200 focus:outline-none cursor-pointer
57
57
  ),
58
58
  variants: {
@@ -82,11 +82,11 @@ module Maglev
82
82
 
83
83
  def self.inner_content
84
84
  <<-ERB
85
- <%= render Maglev::Uikit::IconComponent.new(name: icon.to_s, size: '1.15rem', class_names: 'mr-2 shrink-0') if icon? %>
85
+ <%= render Maglev::Uikit::IconComponent.new(name: icon.to_s, size: '1.15rem', class_names: 'me-2 shrink-0') if icon? %>
86
86
  <span class="<%= 'col-start-2' unless icon? %> whitespace-nowrap whitespace-nowrap truncate overflow-hidden">
87
87
  <%= label %>
88
88
  </span>
89
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1.15rem', class_names: 'ml-2 shrink-0') if right_arrow? %>
89
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1.15rem', class_names: 'ms-2 shrink-0 rtl:-scale-x-100') if right_arrow? %>
90
90
  <span class="col-start-2 whitespace-nowrap whitespace-nowrap truncate overflow-hidden text-xs text-gray-500">
91
91
  <%= sub_label %>
92
92
  </span>
@@ -23,7 +23,7 @@
23
23
  <div class="fixed inset-0 z-10 w-screen overflow-y-auto">
24
24
  <div class="flex min-h-full items-center justify-center p-4" data-action="click->uikit-modal#close:self">
25
25
  <div
26
- class="relative transform overflow-y-visible rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:min-w-96 sm:p-6 w-full sm:w-auto hidden"
26
+ class="relative transform overflow-y-visible rounded-lg bg-white px-4 pb-4 pt-5 text-start shadow-xl transition-all sm:my-8 sm:min-w-96 sm:p-6 w-full sm:w-auto hidden"
27
27
  data-uikit-modal-target="dialog"
28
28
  data-transition-enter="ease-out duration-100"
29
29
  data-transition-enter-start="opacity-0 -translate-y-6 scale-95"
@@ -36,12 +36,12 @@
36
36
  <div class="flex items-center justify-between">
37
37
  <h2 class="text-gray-800 font-semibold antialiased text-lg"><%= title %></h2>
38
38
 
39
- <div class="ml-auto pl-2 gap-0.5 flex items-center">
39
+ <div class="ms-auto ps-2 gap-0.5 flex items-center">
40
40
  <% if notification? %>
41
41
  <%= notification %>
42
42
  <% end %>
43
43
 
44
- <div class="relative -right-2">
44
+ <div class="relative -end-2">
45
45
  <%= render Maglev::Uikit::IconButtonComponent.new(icon_name: 'close', data: { action: 'click->uikit-modal#close' }) %>
46
46
  </div>
47
47
  </div>
@@ -19,7 +19,7 @@ module Maglev
19
19
  def dialog_classes
20
20
  class_variants(
21
21
  base: %(
22
- relative transform overflow-y-visible rounded-lg bg-white px-4 pb-4 pt-5 text-left
22
+ relative transform overflow-y-visible rounded-lg bg-white px-4 pb-4 pt-5 text-start
23
23
  shadow-xl transition-all sm:my-8 sm:p-6 hidden
24
24
  ),
25
25
  variants: {
@@ -1,4 +1,4 @@
1
1
  <%= link_to path, class: 'text-gray-500 hover:text-gray-700 inline-flex items-center space-x text-xs', data: { turbo_frame: '_top' } do %>
2
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_left', size: '1.15rem', class_names: 'relative -left-1') %>
2
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_left', size: '1.15rem', class_names: 'relative -start-1 rtl:-scale-x-100') %>
3
3
  <%= content %>
4
4
  <% end %>
@@ -22,14 +22,14 @@
22
22
  <%= title_html %>
23
23
  <% end %>
24
24
  </div>
25
- <div class="ml-auto pl-2 gap-0.5 flex items-center">
25
+ <div class="ms-auto ps-2 gap-0.5 flex items-center">
26
26
  <turbo-frame id="page-layout-notification">
27
27
  <% if notification? %>
28
28
  <%= notification %>
29
29
  <% end %>
30
30
  </turbo-frame>
31
31
 
32
- <%= link_to back_path, class: 'h-7 w-7 flex items-center justify-center rounded-full focus:outline-none transition-colors duration-200 relative -right-2 bg-gray-600/0 hover:text-gray-900 text-gray-800 hover:bg-gray-600/10', data: { turbo_frame: '_top' } do %>
32
+ <%= link_to back_path, class: 'h-7 w-7 flex items-center justify-center rounded-full focus:outline-none transition-colors duration-200 relative -end-2 bg-gray-600/0 hover:text-gray-900 text-gray-800 hover:bg-gray-600/10', data: { turbo_frame: '_top' } do %>
33
33
  <%= render Maglev::Uikit::IconComponent.new(name: 'close', size: '1.15rem') %>
34
34
  <% end %>
35
35
  </div>
@@ -21,11 +21,11 @@ module Maglev
21
21
  class_variants(
22
22
  base: %(
23
23
  slide-pane absolute inset-y-0 h-[100dvh-(--spacing(16))] bg-white
24
- border-r border-gray-200 origin-top-left flex flex-col top-16 w-104
24
+ border-e border-gray-200 origin-top-left rtl:origin-top-right flex flex-col top-16 w-104
25
25
  ),
26
26
  variants: {
27
- expanded: 'left-0 z-40',
28
- '!expanded': 'left-16 z-10'
27
+ expanded: 'start-0 z-40',
28
+ '!expanded': 'start-16 z-10'
29
29
  }
30
30
  ).render(expanded: expanded)
31
31
  end
@@ -1,11 +1,11 @@
1
1
  <% a = pagy_anchor(pagy) %>
2
2
 
3
3
  <% left_arrow = capture do %>
4
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_left', size: '1.25rem') %>
4
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_left', size: '1.25rem', class_names: 'rtl:-scale-x-100') %>
5
5
  <% end %>
6
6
 
7
7
  <% right_arrow = capture do %>
8
- <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1.25rem') %>
8
+ <%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1.25rem', class_names: 'rtl:-scale-x-100') %>
9
9
  <% end %>
10
10
 
11
11
  <div class="flex items-center justify-between bg-white w-full h-10">
@@ -19,9 +19,9 @@
19
19
  <% end %>
20
20
 
21
21
  <% if pagy.next %>
22
- <%== a.(pagy.next, pagy_t('pagy.aria_label.next'), aria_label: 'Next', classes: 'relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100') %>
22
+ <%== a.(pagy.next, pagy_t('pagy.aria_label.next'), aria_label: 'Next', classes: 'relative ms-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100') %>
23
23
  <% else %>
24
- <a role="link" aria-disabled="true" aria-label="Next" class="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100">
24
+ <a role="link" aria-disabled="true" aria-label="Next" class="relative ms-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100">
25
25
  <%= pagy_t('pagy.aria_label.next') %>
26
26
  </a>
27
27
  <% end %>
@@ -1,15 +1,15 @@
1
1
  <div
2
- class="absolute top-0 left-0 mt-2 ml-2 flex hidden transition ease-[cubic-bezier(0.55,0,0.1,1)]"
2
+ class="absolute top-0 start-0 mt-2 ms-2 flex hidden transition ease-[cubic-bezier(0.55,0,0.1,1)]"
3
3
  data-uikit-section-toolbar-target="topLeftCorner"
4
4
  data-transition-enter="duration-200"
5
- data-transition-enter-start="-translate-x-[50%] opacity-0"
5
+ data-transition-enter-start="-translate-x-[50%] rtl:translate-x-[50%] opacity-0"
6
6
  data-transition-enter-end="translate-x-0 opacity-100"
7
7
  data-transition-leave="duration-200"
8
8
  data-transition-leave-start="translate-x-0 opacity-100"
9
- data-transition-leave-end="-translate-x-[50%] opacity-0"
9
+ data-transition-leave-end="-translate-x-[50%] rtl:translate-x-[50%] opacity-0"
10
10
  >
11
11
  <div
12
- class="bg-editor-primary text-white py-1 px-3 rounded-l-2xl rounded-r-2xl text-xs flex items-center"
12
+ class="bg-editor-primary text-white py-1 px-3 rounded-s-2xl rounded-e-2xl text-xs flex items-center"
13
13
  >
14
14
  <span><%= label %></span>
15
15
  </div>
@@ -1,11 +1,11 @@
1
- <div class="absolute top-0 right-0 mt-2 mr-2 flex justify-center gap-x-2 hidden transition ease-[cubic-bezier(0.55,0,0.1,1)]"
1
+ <div class="absolute top-0 end-0 mt-2 me-2 flex justify-center gap-x-2 hidden transition ease-[cubic-bezier(0.55,0,0.1,1)]"
2
2
  data-uikit-section-toolbar-target="topRightCorner"
3
3
  data-transition-enter="duration-200"
4
- data-transition-enter-start="translate-x-[50%] opacity-0"
4
+ data-transition-enter-start="translate-x-[50%] rtl:-translate-x-[50%] opacity-0"
5
5
  data-transition-enter-end="translate-x-0 opacity-100"
6
6
  data-transition-leave="duration-200"
7
7
  data-transition-leave-start="translate-x-0 opacity-100"
8
- data-transition-leave-end="translate-x-[50%] opacity-0"
8
+ data-transition-leave-end="translate-x-[50%] rtl:-translate-x-[50%] opacity-0"
9
9
  >
10
10
  <%= link_to paths[:edit], class: button_classes, data: { turbo_frame: '_top' } do %>
11
11
  <%= render Maglev::Uikit::IconComponent.new(name: 'pencil') %>
@@ -3,6 +3,8 @@
3
3
  # rubocop:disable Metrics/ModuleLength
4
4
  module Maglev
5
5
  module ApplicationHelper
6
+ RTL_UI_LOCALES = %i[ar he fa ur].freeze
7
+
6
8
  ## "system" helpers
7
9
  def turbo_stream
8
10
  # we don't want to pollute the global Turbo::Streams::TagBuilder
@@ -63,6 +65,10 @@ module Maglev
63
65
  end
64
66
 
65
67
  ## Editor helpers
68
+ def maglev_editor_direction
69
+ RTL_UI_LOCALES.include?(editor_ui_locale.to_sym) ? 'rtl' : 'ltr'
70
+ end
71
+
66
72
  def maglev_editor_title
67
73
  case maglev_config.title
68
74
  when nil
@@ -1,4 +1,4 @@
1
- <html lang="<%= I18n.locale %>">
1
+ <html lang="<%= editor_ui_locale %>" dir="<%= maglev_editor_direction %>">
2
2
  <head>
3
3
  <title><%= maglev_editor_title %></title>
4
4
  <meta name="view-transition" content="same-origin" />
@@ -19,7 +19,7 @@
19
19
  <% end %>
20
20
 
21
21
  </div>
22
- <div class="ml-auto">
22
+ <div class="ms-auto">
23
23
  <%= render Maglev::Uikit::ImageLibrary::UploaderComponent.new(
24
24
  create_path: editor_assets_path,
25
25
  refresh_path: editor_assets_path(query_params)
@@ -1,5 +1,5 @@
1
1
  <div
2
- class="absolute top-16 left-16 right-0 bottom-0 z-0 overflow-hidden group"
2
+ class="absolute top-16 start-16 end-0 bottom-0 z-0 overflow-hidden group"
3
3
  data-controller="editor-page-preview"
4
4
  data-action="
5
5
  uikit-device-toggler:change@window->editor-page-preview#changeDevice
@@ -14,7 +14,7 @@
14
14
  >
15
15
  <div
16
16
  id="page-preview"
17
- class="bg-gray-50 origin-top-left transition-transform duration-150 ease-out will-change-transform transform-gpu hidden opacity-0 group-[.is-loaded]:opacity-100 group-[.is-loaded]:block"
17
+ class="bg-gray-50 origin-top-left rtl:origin-top-right transition-transform duration-150 ease-out will-change-transform transform-gpu hidden opacity-0 group-[.is-loaded]:opacity-100 group-[.is-loaded]:block"
18
18
  data-editor-page-preview-target="iframe-wrapper"
19
19
  >
20
20
  <iframe
@@ -28,7 +28,7 @@
28
28
  </div>
29
29
 
30
30
  <div class="flex h-full w-full justify-center items-center transition-discrete transition-all duration-100 ease-in-out opacity-100 group-[.is-loaded]:opacity-0 group-[.is-loaded]:hidden" data-editor-page-preview-target="loading">
31
- <p class="animate-bounce duration-200 group-data-[expanded-page-layout]/page-layout:pl-88">
31
+ <p class="animate-bounce duration-200 group-data-[expanded-page-layout]/page-layout:ps-88">
32
32
  <%= t('maglev.editor.page_preview.loading') %>
33
33
  </p>
34
34
  </div>
@@ -1,5 +1,5 @@
1
1
  <%# z-[5]: below PageLayoutComponent (z-10 / z-40), above preview shell (z-0). editor-preview-empty: tailwind.css.erb @custom-variant on [data-controller~="editor-page-preview"].is-empty %>
2
- <div class="fixed top-16 left-16 right-0 bottom-0 z-[5] bg-gray-50 hidden editor-preview-empty:block">
2
+ <div class="fixed top-16 start-16 end-0 bottom-0 z-[5] bg-gray-50 hidden editor-preview-empty:block">
3
3
  <div class="flex min-h-full flex-col items-center justify-center px-4">
4
4
  <h2 class="text-center text-2xl font-bold">
5
5
  <%= t('maglev.editor.page_preview.empty.title') %>
@@ -38,9 +38,9 @@
38
38
  <% end %>
39
39
 
40
40
  <% if @section.child_blocks_of(section_block.id).any? %>
41
- <div class="ml-5 mt-3">
42
- <%= render 'maglev/editor/section_blocks/index/tree',
43
- blocks: @section.child_blocks_of(section_block.id),
41
+ <div class="ms-5 mt-3">
42
+ <%= render 'maglev/editor/section_blocks/index/tree',
43
+ blocks: @section.child_blocks_of(section_block.id),
44
44
  parent_id: section_block.id
45
45
  %>
46
46
  </div>
@@ -1,5 +1,5 @@
1
1
  <div class="
2
- absolute inset-0 top-16 left-16 group-data-[expanded-page-layout]/page-layout:left-104 bg-transparent z-5 pointer-events-none mx-auto
2
+ absolute inset-0 top-16 start-16 group-data-[expanded-page-layout]/page-layout:start-104 bg-transparent z-5 pointer-events-none mx-auto
3
3
  group-data-[device=mobile]/device:w-[calc(375px*var(--page-preview-scale-ratio))] group-data-[device=tablet]/device:w-[calc(1024px*var(--page-preview-scale-ratio))]
4
4
  ">
5
5
  <% current_maglev_sections.each_with_index do |section, index| %>
@@ -25,9 +25,11 @@
25
25
  <% end %>
26
26
  <% end %>
27
27
 
28
- <% item.with_title_content(section.human_name) %>
28
+ <% item.with_title_content(section.human_name) %>
29
29
 
30
- <%= f.radio_button :section_type, section.id, class: 'sr-only peer' %>
30
+ <% item.with_leading do %>
31
+ <%= f.radio_button :section_type, section.id, class: 'sr-only peer' %>
32
+ <% end %>
31
33
  <% end %>
32
34
  <% end %>
33
35
  </div>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Maglev
4
- VERSION = '3.0.3'
4
+ VERSION = '3.1.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maglevcms
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Didier Lafforgue
@@ -121,16 +121,22 @@ dependencies:
121
121
  name: view_component
122
122
  requirement: !ruby/object:Gem::Requirement
123
123
  requirements:
124
- - - "~>"
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 4.12.0
127
+ - - "<"
125
128
  - !ruby/object:Gem::Version
126
- version: 4.1.1
129
+ version: '5'
127
130
  type: :runtime
128
131
  prerelease: false
129
132
  version_requirements: !ruby/object:Gem::Requirement
130
133
  requirements:
131
- - - "~>"
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 4.12.0
137
+ - - "<"
132
138
  - !ruby/object:Gem::Version
133
- version: 4.1.1
139
+ version: '5'
134
140
  description: " MaglevCMS integrates a powerful website/page builder with a polished
135
141
  UX/UI into your Ruby on Rails application, backed by a flexible and robust CMS engine.\n"
136
142
  email: