unholy-design-tokens 1.0.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 (111) hide show
  1. package/.github/workflows/lint-format-build.yml +35 -0
  2. package/.github/workflows/publish_release.yml +18 -0
  3. package/.prettierrc +9 -0
  4. package/ANALOGY_HOUSE.md +139 -0
  5. package/ANALOGY_I18NEXT.md +160 -0
  6. package/LICENSE +201 -0
  7. package/README.md +90 -0
  8. package/WHY_THIS_EXISTS.md +74 -0
  9. package/bin/build-tokens.ts +34 -0
  10. package/build/css/bg/bg.css +60 -0
  11. package/build/css/border/border.css +51 -0
  12. package/build/css/colors.css +204 -0
  13. package/build/css/conditional.css +8 -0
  14. package/build/css/cube/cube.block.css +18 -0
  15. package/build/css/cube/cube.composition.css +16 -0
  16. package/build/css/cube/cube.utility.css +185 -0
  17. package/build/css/font/font.css +24 -0
  18. package/build/css/space.css +20 -0
  19. package/build/css/text/text.css +48 -0
  20. package/build/css/themes/private-theme.css +228 -0
  21. package/build/css/themes/public-theme.css +228 -0
  22. package/build/css/variant/variant.css +42 -0
  23. package/build/css/variants.css +167 -0
  24. package/build/types/theme.d.ts +932 -0
  25. package/build/types/tokens.ts +653 -0
  26. package/dist/bin/build-tokens.js +27 -0
  27. package/dist/scripts/build-style-dictionary.js +32 -0
  28. package/dist/scripts/generate-typography-tokens.js +125 -0
  29. package/dist/src/colors/color.config.js +45 -0
  30. package/dist/src/colors/color.filter.js +19 -0
  31. package/dist/src/colors/color.formatter.js +25 -0
  32. package/dist/src/colors/index.js +2 -0
  33. package/dist/src/cube-css/cube.config.js +42 -0
  34. package/dist/src/cube-css/cube.formatter.js +89 -0
  35. package/dist/src/style-dictionary.config.js +143 -0
  36. package/dist/src/type-declarations/type-declarations.config.js +29 -0
  37. package/dist/src/type-declarations/type-declarations.formatter.js +111 -0
  38. package/dist/src/utils/helpers.js +9 -0
  39. package/dist/src/utils/index.js +4 -0
  40. package/dist/src/utils/template.js +83 -0
  41. package/dist/src/utils/tokens.js +80 -0
  42. package/dist/src/utils/utopia.js +19 -0
  43. package/eslint.config.js +67 -0
  44. package/package.json +60 -0
  45. package/scripts/build-style-dictionary.ts +44 -0
  46. package/scripts/generate-typography-tokens.ts +138 -0
  47. package/src/LICENSE +201 -0
  48. package/src/README.md +88 -0
  49. package/src/colors/color.config.ts +48 -0
  50. package/src/colors/color.filter.ts +28 -0
  51. package/src/colors/color.formatter.ts +43 -0
  52. package/src/colors/index.ts +6 -0
  53. package/src/cube-css/cube.config.ts +50 -0
  54. package/src/cube-css/cube.formatter.ts +104 -0
  55. package/src/formatters/spacing.js +95 -0
  56. package/src/style-dictionary.config.ts +151 -0
  57. package/src/theme/README.md +256 -0
  58. package/src/theme/cube-theme-addon.js +44 -0
  59. package/src/theme/helper.js +38 -0
  60. package/src/theme/index.js +6 -0
  61. package/src/theme/theme.config.js +42 -0
  62. package/src/theme/theme.filter.js +42 -0
  63. package/src/theme/theme.formatter.js +71 -0
  64. package/src/tokens/1 - primitives/README.md +58 -0
  65. package/src/tokens/1 - primitives/border.json +54 -0
  66. package/src/tokens/1 - primitives/breakpoint.json +10 -0
  67. package/src/tokens/1 - primitives/color-pool.json +266 -0
  68. package/src/tokens/1 - primitives/color.json +266 -0
  69. package/src/tokens/1 - primitives/font-scale.json +27 -0
  70. package/src/tokens/1 - primitives/font.json +23 -0
  71. package/src/tokens/1 - primitives/shadow.json +26 -0
  72. package/src/tokens/1 - primitives/space.json +27 -0
  73. package/src/tokens/2 - semantic/README.md +49 -0
  74. package/src/tokens/2 - semantic/border.json +27 -0
  75. package/src/tokens/2 - semantic/color.json +263 -0
  76. package/src/tokens/2 - semantic/details.md +1 -0
  77. package/src/tokens/2 - semantic/layout.json +52 -0
  78. package/src/tokens/2 - semantic/radius.json +13 -0
  79. package/src/tokens/2 - semantic/shadow.json +19 -0
  80. package/src/tokens/2 - semantic/spacing.json +25 -0
  81. package/src/tokens/3 - intent/README.md +43 -0
  82. package/src/tokens/3 - intent/background.json +135 -0
  83. package/src/tokens/3 - intent/color.json +265 -0
  84. package/src/tokens/3 - intent/font.json +61 -0
  85. package/src/tokens/3 - intent/text +67 -0
  86. package/src/tokens/README.md +176 -0
  87. package/src/tokens/color/brand.json +316 -0
  88. package/src/tokens/component/theming.json +69 -0
  89. package/src/tokens/conditional.json +40 -0
  90. package/src/tokens/custom/4 - (OPTIONAL) cube css/README.md +38 -0
  91. package/src/tokens/custom/4 - (OPTIONAL) cube css/block.json +24 -0
  92. package/src/tokens/custom/4 - (OPTIONAL) cube css/composition.json +26 -0
  93. package/src/tokens/custom/4 - (OPTIONAL) cube css/global.json +15 -0
  94. package/src/tokens/custom/4 - (OPTIONAL) cube css/utility.json +224 -0
  95. package/src/tokens/custom/OKlch/color.json +61 -0
  96. package/src/tokens/custom/OKlch/state.json +107 -0
  97. package/src/tokens/custom/OKlch/theme-color.json +34 -0
  98. package/src/tokens/custom/OKlch/variant.json +67 -0
  99. package/src/tokens/custom/components/highlighted.json +16 -0
  100. package/src/tokens/state.js +29 -0
  101. package/src/tokens/theme-color.json +34 -0
  102. package/src/type-declarations/type-declarations.config.ts +34 -0
  103. package/src/type-declarations/type-declarations.formatter.ts +122 -0
  104. package/src/utils/helpers.ts +11 -0
  105. package/src/utils/index.ts +4 -0
  106. package/src/utils/template.ts +110 -0
  107. package/src/utils/tokens.ts +95 -0
  108. package/src/utils/utopia.ts +36 -0
  109. package/tailwind.md +720 -0
  110. package/tsconfig.json +19 -0
  111. package/turbowatch.ts +14 -0
