dynamic-ds 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.
@@ -0,0 +1,396 @@
1
+ @use "sass:math";
2
+
3
+ // ============================================================================
4
+ // 1. DEFAULT COLORS
5
+ // ============================================================================
6
+ $brand-color-default: #2740B4;
7
+ $primary-color-default: #006BDF;
8
+ $secondary-color-default: #9F5100;
9
+ $neutral-color-default: #505A5F;
10
+ $functional-color-default: #006BDF;
11
+ $utility-color-default: #CF0026;
12
+ $text-color-default: #344054;
13
+ $disable-bg-default: #F9FAFB;
14
+ $disable-text-default: #667085;
15
+
16
+ // ============================================================================
17
+ // 2. RGB COLOR GENERATOR (REPLACED HSL)
18
+ // ============================================================================
19
+ // Hàm này sử dụng mix() để trộn màu với Trắng hoặc Đen
20
+ @function generate-shade($color, $weight) {
21
+ @if $weight > 0 {
22
+ // Weight dương -> Trộn với Trắng (Làm sáng)
23
+ @return mix(#ffffff, $color, $weight);
24
+ } @else if $weight < 0 {
25
+ // Weight âm -> Trộn với Đen (Làm tối)
26
+ // 2. Sử dụng math.abs() thay vì abs() toàn cục
27
+ @return mix(#000000, $color, math.abs($weight));
28
+ } @else {
29
+ @return $color;
30
+ }
31
+ }
32
+
33
+ // Cập nhật lại offsets để phù hợp với logic mix()
34
+ // Giá trị biểu thị % màu trắng hoặc đen được trộn vào
35
+ $shade-offsets: (
36
+ // Dải màu tối (Pha Đen) - Tính toán từ Base #505A5F
37
+ "900": -73.5%, // Hex đích: #161819
38
+ "875": -62.5%, // Hex đích: #1E2225
39
+ "850": -47.0%, // Hex đích: #2A3034
40
+ "800": -34.5%, // Hex đích: #343D41
41
+ "700": -18.5%, // Hex đích: #41494E
42
+ "600": 0%, // BASE: #505A5F
43
+
44
+ // Dải màu sáng (Pha Trắng) - Tính toán từ Base #505A5F
45
+ "500": 17.5%, // Hex đích: #69757C
46
+ "400": 33.0%, // Hex đích: #828F96
47
+ "300": 53.0%, // Hex đích: #A3AEB5
48
+ "200": 72.0%, // Hex đích: #C5CDD2
49
+ "100": 85.0%, // Hex đích: #DEE3E7
50
+ "50": 89.5%, // Hex đích: #E9EDF1
51
+ "25": 93.5%, // Hex đích: #F1F4F6
52
+ "10": 97.0% // Hex đích: #F8F9FB
53
+ );
54
+
55
+ // ============================================================================
56
+ // 3. CSS CUSTOM PROPERTIES
57
+ // ============================================================================
58
+ :root {
59
+ --neutral-color: #{$neutral-color-default};
60
+
61
+ $palettes: (
62
+ "brand": $brand-color-default,
63
+ "primary": $primary-color-default,
64
+ "secondary": $secondary-color-default,
65
+ "functional": $functional-color-default,
66
+ "utility": $utility-color-default
67
+ );
68
+
69
+ @each $name, $base-color in $palettes {
70
+ --#{$name}-color: #{$base-color};
71
+ --#{$name}-color-rgb: #{red($base-color)}, #{green($base-color)}, #{blue($base-color)};
72
+
73
+ @each $shade, $offset in $shade-offsets {
74
+ $shade-color: generate-shade($base-color, $offset);
75
+ --#{$name}-#{$shade}: #{$shade-color};
76
+ --#{$name}-#{$shade}-rgb: #{red($shade-color)}, #{green($shade-color)}, #{blue($shade-color)};
77
+ }
78
+ }
79
+ }
80
+
81
+ // ============================================================================
82
+ // BADGE THEME PALETTES (exposed as CSS custom properties)
83
+ // ============================================================================
84
+ $badge-theme-bases: (
85
+ "neutral": #505A5F,
86
+ "neutral-light": #8B9399,
87
+ "red": #CF0026,
88
+ "orange": #B93600,
89
+ "yellow": #995500,
90
+ "lime": #2E7600,
91
+ "green": #008345,
92
+ "ocean": #008692,
93
+ "blue": #007DD7,
94
+ "indigo": #2461E2,
95
+ "violet": #9D3ABB,
96
+ "pink": #BC1D92
97
+ );
98
+
99
+ :root {
100
+ @each $name, $base-color in $badge-theme-bases {
101
+ --theme-#{$name}-color: #{$base-color};
102
+ --theme-#{$name}-color-rgb: #{red($base-color)}, #{green($base-color)}, #{blue($base-color)};
103
+
104
+ @each $shade, $offset in $shade-offsets {
105
+ $shade-color: generate-shade($base-color, $offset);
106
+ --theme-#{$name}-#{$shade}: #{$shade-color};
107
+ --theme-#{$name}-#{$shade}-rgb: #{red($shade-color)}, #{green($shade-color)}, #{blue($shade-color)};
108
+ }
109
+ }
110
+ }
111
+
112
+ $theme-types: ('red', 'orange', 'yellow', 'lime', 'green', 'ocean', 'blue', 'indigo', 'violet', 'pink');
113
+ @each $type in $theme-types {
114
+ // Backgrounds
115
+ .bg-#{$type}-canvas { background-color: var(--theme-#{$type}-10) !important; }
116
+ .bg-#{$type}-soft { background-color: var(--theme-#{$type}-25) !important; }
117
+ .bg-#{$type}-sub { background-color: var(--theme-#{$type}-50) !important; }
118
+ .bg-#{$type}-accent { background-color: var(--theme-#{$type}-600) !important; }
119
+
120
+ // Texts
121
+ .text-#{$type}-soft { color: var(--theme-#{$type}-400) !important; }
122
+ .text-#{$type}-sub { color: var(--theme-#{$type}-700) !important; }
123
+ .text-#{$type}-strong { color: var(--theme-#{$type}-850) !important; }
124
+ .text-#{$type}-white { color: #FFFFFF !important; }
125
+
126
+ // Strokes
127
+ .stroke-#{$type}-soft { border-color: var(--theme-#{$type}-50) !important; }
128
+ .stroke-#{$type}-sub { border-color: var(--theme-#{$type}-100) !important; }
129
+ .stroke-#{$type}-strong { border-color: var(--theme-#{$type}-500) !important; }
130
+ .stroke-#{$type}-strong-alpha { border-color: rgba(var(--theme-#{$type}-500-rgb), 0.5) !important; }
131
+
132
+ // Icons
133
+ .icon-#{$type}-soft { fill: var(--theme--#{$type}-300) !important; }
134
+ .icon-#{$type}-sub { fill: var(--theme-#{$type}-600) !important; }
135
+ .icon-#{$type}-strong { fill: var(--theme-#{$type}-800) !important; }
136
+ .icon-#{$type}-white { fill: #FFFFFF !important; }
137
+ }
138
+
139
+ // ============================================================================
140
+ // 4. NEUTRAL PALETTE (Static SCSS - RGB Mix)
141
+ // ============================================================================
142
+ $neutral-B: #000000;
143
+ $neutral-W: #FFFFFF;
144
+
145
+ $neutral-shades: (
146
+ "black": $neutral-B,
147
+ "white": $neutral-W,
148
+ "900": #161819,
149
+ "875": #1E2225,
150
+ "850": #2A3034,
151
+ "800": #343D41,
152
+ "700": #41494E,
153
+ "600": $neutral-color-default,
154
+ "500": #69757C,
155
+ "400": #828F96,
156
+ "300": #A3AEB5,
157
+ "200": #C5CDD2,
158
+ "100": #DEE3E7,
159
+ "50": #E9EDF1,
160
+ "25": #F1F4F6,
161
+ "10": #F8F9FB
162
+ );
163
+
164
+ :root {
165
+ --neutral-color-900: #{map-get($neutral-shades, "900")};
166
+ --neutral-color-875: #{map-get($neutral-shades, "875")};
167
+ --neutral-color-850: #{map-get($neutral-shades, "850")};
168
+ --neutral-color-800: #{map-get($neutral-shades, "800")};
169
+ --neutral-color-700: #{map-get($neutral-shades, "700")};
170
+ --neutral-color-600: #{map-get($neutral-shades, "600")};
171
+ --neutral-color-500: #{map-get($neutral-shades, "500")};
172
+ --neutral-color-400: #{map-get($neutral-shades, "400")};
173
+ --neutral-color-300: #{map-get($neutral-shades, "300")};
174
+ --neutral-color-200: #{map-get($neutral-shades, "200")};
175
+ --neutral-color-100: #{map-get($neutral-shades, "100")};
176
+ --neutral-color-50: #{map-get($neutral-shades, "50")};
177
+ --neutral-color-25: #{map-get($neutral-shades, "25")};
178
+ --neutral-color-10: #{map-get($neutral-shades, "10")};
179
+ }
180
+
181
+ // Helper function để thay thế logic lighten/darken cũ
182
+ @function safe-lighten($color, $percent) {
183
+ @return mix(#ffffff, $color, $percent);
184
+ }
185
+ @function safe-darken($color, $percent) {
186
+ @return mix(#000000, $color, $percent);
187
+ }
188
+
189
+ // ============================================================================
190
+ // 5. SEMANTIC UTILITY CLASSES
191
+ // ============================================================================
192
+
193
+ // --- NEUTRAL SEMANTIC ---
194
+ .bg-neutral-disable { background-color: #FFFFFF !important; }
195
+ .bg-neutral-canvas { background-color: #FFFFFF !important; }
196
+ .bg-neutral-soft { background-color: #F8F9FB !important; }
197
+ .bg-neutral-sub { background-color: #E9EDF1 !important; }
198
+ .bg-neutral-accent { background-color: #E9EDF1 !important; }
199
+
200
+ .text-neutral-disable { color: #C5CDD2 !important; }
201
+ .text-neutral-soft { color: #828F96 !important; }
202
+ .text-neutral-sub { color: #505A5F !important; }
203
+ .text-neutral-strong { color: #1E2225 !important; }
204
+
205
+ .stroke-neutral-disable { border-color: rgba(2, 48, 94, 0.09) !important; } // #02305E 8.7%
206
+ .stroke-neutral-soft { border-color: rgba(10, 47, 77, 0.14) !important; } // #0A2F4D 13.5%
207
+ .stroke-neutral-sub { border-color: rgba(13, 46, 67, 0.24) !important; } // #0D2E43 24%
208
+ .stroke-neutral-strong { border-color: rgba(0, 21, 32, 0.59) !important; } // #001520 59%
209
+
210
+ .icon-neutral-disable { fill: #C5CDD2 !important; }
211
+ .icon-neutral-soft { fill: #A3AEB5 !important; }
212
+ .icon-neutral-sub { fill: #505A5F !important; }
213
+ .icon-neutral-strong { fill: #343D41 !important; }
214
+
215
+ // --- DYNAMIC SEMANTIC (Brand, Functional, Utility) ---
216
+ $semantic-types: ("brand", "functional", "utility");
217
+
218
+ .bg-default {
219
+ background-color: #F2F5FF !important;
220
+ }
221
+
222
+ @each $type in $semantic-types {
223
+ // Backgrounds
224
+ .bg-#{$type}-canvas { background-color: var(--#{$type}-10) !important; }
225
+ .bg-#{$type}-soft { background-color: var(--#{$type}-25) !important; }
226
+ .bg-#{$type}-sub { background-color: var(--#{$type}-50) !important; }
227
+ .bg-#{$type}-accent { background-color: var(--#{$type}-600) !important; }
228
+ @if $type != "brand" { .bg-#{$type}-disable { background-color: var(--#{$type}-10) !important; } }
229
+
230
+ // Texts
231
+ .text-#{$type}-soft { color: var(--#{$type}-400) !important; }
232
+ .text-#{$type}-sub { color: var(--#{$type}-700) !important; }
233
+ .text-#{$type}-strong { color: var(--#{$type}-850) !important; }
234
+ .text-#{$type}-white { color: #FFFFFF !important; }
235
+ @if $type != "brand" { .text-#{$type}-disable { color: var(--#{$type}-200) !important; } }
236
+
237
+ // Strokes
238
+ .stroke-#{$type}-soft { border-color: var(--#{$type}-50) !important; }
239
+ .stroke-#{$type}-sub { border-color: var(--#{$type}-100) !important; }
240
+ .stroke-#{$type}-strong { border-color: var(--#{$type}-500) !important; }
241
+ .stroke-#{$type}-strong-alpha { border-color: rgba(var(--#{$type}-500-rgb), 0.5) !important; }
242
+
243
+ // Icons
244
+ .icon-#{$type}-soft { fill: var(--#{$type}-300) !important; }
245
+ .icon-#{$type}-sub { fill: var(--#{$type}-600) !important; }
246
+ .icon-#{$type}-strong { fill: var(--#{$type}-800) !important; }
247
+ .icon-#{$type}-white { fill: #FFFFFF !important; }
248
+ }
249
+
250
+ // ============================================================================
251
+ // 6. UTILITY CLASSES GENERATOR
252
+ // ============================================================================
253
+
254
+ // --- NEUTRAL CLASSES ---
255
+ .color-text-neutral-black { color: $neutral-B !important; }
256
+ .color-text-neutral-white { color: $neutral-W !important; }
257
+ @each $shade, $value in $neutral-shades {
258
+ .color-text-neutral-#{$shade} { color: $value !important; }
259
+ .color-bg-neutral-#{$shade} { background-color: $value !important; }
260
+ .color-stroke-neutral-#{$shade} { border-color: $value !important; }
261
+ .color-icon-neutral-#{$shade} { fill: $value !important; }
262
+ }
263
+
264
+ // ALPHA NEUTRAL STROKE CLASSES
265
+ $neutral-alphas: (90, 80, 70, 60, 50, 40, 30, 20, 10, 5);
266
+ @each $a in $neutral-alphas {
267
+ .color-stroke-neutral-alpha-#{$a} {
268
+ border-color: rgba(red($neutral-color-default), green($neutral-color-default), blue($neutral-color-default), $a * 0.01) !important;
269
+ }
270
+ }
271
+
272
+ // --- DYNAMIC CLASSES (Brand, Primary, Secondary) ---
273
+ $dynamic-types: ("brand", "primary", "secondary");
274
+
275
+ @each $type in $dynamic-types {
276
+ // Base Alias
277
+ .color-text-#{$type} { color: var(--#{$type}-color) !important; }
278
+ .color-bg-#{$type} { background-color: var(--#{$type}-color) !important; }
279
+ .color-stroke-#{$type} { border-color: var(--#{$type}-color) !important; }
280
+ .color-icon-#{$type} { fill: var(--#{$type}-color) !important; }
281
+
282
+ // Shades
283
+ @each $shade, $offset in $shade-offsets {
284
+ .color-text-#{$type}-#{$shade} { color: var(--#{$type}-#{$shade}) !important; }
285
+ .color-bg-#{$type}-#{$shade} { background-color: var(--#{$type}-#{$shade}) !important; }
286
+ .color-stroke-#{$type}-#{$shade} { border-color: var(--#{$type}-#{$shade}) !important; }
287
+
288
+ @if $shade == "700" or $shade == "300" {
289
+ .color-icon-#{$type}-#{$shade} { fill: var(--#{$type}-#{$shade}) !important; }
290
+ }
291
+ }
292
+
293
+ // Alpha backgrounds
294
+ $alphas: (90, 80, 70, 60, 50, 40, 30, 20, 10, 5);
295
+ @each $a in $alphas {
296
+ .color-bg-#{$type}-alpha-#{$a} {
297
+ background-color: rgba(var(--#{$type}-color-rgb), $a * 0.01) !important;
298
+ }
299
+ }
300
+
301
+ // Alpha strokes
302
+ @each $a in $alphas {
303
+ .color-stroke-#{$type}-alpha-#{$a} {
304
+ border-color: rgba(var(--#{$type}-color-rgb), $a * 0.01) !important;
305
+ }
306
+ }
307
+ }
308
+
309
+ // ============================================================================
310
+ // 7. UTILITY MIXINS
311
+ // ============================================================================
312
+ @mixin text-neutral($shade) {
313
+ @if $shade == 'B' { color: $neutral-B !important; }
314
+ @else if $shade == 'W' { color: $neutral-W !important; }
315
+ @else { color: map-get($neutral-shades, $shade) !important; }
316
+ }
317
+
318
+ @mixin bg-neutral($shade) {
319
+ @if $shade == 'B' { background-color: $neutral-B !important; }
320
+ @else if $shade == 'W' { background-color: $neutral-W !important; }
321
+ @else { background-color: map-get($neutral-shades, $shade) !important; }
322
+ }
323
+
324
+ // ============================================================================
325
+ // 8. SIZING & TYPOGRAPHY SYSTEM
326
+ // ============================================================================
327
+ $widths: (
328
+ "xxs": 16px,
329
+ "xs": 24px,
330
+ "sm": 28px,
331
+ "md": 36px,
332
+ "lg": 44px
333
+ );
334
+
335
+ $heights: (
336
+ "xxs": 16px,
337
+ "xs": 24px,
338
+ "sm": 28px,
339
+ "md": 36px,
340
+ "lg": 44px
341
+ );
342
+
343
+ $font-sizes: (
344
+ "xs": 12px,
345
+ "sm": 14px,
346
+ "md": 14px,
347
+ "lg": 16px,
348
+ "xl": 20px
349
+ );
350
+
351
+ $radius: (
352
+ "xs": 4px,
353
+ "sm": 6px,
354
+ "md": 8px,
355
+ "lg": 12px,
356
+ "full": 999px
357
+ );
358
+
359
+ :root {
360
+ --radius-md: #{map-get($radius, "md")};
361
+ --font-xs: #{map-get($font-sizes, "xs")};
362
+ --font-sm: #{map-get($font-sizes, "sm")};
363
+ }
364
+
365
+ // --- Helper Classes cho Sizing ---
366
+ @each $name, $val in $heights {
367
+ .h-#{$name} { height: $val !important; }
368
+ }
369
+
370
+ @each $name, $val in $widths {
371
+ .w-#{$name} { width: $val !important; }
372
+ }
373
+
374
+ @each $name, $val in $font-sizes {
375
+ .text-#{$name} { font-size: $val !important; }
376
+ }
377
+
378
+ @each $name, $val in $radius {
379
+ .rounded-#{$name} { border-radius: $val !important; }
380
+ }
381
+
382
+ // ============================================================================
383
+ // 9. COLOR EXCEPTIONS OF FIGMA
384
+ // ============================================================================
385
+
386
+ .bg-default-gray {
387
+ background-color: #344054 !important;
388
+ }
389
+
390
+ .text-default-gray {
391
+ color: #344054 !important;
392
+ }
393
+
394
+ .rounded-default-gray {
395
+ border-color: #344054 !important;
396
+ }