package/tailwind.md ADDED
@@ -0,0 +1,720 @@
1
+ Hey
2
+
3
+ I’m a bit surprised by how this turned out. Also why it happens now
4
+
5
+ There’s a lot of things - probably would have been better to sync first 😅 I didn't expect you would come with such a big refactoring - and that I would be pressed to review as we don't have much time :/ also I feel you misunderstood my idea of getting rid of Tailwind, and there's this "AI part"
6
+ We will find some
7
+
8
+ ---
9
+
10
+ ### **"Tailwind and CSS architecture Bootcamp"**
11
+
12
+ 🗒️ There is a special page for me - you quoted and used the 4 private messages of our chat (part 2 🔝 ) as source material for AI (not fair :D) regarding Tailwind - this was casual talks, with as we stated resulted in a bit harsh “tone”.
13
+
14
+ I also don’t know which part is from AI / which is from you. But I will assume that every words and statements present there is from you, or at least the meaning of the sections.
15
+
16
+ I do find some part quite opinionated and tends to interpret some of my personal thoughts, to being condescension on my way of work or regarding Design Systems, so I will answer in the same way.
17
+
18
+ I asked ChatGPT about it
19
+
20
+ <img width="1468" height="300" alt="image" src="https://github.com/user-attachments/assets/ba7ad480-4563-41d4-afbc-8d9f8403584c" />
21
+
22
+ <img width="1742" height="1206" alt="image" src="https://github.com/user-attachments/assets/da7d0200-0644-4a05-b14a-888868f9badf" />
23
+
24
+ Don't get me wrong, I'm not mad, but definitely want to correct many points 😄
25
+
26
+ I will for the most part not using any AI, I think some subjects require details as the refactoring is quite big
27
+
28
+ ---
29
+
30
+ <details>
31
+ <summary>The Design System</summary>
32
+ ## The status of the Design System
33
+ We started implementing a new design system in the end of 2024.
34
+ Having such PR ~1 year later can not be more illustrating how the lack of communication and the process went quite wrong.
35
+ I take [**@bilbo7833**](https://github.com/bilbo7833) as witness on how many times he didn't understand why was it so long, and why I took so much time. The truth is we were both working on our side - without proper sync... to mitigate - the current UI Library works, I'm just personally not super happy of the result.
36
+ There were some messages a while ago
37
+ <img width="998" height="1022" alt="image" src="https://github.com/user-attachments/assets/ff8c309c-a68a-4300-89da-ad5c058b9975" />
38
+ [link](https://teams.microsoft.com/l/message/19:4ae921a1580a414888d0f3ec32618b9f@thread.v2/1733059683515?context=%7B%22contextType%22%3A%22chat%22%7D)
39
+
40
+ (The all exchange is worth reading, also Joshi's answer and ask the question of if we should have done from scratch for example)
41
+
42
+ We still don't have all the screws.
43
+
44
+ </details>
45
+
46
+ ---
47
+
48
+ I think I will start by explaining why I considered moving away from Tailwind, as that will help to answer many questions from the `.md` files and to review the overall PR.
49
+
50
+ ### **TL;DR - I found back [this comment](https://github.com/reteach/reteach-app/pull/4063#issuecomment-2449480616) I put on the initialization of the UI Library. (exactly one year ago)**
51
+
52
+ I list the concerns I had with Tailwind and "utility-first" in general.
53
+ One year later, I can unfortunately confirm these concerns, but now I can and will describe more *why*
54
+
55
+ # Why I fear Tailwind in the long term or in a big project short/mid-term
56
+
57
+ First I'll clarify my incentives when working with design system / UI libraries. In this PR there's statements that assume my vision on a Design System and give me recommendations, I will put my take, also it's more clear if we disagree from the early point 😄
58
+ Moving away from Tailwind is not *only* a personal preference
59
+
60
+ ## I care about bridging the gap between Developers and Design System foundations 
61
+
62
+ <a id="ds-conception"></a> Foundations are the core base variables that shape every color, size, and style in the product.
63
+
64
+ 🎨 Once defined, they bring the first important factor: **$\large{\color{teal}{\text{Consistency}}}$**.
65
+
66
+ But here's one key: I think **$\large{\color{teal}{\text{Consistency}}}$** that can last without getting too much tech debt is to **limit these variables**, rather than having a larger scale.
67
+ You can always extend later, but reducing is harder.
68
+
69
+ This brings more robustness to the system, an immediate visual catch from the end-user, and more important, an easier **$\large{\color{lightgreen}{\text{Scalability}}}$** from day one.
70
+
71
+ It's how I would define an efficient starting point for a Design System. The rest is in the hands of designer 🖌️
72
+ I thought important to define this before next part
73
+
74
+ ## <img width="20" alt="image" src="https://github.com/user-attachments/assets/5eed85b8-b9c9-4aed-b92d-b0ccc0eb388b" /> Tailwind's workflow - how is it used
75
+
76
+ Origins of Tailwind
77
+
78
+ ### 1. The "Separation of Concerns" and HTML semantics - why Tailwind was created
79
+
80
+ From Tailwind doc (version 3 - it's important to write for later :))
81
+
82
+ > Rapidly build modern websites without ever leaving your HTML.
83
+
84
+ Tailwind was originally created in opposition of semantic CSS which would bring too much complexity and poor vision on layout / spacing / colors and bloat your CSS code.
85
+
86
+ There is this article from the creator [https://adamwathan.me/css-utility-classes-and-separation-of-concerns](https://adamwathan.me/css-utility-classes-and-separation-of-concerns) (it's worth the read) where he stated that at the end, HTML is tied to CSS and CSS is tied to HTML - and by any method, we end up duplicating CSS.
87
+
88
+ It's where he wrote the "Utility-First" term for the first time 😉
89
+
90
+ ### 2. Concept
91
+
92
+ From Tailwind [docs](https://v3.tailwindcss.com/):
93
+
94
+ > A utility-first CSS framework packed with classes like flex, pt-4, text-center and rotate-90 that can be composed to build any design, directly in your markup.
95
+
96
+ With Tailwind, you get a ready-to-go configuration and design token that you can then customize, add your own tools etc. but the core of it is utility classes (and *only* utility classes) aiming lack of abstraction.
97
+
98
+ One class = one single thing, easy to get on board. Perfect for prototyping, and if your theme config is in accordance with a defined design system, you're ready to go.
99
+
100
+ ---
101
+
102
+ ### 3. Building component that don't rely on the content and without abstraction
103
+
104
+ As they state:
105
+
106
+ > When you realize how productive you can be working exclusively in HTML with predefined utility classes, working any other way will feel like torture.
107
+
108
+ So you create components, it's fast and you might end-up with component as such (`RtDateRangePicker`)
109
+
110
+ ```vue
111
+ <template>
112
+ <div
113
+ id="default-daterangepicker"
114
+ class="rt-flex rt-items-center rt-gap-2 rt-flex-col"
115
+ >
116
+ <div class="rt-relative rt-w-full">
117
+ <div
118
+ class="rt-absolute rt-inset-y-0 rt-end-0 rt-flex rt-items-center rt-pe-4 rt-pointer-events-none"
119
+ >
120
+ <CalendarIcon />
121
+ </div>
122
+ <input
123
+ id="default-datepicker-1"
124
+ datepicker
125
+ type="text"
126
+ class="rt-bg-white rt-appearance-none rt-border rt-border-solid rt-border-neutral-400 focus:rt-border-neutral-800 focus:rt-outline-0 rt-rounded-lg rt-block rt-w-full rt-pe-9 rt-p-2.5"
127
+ :placeholder="placeholder"
128
+ />
129
+ </div>
130
+ <div class="rt-relative rt-grow-0">
131
+ <span class="rt-body-small-regular">{{ spanWord }}</span>
132
+ </div>
133
+ <div class="rt-relative rt-w-full">
134
+ <div
135
+ class="rt-absolute rt-inset-y-0 rt-end-0 rt-flex rt-items-center rt-pe-4 rt-pointer-events-none"
136
+ >
137
+ <CalendarIcon />
138
+ </div>
139
+ <input
140
+ id="default-datepicker-2"
141
+ datepicker
142
+ type="text"
143
+ class="rt-bg-white rt-appearance-none rt-border rt-border-solid rt-border-neutral-400 focus:rt-border-neutral-800 focus:rt-outline-0 rt-rounded-lg rt-block rt-w-full rt-pe-9 rt-p-2.5"
144
+ :placeholder="placeholder"
145
+ />
146
+ </div>
147
+ </div>
148
+ </template>
149
+ ```
150
+
151
+ At first writing, it's fine, and can be done fast. The UI is built continuously as you chain the utility classes.
152
+
153
+ Good for initial **$\large{\color{teal}{\text{Consistency}}}$**
154
+
155
+ But what if this component needs to be changed / modified in the future? This change could simply be a border / background change from one part of the Datepicker for example.
156
+
157
+ ---
158
+
159
+ ## ⚙️ Complexity as the project grows - What problems does Tailwind bring
160
+
161
+ ### 1. Readability 👓
162
+
163
+ - It can be hard hard to see what each tag is doing or rendering if no visual on a browser or so
164
+ - There are a lot of `<div>` - and we *don't know at first what is doing what*, you need to read class by class to understand it, as elements are not identified (see [here](https://github.com/arthur-plazanet/thoughts/pull/1#naming-things))
165
+ - `-neutral-400` or `-neutral-800` (or even with any word such `-primary-400` or `-primary-800` - even though a bit better) doesn't bring a lot of *context*
166
+
167
+ ❓ Which brings the question: "Why this new language? What does it bring?"
168
+ *What is Tailwind* at the end?
169
+
170
+ Tailwind create utility classes that usually do one thing, based on declarative CSS properties
171
+
172
+ | **Raw CSS Declaration** | **Tailwind Utility Class** | **Applied in HTML** | **Final Rendered UI** |
173
+ | ----------------------- | -------------------------- | -------------------------- | ----------------------------------------------- |
174
+ | `display: flex;` | `.flex { display: flex; }` | `<div class="flex"></div>` | 🧩 Element is displayed as a flexbox container. |
175
+
176
+ ---
177
+
178
+ ### 2. Tailwind is a layer on top of native CSS
179
+
180
+ ### ⚙️ Why does it bring more complexity:
181
+
182
+ - By mapping CSS declaration to a new syntax - you now depend on any changes from the original API
183
+ - It's a new grammar to learn, on top of HTML/CSS (as additional "layer")
184
+ - Even though it can be considered "industry-standard" - `p-3` doesn't always resolve to the same value as each theming is different.
185
+ - As each new "tool" / library we decide to use on top of native standards, it bring inconsistencies
186
+ - Tailwind classes are not always directly intuitive or worded as the corresponded CSS rule. A few examples:
187
+ - In CSS Flexbox or Grid, `justify-content` / `align-items` / `align-content` are often used to position items in a layout. How does it translate in terms of Tailwind's classes?
188
+ - `justify-*` for `justify-content` - which makes sense and is consistent with the initial syntax
189
+ - but for `align-items`, it is `items-*`
190
+ - `font-weight` is `font-*` but `font-size` is `text-*`
191
+ - `border-radius` is `rounded-*`
192
+ - Maintainability is a concern, as we rely on an external tool (see [Tailwind v4](https://github.com/arthur-plazanet/thoughts/pull/1#tailwind-v4))
193
+
194
+ ---
195
+
196
+ ### 3. Semantic 📏 and understandable code
197
+
198
+ ### This is our `RtSkeleton`
199
+
200
+ ```vue
201
+ <template>
202
+ <div
203
+ class=" rt-relative rt-w-full rt-h-full rt-group data-[loading=true] [&_.rt-skeleton-placeholder]:rt-opacity-0"
204
+ ref="skeletonRef"
205
+ v-bind="attrs"
206
+ >
207
+ <div
208
+ class="rt-skeleton-placeholder rt-absolute rt-inset-0 rt-z-10 group-data-[loading=true]:rt-opacity-100 rt-pointer-events-none rt-transition-opacity rt-duration-400 rt-ease-in-out"
209
+ :style="skeletonStyles"
210
+ >
211
+ <RtSkeletonText />
212
+ </div>
213
+ <div
214
+ class="transition-opacity rt-duration-400 ease-in-out z-20 relative rt-h-full group-data-[loading=true]:rt-opacity-0 group-data-[loading=true]:rt-pointer-events-none"
215
+ >
216
+ <slot />
217
+ </div>
218
+ </div>
219
+ </template>
220
+ ```
221
+
222
+ ### Here is a pretty much equivalent component in my [UI Library](https://github.com/use-compose/ui/blob/dev/src/components/YSkeleton/YSkeleton.vue) - `YSkeleton`
223
+
224
+ ```vue
225
+ <template>
226
+ <div :class="getClasses">
227
+ <slot>
228
+ <div class="brutalist-skeleton brutalist-skeleton-line"></div>
229
+ <div class="brutalist-skeleton brutalist-skeleton-block"></div>
230
+ <div class="brutalist-skeleton brutalist-skeleton-circle"></div>
231
+ </slot>
232
+ </div>
233
+ </template>
234
+ ```
235
+
236
+ Here's our RtModalHeader:
237
+
238
+ ```vue
239
+ <template>
240
+ <header :class="$slots.default ? '' : 'rt-px-10 rt-py-6'">
241
+ <slot>
242
+ <div class="rt-flex rt-items-start rt-gap-x-4">
243
+ <div class="rt-pt-2 rt-pb-4 rt-flex rt-flex-1 rt-flex-col rt-gap-y-1">
244
+ <RtHeading
245
+ size="2"
246
+ variant="bold"
247
+ class="rt-m-0 rt-text-neutral-900"
248
+ >{{ header }}</RtHeading
249
+ >
250
+ <RtHeading
251
+ size="3"
252
+ v-if="hasSubHeader"
253
+ class="rt-m-0 rt-text-neutral-700"
254
+ >{{ subHeader }}</RtHeading
255
+ >
256
+ </div>
257
+ <div v-if="hasCloseButton" class="rt-flex rt-items-start">
258
+ <RtIconButton variant="secondary" tone="neutral" @click="close">
259
+ <CloseIcon color="neutral-600" />
260
+ </RtIconButton>
261
+ </div>
262
+ </div>
263
+ </slot>
264
+ </header>
265
+ </template>
266
+ ```
267
+
268
+ Equivalent in [@use-compose/ui](https://github.com/use-compose/ui/blob/dev/src/components/YModal/components/YModalHeader.vue) - `YModalHeader`
269
+
270
+ ```vue
271
+ <template>
272
+ <header class="y-modal-header">
273
+ <slot>
274
+ <div class="flex justify-between">
275
+ <h2 class="margin-0">{{ header }}</h2>
276
+ <CloseIcon
277
+ v-if="props.hasCloseButton"
278
+ class="cursor-pointer align-self-start"
279
+ :width="48"
280
+ :height="48"
281
+ @click="close"
282
+ />
283
+ </div>
284
+ </slot>
285
+ </header>
286
+ </template>
287
+ ```
288
+
289
+ None of these code is perfect, they both might get tech debt with time. The difference is that in the Tailwind version, it's utility *only*, while in the other the setup is more hybrid:
290
+
291
+ - It uses Design Tokens (with [Style-Dictionary](https://github.com/use-compose/ui/blob/dev/style-dictionary/config.js))
292
+ - It also uses utility classes but not for everything
293
+ - But take also advantage of *semantic* classes. This doesn't have to be "one new class every time" but content related shorter word that help the reader.
294
+
295
+ Concretely, what does that change?
296
+ We could argue for days about which approach is better for your system with thousands of components / more scalable, makes more sense etc.
297
+
298
+ But which one is more readable / easy to get into as a new developer getting into the codebase?
299
+
300
+ **Note:** ➡️ I want to make the code clearer enough that anyone can understand and start contributing from day 1 🏄
301
+
302
+ For this, I do think using a more semantic approach help for scalability
303
+
304
+ Important
305
+
306
+ All of these points **assume that your initial Tailwind configuration is already done and won't change**
307
+
308
+ ---
309
+
310
+ ## Deeper issues - Scalability and Consistency 👨‍💻
311
+
312
+ ### 1. Maintainability
313
+
314
+ In addition of previous points:
315
+
316
+ - Tailwind initial theming configuration is already made and ready to start. Which can be fine, but not if you want to build a robust scalable design system in my opinion. I truly believe in [this](#ds-conception) and that the bases need to be done at the beginning :) It will take times, as a diesel - to sync and start 🎨🔗💻 but then it's a no game :) 🚗💨⛽️
317
+ Also we have cases that relate to this it seems.
318
+ - It makes PR overall hard to review - [here](https://github.com/reteach/reteach-app/pull/5353/files#diff-7f5e41be8bf12d701559fe2972a7d676c4a0b52eab800e1d1b57af11179df708L12) the vertical scrollbar
319
+ - If you need to change a value in a component, you might need to do a global search and change individual Tailwind classes rather than one center single-source-of-truth
320
+ - Reusable components: you rely on the framework you use (Vue in our case) to create *visible* components to reuse
321
+ - DevTools and editor support are not fully up-to-date ([https://devtoolsfortailwind.com/](https://devtoolsfortailwind.com/)) so you rely on more and more tools (and Tailwind-related) which sometimes are not free
322
+
323
+ From the comment in the UI Library initialization, there's one part:
324
+
325
+ [image](https://github.com/user-attachments/assets/8a314d53-1d67-4840-a685-065956a30a58)
326
+
327
+ That brings, I think, a really important drawback of Tailwind
328
+
329
+ ---
330
+
331
+ ### <a id="naming-things"></a> **2. Naming things ✍️**
332
+
333
+ In Design, as well a in a codebase, we need to know "what" exactly we are dealing with.
334
+
335
+ - Is it a complete component?
336
+ - In Figma, this would be shown as an extracted and standalone component
337
+ - In the codebase... it depends, you rely on the factor that if the codebase is using a Framework (Vue, React) to name the component or not
338
+ - If you inspect a browser devtools, hard to say
339
+ - Is it just a "div wrapper"? It's common to see such div with a lot of tailwind classes. For example our `RtDropdown`, how did we figure out to create a `RtMenu`? It seems clear on paper but concretely - we just had a bunch of tailwind class and had to figure out what was the role/purpose of each
340
+ - If you need to change a component (e.g. for a bug), it can make things harder, leading to non-sense global search (think of DevTools again for example that wouldn't be helpful there).
341
+
342
+ 🏄 This point affect **$\large{\color{teal}{\text{Consistency}}}$** and **$\large{\color{lightgreen}{\text{Scalability}}}$** on the long term, and in short term it can also affects onboarding
343
+
344
+ Resource: [https://nicolasgallagher.com/about-html-semantics-front-end-architecture/](https://nicolasgallagher.com/about-html-semantics-front-end-architecture/)
345
+
346
+ ---
347
+
348
+ ### **3. CSS limitations**
349
+
350
+ The configuration file is initially generated with default "standard" values. But the more you want to customize your theme by integrating your design system, the more you face limitations.
351
+
352
+ Tailwind is sometimes a regression as it doesn't support all CSS features. From our codebase see [here](https://github.com/reteach/reteach-app/blob/dev/packages/ui/src/assets/styles/css/components/table.css#L5) or [here](https://github.com/reteach/reteach-app/blob/dev/apps/admin-frontend/src/components/atomics/atoms/tooltip/RtTooltip.scss#L6) for example. We don't know when it happens but it end up in loosing time searching for a solution to finally use a workaround as in 3.
353
+
354
+ Resources: [https://scriptraccoon.dev/blog/tailwind-disadvantages#missing-features](https://scriptraccoon.dev/blog/tailwind-disadvantages#missing-features)
355
+
356
+ ### **Build-time only**
357
+
358
+ Classes from Tailwind are generated only at build time. There's no way of using CSS custom properties that can be change at runtime directly, and we loose a lot of the new features CSS has to offer.
359
+
360
+ ---
361
+
362
+ ## **The "paradox" with Tailwind - and how do they respond**
363
+
364
+ CSS is now covering a lot of the features preprocessors and other tools were before in advance (layers, scoped styles, CSS variables, conditions etc.).
365
+
366
+ Tailwind lacks in this regard as explained before.
367
+
368
+ ### **1. The maintainability concern**
369
+
370
+ From their [docs](https://v3.tailwindcss.com/docs/utility-first#maintainability-concerns):
371
+
372
+ > The biggest maintainability concern when using a utility-first approach is managing commonly repeated utility combinations.
373
+
374
+ > This is easily solved by extracting components and partials, and using editor and language features like multi-cursor editing and simple loops.
375
+
376
+ In clear, they tell to either:
377
+
378
+ - Use your editor built-in tools to solve the issues we initially didn't have without Tailwind ("multi-cursor editing")
379
+ - "extracting components and partials" - which are their in-house solution when repetition becomes a problem
380
+
381
+ ---
382
+
383
+ ### **2. 🌀 Resolve the lack of Abstraction and their own Paradox**
384
+
385
+ As mentioned by Tailwind themselves,
386
+
387
+ > But of course as a project grows, you’ll inevitably find yourself repeating common utility combinations to recreate the same design in many different places.
388
+
389
+ They do propose alternative solutions to reuse styles, as of:
390
+
391
+ <table role="table" class="unchanged">
392
+ <thead>
393
+ <tr>
394
+ <th>Tailwind Solutions</th>
395
+ <th>Example</th>
396
+ <th>Problem(s)</th>
397
+ </tr>
398
+ </thead>
399
+ <tbody>
400
+ <tr>
401
+ <td>Using component partials <br> <a href="https://v3.tailwindcss.com/docs/reusing-styles#extracting-components-and-partials" rel="nofollow">("Create a template partial or JavaScript component")</a>
402
+ </td>
403
+ <td><a target="_blank" rel="noopener noreferrer" href="https://github.com/user-attachments/assets/3a86ea41-24a8-435b-ae2d-854a28e373ca"><img width="744" height="324" alt="image" src="https://github.com/user-attachments/assets/3a86ea41-24a8-435b-ae2d-854a28e373ca" style="max-width: 100%; height: auto; max-height: 324px;"></a></td>
404
+ <td>It basically means or is almost equivalent to use a framework to create components - with some edge cases as they show Vue + JSX, which is not even a really common use case</td>
405
+ </tr>
406
+ <tr>
407
+ <td>By using <a href="https://v3.tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply" rel="nofollow"><code class="notranslate">@apply</code></a>
408
+ </td>
409
+ <td><a target="_blank" rel="noopener noreferrer" href="https://github.com/user-attachments/assets/efea73af-35e1-461d-9fbf-fbfb104a2fc8"><img width="744" height="640" alt="image" src="https://github.com/user-attachments/assets/efea73af-35e1-461d-9fbf-fbfb104a2fc8" style="max-width: 100%; height: auto; max-height: 640px;"></a></td>
410
+ <td>That's it, so you use their own layer of utility classes <em>directly</em> inside the CSS, which they will resolve to... the CSS rule itself</td>
411
+ </tr>
412
+ <tr>
413
+ <td>By creating complex utility or even <a href="https://v3.tailwindcss.com/docs/adding-custom-styles#adding-component-classes" rel="nofollow">component classes</a>
414
+ </td>
415
+ <td><a target="_blank" rel="noopener noreferrer" href="https://github.com/user-attachments/assets/8107a9c4-2d7b-4b09-aedb-3a8074f2b3b7"><img width="447" height="227" alt="image" src="https://github.com/user-attachments/assets/8107a9c4-2d7b-4b09-aedb-3a8074f2b3b7" style="max-width: 100%; height: auto; max-height: 227px;"></a></td>
416
+ <td>Which is equivalent to using native CSS</td>
417
+ </tr>
418
+ </tbody>
419
+ </table>
420
+
421
+ These rules are a bit scary and anti-pattern on their side, it easily can lead to a messy codebase as from what I described, + this duplication HTML / CSS which is usually a not too bad norm but here we're facing a new external tool/API.
422
+
423
+ ---
424
+
425
+ ### **3. Tailwind v.4, drop JavaScript for CSS-oriented - complex migration and conflictual thoughts**
426
+
427
+ The new and actual version of Tailwind is now **_extremely_** based on CSS approach rather than a layer to abstract it.
428
+
429
+ [Here](https://tailwindcss.com/docs/upgrade-guide#changes-from-v3) is the upgrade guide from v3 to v4. I tried to do it a few months ago and it was quite painful, couldn't make it work...
430
+
431
+ #### **What concrete changes?**
432
+
433
+ Along from many deprecated function / utilities etc. Tailwind now is leaning towards CSS-approach first (which wasn't really well received from the initial users as I understood)
434
+
435
+ - No more [JavaScript configuration](https://tailwindcss.com/docs/upgrade-guide#using-a-javascript-config-file) and extension / referencing using Javascript [https://tailwindcss.com/docs/upgrade-guide#theme-values-in-javascript](https://tailwindcss.com/docs/upgrade-guide#theme-values-in-javascript)
436
+ - No more need (or at least not advice and not practical) for any [external preprocessor like Sass, Less, or Stylus](https://tailwindcss.com/docs/compatibility#sass-less-and-stylus)
437
+
438
+ > We've removed this in v4 in hopes that people can use the CSS variables we generate directly instead, which is much simpler and will significantly reduce your bundle size.
439
+
440
+ In short: [https://tailwindcss.com/docs/upgrade-guide#using-the-theme-function](https://tailwindcss.com/docs/upgrade-guide#using-the-theme-function)
441
+
442
+ ```css
443
+ .my-class {
444
+ /* OLD */
445
+ /* background-color: theme(colors.red.500); */
446
+
447
+ /* New version */
448
+ background-color: var(--color-red-500);
449
+ }
450
+ ```
451
+
452
+ The theme is now written in pure CSS with `@theme` and is what I wanted to progressively do in the [admin-frontend theme file](https://github.com/reteach/reteach-app/pull/5547/files#diff-16d9ae670465c45d5046ee77b6b3a48825026d2791dcb695f7a6da3c7c485c04)
453
+
454
+ <details>
455
+ <summary>Quick sample of the Tailwind 4 @theme</summary>
456
+ test
457
+
458
+ ```css
459
+ @theme {
460
+ --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
461
+ 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
462
+ --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
463
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
464
+ 'Liberation Mono', 'Courier New', monospace;
465
+ --color-red-50: oklch(97.1% 0.013 17.38);
466
+ --color-red-100: oklch(93.6% 0.032 17.717);
467
+ --color-red-200: oklch(88.5% 0.062 18.334);
468
+ --color-red-300: oklch(80.8% 0.114 19.571);
469
+ --color-red-400: oklch(70.4% 0.191 22.216);
470
+ --color-red-500: oklch(63.7% 0.237 25.331);
471
+ --color-red-600: oklch(57.7% 0.245 27.325);
472
+ --color-lime-200: oklch(93.8% 0.127 124.321);
473
+ --color-lime-300: oklch(89.7% 0.196 126.665);
474
+ --color-lime-400: oklch(84.1% 0.238 128.85);
475
+ --color-lime-500: oklch(76.8% 0.233 130.85);
476
+ --color-lime-600: oklch(64.8% 0.2 131.684);
477
+ --color-lime-700: oklch(53.2% 0.157 131.589);
478
+ --color-lime-800: oklch(45.3% 0.124 130.933);
479
+ --color-lime-900: oklch(40.5% 0.101 131.063);
480
+ --color-lime-950: oklch(27.4% 0.072 132.109);
481
+ --color-green-50: oklch(98.2% 0.018 155.826);
482
+ --color-green-100: oklch(96.2% 0.044 156.743);
483
+ --color-green-200: oklch(92.5% 0.084 155.995);
484
+ --color-green-300: oklch(87.1% 0.15 154.449);
485
+ --color-green-400: oklch(79.2% 0.209 151.711);
486
+ --color-green-500: oklch(72.3% 0.219 149.579);
487
+ --color-green-600: oklch(62.7% 0.194 149.214);
488
+ --color-green-700: oklch(52.7% 0.154 150.069);
489
+ --color-green-800: oklch(44.8% 0.119 151.328);
490
+ --color-green-900: oklch(39.3% 0.095 152.535);
491
+ --color-green-950: oklch(26.6% 0.065 152.934);
492
+ --color-emerald-50: oklch(97.9% 0.021 166.113);
493
+ --color-emerald-100: oklch(95% 0.052 163.051);
494
+ --color-emerald-200: oklch(90.5% 0.093 164.15);
495
+ --color-emerald-300: oklch(84.5% 0.143 164.978);
496
+ --color-emerald-400: oklch(76.5% 0.177 163.223);
497
+ --color-emerald-500: oklch(69.6% 0.17 162.48);
498
+ --color-emerald-600: oklch(59.6% 0.145 163.225);
499
+ --color-emerald-700: oklch(50.8% 0.118 165.612);
500
+ --color-emerald-800: oklch(43.2% 0.095 166.913);
501
+ --color-emerald-900: oklch(37.8% 0.077 168.94);
502
+ --color-emerald-950: oklch(26.2% 0.051 172.552);
503
+ --color-teal-50: oklch(98.4% 0.014 180.72);
504
+ --color-teal-100: oklch(95.3% 0.051 180.801);
505
+ --color-teal-200: oklch(91% 0.096 180.426);
506
+ --color-teal-300: oklch(85.5% 0.138 181.071);
507
+ --color-teal-400: oklch(77.7% 0.152 181.912);
508
+ --color-teal-500: oklch(70.4% 0.14 182.503);
509
+ --color-teal-600: oklch(60% 0.118 184.704);
510
+ --color-teal-700: oklch(51.1% 0.096 186.391);
511
+ --color-teal-800: oklch(43.7% 0.078 188.216);
512
+ --color-teal-900: oklch(38.6% 0.063 188.416);
513
+ --color-teal-950: oklch(27.7% 0.046 192.524);
514
+ --color-cyan-50: oklch(98.4% 0.019 200.873);
515
+ --color-cyan-100: oklch(95.6% 0.045 203.388);
516
+ --color-cyan-200: oklch(91.7% 0.08 205.041);
517
+ --color-cyan-300: oklch(86.5% 0.127 207.078);
518
+ --color-cyan-400: oklch(78.9% 0.154 211.53);
519
+ --color-cyan-500: oklch(71.5% 0.143 215.221);
520
+ --color-cyan-600: oklch(60.9% 0.126 221.723);
521
+ --color-cyan-700: oklch(52% 0.105 223.128);
522
+ --color-cyan-800: oklch(45% 0.085 224.283);
523
+ --color-cyan-900: oklch(39.8% 0.07 227.392);
524
+ --color-cyan-950: oklch(30.2% 0.056 229.695);
525
+ --color-sky-50: oklch(97.7% 0.013 236.62);
526
+ --color-sky-100: oklch(95.1% 0.026 236.824);
527
+ --color-sky-200: oklch(90.1% 0.058 230.902);
528
+ --color-sky-300: oklch(82.8% 0.111 230.318);
529
+ --color-sky-400: oklch(74.6% 0.16 232.661);
530
+ --color-sky-500: oklch(68.5% 0.169 237.323);
531
+ --color-sky-600: oklch(58.8% 0.158 241.966);
532
+ --color-sky-700: oklch(50% 0.134 242.749);
533
+ --color-sky-800: oklch(44.3% 0.11 240.79);
534
+ --color-sky-900: oklch(39.1% 0.09 240.876);
535
+ --color-sky-950: oklch(29.3% 0.066 243.157);
536
+ --color-blue-50: oklch(97% 0.014 254.604);
537
+ --color-blue-100: oklch(93.2% 0.032 255.585);
538
+ --color-blue-200: oklch(88.2% 0.059 254.128);
539
+ --color-blue-300: oklch(80.9% 0.105 251.813);
540
+ --color-blue-400: oklch(70.7% 0.165 254.624);
541
+ --color-blue-500: oklch(62.3% 0.214 259.815);
542
+ --color-blue-600: oklch(54.6% 0.245 262.881);
543
+ --color-blue-700: oklch(48.8% 0.243 264.376);
544
+ --color-blue-800: oklch(42.4% 0.199 265.638);
545
+ --color-blue-900: oklch(37.9% 0.146 265.522);
546
+ --color-blue-950: oklch(28.2% 0.091 267.935);
547
+ --color-indigo-50: oklch(96.2% 0.018 272.314);
548
+ --color-indigo-100: oklch(93% 0.034 272.788);
549
+ --color-indigo-200: oklch(87% 0.065 274.039);
550
+ --color-indigo-300: oklch(78.5% 0.115 274.713);
551
+ --color-indigo-400: oklch(67.3% 0.182 276.935);
552
+ --color-indigo-500: oklch(58.5% 0.233 277.117);
553
+ --color-indigo-600: oklch(51.1% 0.262 276.966);
554
+ --color-indigo-700: oklch(45.7% 0.24 277.023);
555
+ --color-indigo-800: oklch(39.8% 0.195 277.366);
556
+ --color-indigo-900: oklch(35.9% 0.144 278.697);
557
+ --color-indigo-950: oklch(25.7% 0.09 281.288);
558
+ --color-violet-50: oklch(96.9% 0.016 293.756);
559
+ --color-violet-100: oklch(94.3% 0.029 294.588);
560
+ --color-violet-200: oklch(89.4% 0.057 293.283);
561
+ --color-violet-300: oklch(81.1% 0.111 293.571);
562
+ --color-violet-400: oklch(70.2% 0.183 293.541);
563
+ --color-violet-500: oklch(60.6% 0.25 292.717);
564
+ --color-violet-600: oklch(54.1% 0.281 293.009);
565
+ --color-violet-700: oklch(49.1% 0.27 292.581);
566
+ --color-violet-800: oklch(43.2% 0.232 292.759);
567
+ --color-violet-900: oklch(38% 0.189 293.745);
568
+ --color-violet-950: oklch(28.3% 0.141 291.089);
569
+ --color-purple-50: oklch(97.7% 0.014 308.299);
570
+ --color-purple-100: oklch(94.6% 0.033 307.174);
571
+ --color-purple-200: oklch(90.2% 0.063 306.703);
572
+ --color-purple-300: oklch(82.7% 0.119 306.383);
573
+ --color-purple-400: oklch(71.4% 0.203 305.504);
574
+ --color-purple-500: oklch(62.7% 0.265 303.9);
575
+ --color-purple-600: oklch(55.8% 0.288 302.321);
576
+ --color-purple-700: oklch(49.6% 0.265 301.924);
577
+ --color-purple-800: oklch(43.8% 0.218 303.724);
578
+ --color-purple-900: oklch(38.1% 0.176 304.987);
579
+ --color-purple-950: oklch(29.1% 0.149 302.717);
580
+ --color-fuchsia-50: oklch(97.7% 0.017 320.058);
581
+ --color-fuchsia-100: oklch(95.2% 0.037 318.852);
582
+ --color-fuchsia-200: oklch(90.3% 0.076 319.62);
583
+ --color-fuchsia-300: oklch(83.3% 0.145 321.434);
584
+ --color-fuchsia-400: oklch(74% 0.238 322.16);
585
+ --color-fuchsia-500: oklch(66.7% 0.295 322.15);
586
+ --color-fuchsia-600: oklch(59.1% 0.293 322.896);
587
+ --color-fuchsia-700: oklch(51.8% 0.253 323.949);
588
+ --color-fuchsia-800: oklch(45.2% 0.211 324.591);
589
+ --color-fuchsia-900: oklch(40.1% 0.17 325.612);
590
+ --color-fuchsia-950: oklch(29.3% 0.136 325.661);
591
+ --color-pink-50: oklch(97.1% 0.014 343.198);
592
+ --color-pink-100: oklch(94.8% 0.028 342.258);
593
+ --color-pink-200: oklch(89.9% 0.061 343.231);
594
+ --color-pink-300: oklch(82.3% 0.12 346.018);
595
+ --color-pink-400: oklch(71.8% 0.202 349.761);
596
+ --color-pink-500: oklch(65.6% 0.241 354.308);
597
+ --color-pink-600: oklch(59.2% 0.249 0.584);
598
+ --color-pink-700: oklch(52.5% 0.223 3.958);
599
+ --color-pink-800: oklch(45.9% 0.187 3.815);
600
+ --color-pink-900: oklch(40.8% 0.153 2.432);
601
+ --color-pink-950: oklch(28.4% 0.109 3.907);
602
+ --color-rose-50: oklch(96.9% 0.015 12.422);
603
+ --color-rose-100: oklch(94.1% 0.03 12.58);
604
+ --color-rose-200: oklch(89.2% 0.058 10.001);
605
+ --color-rose-300: oklch(81% 0.117 11.638);
606
+ --color-rose-400: oklch(71.2% 0.194 13.428);
607
+ --color-rose-500: oklch(64.5% 0.246 16.439);
608
+ --color-rose-600: oklch(58.6% 0.253 17.585);
609
+ --color-rose-700: oklch(51.4% 0.222 16.935);
610
+ --color-rose-800: oklch(45.5% 0.188 13.697);
611
+ --color-rose-900: oklch(41% 0.159 10.272);
612
+ --color-rose-950: oklch(27.1% 0.105 12.094);
613
+ --color-slate-50: oklch(98.4% 0.003 247.858);
614
+ --color-slate-100: oklch(96.8% 0.007 247.896);
615
+ --color-slate-200: oklch(92.9% 0.013 255.508);
616
+ --color-slate-300: oklch(86.9% 0.022 252.894);
617
+ --color-slate-400: oklch(70.4% 0.04 256.788);
618
+ --color-slate-500: oklch(55.4% 0.046 257.417);
619
+ --color-slate-600: oklch(44.6% 0.043 257.281);
620
+ --color-slate-700: oklch(37.2% 0.044 257.287);
621
+ --color-slate-800: oklch(27.9% 0.041 260.031);
622
+ --color-slate-900: oklch(20.8% 0.042 265.755);
623
+ --color-slate-950: oklch(12.9% 0.042 264.695);
624
+ --color-gray-50: oklch(98.5% 0.002 247.839);
625
+ --color-gray-100: oklch(96.7% 0.003 264.542);
626
+ --color-gray-200: oklch(92.8% 0.006 264.531);
627
+ --color-gray-300: oklch(87.2% 0.01 258.338);
628
+ --color-gray-400: oklch(70.7% 0.022 261.325);
629
+ --color-gray-500: oklch(55.1% 0.027 264.364);
630
+ --color-gray-600: oklch(44.6% 0.03 256.802);
631
+ --color-gray-700: oklch(37.3% 0.034 259.733);
632
+ --color-gray-800: oklch(27.8% 0.033 256.848);
633
+ --color-gray-900: oklch(21% 0.034 264.665);
634
+ --color-gray-950: oklch(13% 0.028 261.692);
635
+ --color-zinc-50: oklch(98.5% 0 0);
636
+ --color-zinc-100: oklch(96.7% 0.001 286.375);
637
+ --color-zinc-200: oklch(92% 0.004 286.32);
638
+ --color-zinc-300: oklch(87.1% 0.006 286.286);
639
+ --color-zinc-400: oklch(70.5% 0.015 286.067);
640
+ --color-zinc-500: oklch(55.2% 0.016 285.938);
641
+ --color-zinc-600: oklch(44.2% 0.017 285.786);
642
+ --color-zinc-700: oklch(37% 0.013 285.805);
643
+ --color-zinc-800: oklch(27.4% 0.006 286.033);
644
+ --color-zinc-900: oklch(21% 0.006 285.885);
645
+ --color-zinc-950: oklch(14.1% 0.005 285.823);
646
+ --color-neutral-50: oklch(98.5% 0 0);
647
+ --color-neutral-100: oklch(97% 0 0);
648
+ --color-neutral-200: oklch(92.2% 0 0);
649
+ --color-neutral-300: oklch(87% 0 0);
650
+ --color-neutral-400: oklch(70.8% 0 0);
651
+ --color-neutral-500: oklch(55.6% 0 0);
652
+ --color-neutral-600: oklch(43.9% 0 0);
653
+ --color-neutral-700: oklch(37.1% 0 0);
654
+ --color-neutral-800: oklch(26.9% 0 0);
655
+ --color-neutral-900: oklch(20.5% 0 0);
656
+ --color-neutral-950: oklch(14.5% 0 0);
657
+ --color-stone-50: oklch(98.5% 0.001 106.423);
658
+ --color-stone-100: oklch(97% 0.001 106.424);
659
+ --color-stone-200: oklch(92.3% 0.003 48.717);
660
+ --color-stone-300: oklch(86.9% 0.005 56.366);
661
+ --color-stone-400: oklch(70.9% 0.01 56.259);
662
+ --color-stone-500: oklch(55.3% 0.013 58.071);
663
+ --color-stone-600: oklch(44.4% 0.011 73.639);
664
+ --color-stone-700: oklch(37.4% 0.01 67.558);
665
+ --color-stone-800: oklch(26.8% 0.007 34.298);
666
+ --color-stone-900: oklch(21.6% 0.006 56.043);
667
+ --color-stone-950: oklch(14.7% 0.004 49.25);
668
+ --color-black: #000;
669
+ --color-white: #fff;
670
+ --spacing: 0.25rem;
671
+ --breakpoint-sm: 40rem;
672
+ --breakpoint-md: 48rem;
673
+ --breakpoint-lg: 64rem;
674
+ --breakpoint-xl: 80rem;
675
+ --breakpoint-2xl: 96rem;
676
+ --container-3xs: 16rem;
677
+ --container-2xs: 18rem;
678
+ --container-xs: 20rem;
679
+ --container-sm: 24rem;
680
+ --container-md: 28rem;
681
+ --container-lg: 32rem;
682
+ --container-xl: 36rem;
683
+ --container-2xl: 42rem;
684
+ --container-3xl: 48rem;
685
+ --container-4xl: 56rem;
686
+ --container-5xl: 64rem;
687
+ --container-6xl: 72rem;
688
+ --container-7xl: 80rem;
689
+ --text-xs: 0.75rem;
690
+ --text-xs--line-height: calc(1 / 0.75);
691
+ --text-sm: 0.875rem;
692
+ --text-sm--line-height: calc(1.25 / 0.875);
693
+ --text-base: 1rem;
694
+ --text-base--line-height: calc(1.5 / 1);
695
+ --text-lg: 1.125rem;
696
+ --text-lg--line-height: calc(1.75 / 1.125);
697
+ --text-xl: 1.25rem;
698
+ --text-xl--line-height: calc(1.75 / 1.25);
699
+ --text-2xl: 1.5rem;
700
+ --text-2xl--line-height: calc(2 / 1.5);
701
+ --text-3xl: 1.875rem;
702
+ --text-3xl--line-height: calc(2.25 / 1.875);
703
+ --text-4xl: 2.25rem;
704
+ --text-4xl--line-height: calc(2.5 / 2.25);
705
+ }
706
+ ```
707
+
708
+ </details>
709
+
710
+ ## (Short) Conclusion
711
+
712
+ I kind of feel that Tailwind came to propose a solution to the problem of CSS duplication but by going too far. They used an aggressive marketing to "break the rules" but if there's existing directions and conventions in softwares engineering, it's for a reason 😶.
713
+ I understand the appeal and purpose when you don't like CSS and feel quick with it.
714
+
715
+ - 👎 Tailwind does not resolve the separation of concerns issue initially targeted as they created an API on top of CSS used directly in HTML
716
+ - By their lack of support of many features, they invented to encapsulate logic into single semantic styled objects - looking close to CSS classes but by keeping this "risky" additional syntax
717
+ - It's interesting to see years later they now promote pure CSS-approach as it's "easier" while being not so intuitive and the quite opposite syntax to write tokens from the one they started from
718
+ I'm more a client for V4 though
719
+
720
+ --generated-by-arthur-remis-Claude