1 | # @zaydek/duomo
|
2 |
|
3 | Duomo is a stack-based CSS framework. Contributions are welcome as issues and or pull requests.
|
4 |
|
5 | To get started, simply run this command:
|
6 |
|
7 | ```bash
|
8 | yarn add @zaydek/duomo
|
9 | # or npm i @zaydek/duomo
|
10 | ```
|
11 |
|
12 | **Usage: (CDN)**
|
13 |
|
14 | CodePen to get you started: https://codepen.io/zaydek/pen/ExgxjYy.
|
15 |
|
16 | ```html
|
17 | <!DOCTYPE html>
|
18 | <html lang="en">
|
19 | <head>
|
20 | <meta charset="UTF-8" />
|
21 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
22 | <title>Hello, world!</title>
|
23 | <link rel="stylesheet" href="https://unpkg.com/@zaydek/duomo" />
|
24 | </head>
|
25 | <body>
|
26 | <div class="hstack">
|
27 | <div class="hstack space-16">
|
28 | <div class="w-32 h-32 bg-gray-300 rounded-full"></div>
|
29 | <div class="w-32 h-32 bg-gray-300 rounded-full"></div>
|
30 | </div>
|
31 | <div class="spacer"></div>
|
32 | <div class="hstack space-16">
|
33 | <div class="w-32 h-32 bg-gray-300 rounded-full"></div>
|
34 | <div class="w-32 h-32 bg-gray-300 rounded-full"></div>
|
35 | </div>
|
36 | </div>
|
37 | </body>
|
38 | </html>
|
39 | ```
|
40 |
|
41 | **Usage (React):**
|
42 |
|
43 | ```tsx
|
44 | import "@zaydek/duomo"
|
45 |
|
46 | function Component() {
|
47 | return (
|
48 | <div className="hstack">
|
49 | <div className="hstack space-16">
|
50 | <div className="w-32 h-32 bg-gray-300 rounded-full" />
|
51 | <div className="w-32 h-32 bg-gray-300 rounded-full" />
|
52 | </div>
|
53 | <div className="spacer" />
|
54 | <div className="hstack space-16">
|
55 | <div className="w-32 h-32 bg-gray-300 rounded-full" />
|
56 | <div className="w-32 h-32 bg-gray-300 rounded-full" />
|
57 | </div>
|
58 | </div>
|
59 | )
|
60 | }
|
61 | ```
|
62 |
|
63 | ## Table of Contents:
|
64 |
|
65 | - [Why](#why)
|
66 | - [HStack](#hstack)
|
67 | - [VStack](#vstack)
|
68 | - [Spacer](#spacer)
|
69 | - [Spacing](#spacing)
|
70 | - [ZStack](#zstack)
|
71 | - [Range](#range)
|
72 |
|
73 | ## Why
|
74 |
|
75 | Duomo is a spiritual successor of Tailwind CSS.
|
76 |
|
77 | Duomo benefits you in the following ways:
|
78 |
|
79 | - Small and intuitive API
|
80 | - Small JavaScript runtime for toggling dark mode, etc.
|
81 | - Built in debugging layout utilities
|
82 | - Soft landing for iOS / SwiftUI developers
|
83 | - Uses HStack and VStack instead of Flexbox for rows and columns
|
84 | - Uses ZStack to layer along the z-axis
|
85 | - Lightweight CDN footprint (<TODO>kb uncompressed, <TODO>kb with Brotli); no NPM installs required
|
86 | - No configuration needed
|
87 | - Sass API; easily extend Duomo when you install via NPM
|
88 | - Introspection via CSS variables; Duomo tokens can be overridden _without_ Sass
|
89 | - Maintenance-friendly HTML / CSS
|
90 |
|
91 | Reasons you might not want to use Duomo:
|
92 |
|
93 | - You like Tailwind CSS just fine thank you very much
|
94 | - You don’t want to use stacks vs. Flexbox\* (_stacks are based on Flexbox_)
|
95 | - You don’t have a need for small CDN footprints
|
96 | - Duomo is not 1.0 stable
|
97 |
|
98 | \*Note that stacks are exported as a standalone dependency; you can experiment with stacks _with_ any CSS library.
|
99 |
|
100 | ## HStack
|
101 |
|
102 | HStacks `<div class="hstack">` stack children elements _horizontally_. Like `VStack`s, they can be modified with
|
103 | `align-{alignment}` and `space-{range}`. By default, children are automatically centered horizontally and vertically. To
|
104 | opt-out of horizontal centering, use a nested `<div class="spacer">`. To opt-out of vertical centering, use
|
105 | `align-stretch`, `align-start`, or `align-end`.
|
106 |
|
107 | **Spacer examples:**
|
108 |
|
109 | ```html
|
110 | <!--
|
111 | . . .
|
112 | . x .
|
113 | . . .
|
114 | -->
|
115 | <div class="hstack">
|
116 | <div class="x"></div>
|
117 | </div>
|
118 |
|
119 | <!--
|
120 | . . .
|
121 | . . x
|
122 | . . .
|
123 | -->
|
124 | <div class="hstack">
|
125 | <div class="spacer"></div>
|
126 | <div class="x"></div>
|
127 | </div>
|
128 |
|
129 | <!--
|
130 | . . .
|
131 | x . .
|
132 | . . .
|
133 | -->
|
134 | <div class="hstack">
|
135 | <div class="x"></div>
|
136 | <div class="spacer"></div>
|
137 | </div>
|
138 | ```
|
139 |
|
140 | **Alignment examples:**
|
141 |
|
142 | ```html
|
143 | <!--
|
144 | . x .
|
145 | . x .
|
146 | . x .
|
147 | -->
|
148 | <div class="hstack align-stretch">
|
149 | <div class="x"></div>
|
150 | </div>
|
151 |
|
152 | <!--
|
153 | . x .
|
154 | . . .
|
155 | . . .
|
156 | -->
|
157 | <div class="hstack align-start">
|
158 | <div class="x"></div>
|
159 | </div>
|
160 |
|
161 | <!--
|
162 | . . .
|
163 | . . .
|
164 | . x .
|
165 | -->
|
166 | <div class="hstack align-end">
|
167 | <div class="x"></div>
|
168 | </div>
|
169 | ```
|
170 |
|
171 | **Responsive examples:**
|
172 |
|
173 | Adapts to a vertical stack at the medium breakpoint.
|
174 |
|
175 | ```html
|
176 | <div class="hstack md:vstack">
|
177 | <!-- ... -->
|
178 | </div>
|
179 | ```
|
180 |
|
181 | Stack is revealed at the medium breakpoint.\*
|
182 |
|
183 | _\*Not yet implemented._
|
184 |
|
185 | ```html
|
186 | <div class="hidden md:vstack">
|
187 | <!-- ... -->
|
188 | </div>
|
189 | ```
|
190 |
|
191 | Stack is hidden at the medium breakpoint.\*
|
192 |
|
193 | _\*Not yet implemented._
|
194 |
|
195 | ```html
|
196 | <div class="hstack md:hidden">
|
197 | <!-- ... -->
|
198 | </div>
|
199 | ```
|
200 |
|
201 | ## VStack
|
202 |
|
203 | VStacks `<div class="vstack">` stack children elements _vertically_. Like `HStack`s, they can be modified with
|
204 | `align-{alignment}` and `space-{range}`. By default, children are automatically centered horizontally and vertically. To
|
205 | opt-out of horizontal centering, use a nested `<div class="spacer">`. To opt-out of horizontal centering, use
|
206 | `align-stretch`, `align-start`, or `align-end`.
|
207 |
|
208 | **Spacer examples:**
|
209 |
|
210 | ```html
|
211 | <!--
|
212 | . . .
|
213 | . x .
|
214 | . . .
|
215 | -->
|
216 | <div class="vstack">
|
217 | <div class="x"></div>
|
218 | </div>
|
219 |
|
220 | <!--
|
221 | . . .
|
222 | . . .
|
223 | . x .
|
224 | -->
|
225 | <div class="vstack">
|
226 | <div class="spacer"></div>
|
227 | <div class="x"></div>
|
228 | </div>
|
229 |
|
230 | <!--
|
231 | . x .
|
232 | . . .
|
233 | . . .
|
234 | -->
|
235 | <div class="vstack">
|
236 | <div class="x"></div>
|
237 | <div class="spacer"></div>
|
238 | </div>
|
239 | ```
|
240 |
|
241 | **Alignment examples:**
|
242 |
|
243 | ```html
|
244 | <!--
|
245 | . . .
|
246 | x x x
|
247 | . . .
|
248 | -->
|
249 | <div class="vstack align-stretch">
|
250 | <div class="x"></div>
|
251 | </div>
|
252 |
|
253 | <!--
|
254 | . . .
|
255 | x . .
|
256 | . . .
|
257 | -->
|
258 | <div class="vstack align-start">
|
259 | <div class="x"></div>
|
260 | </div>
|
261 |
|
262 | <!--
|
263 | . . .
|
264 | . . x
|
265 | . . .
|
266 | -->
|
267 | <div class="vstack align-end">
|
268 | <div class="x"></div>
|
269 | </div>
|
270 | ```
|
271 |
|
272 | **Responsive examples:**
|
273 |
|
274 | Adapts to a horizontal stack at the medium breakpoint.
|
275 |
|
276 | ```html
|
277 | <div class="vstack md:hstack">
|
278 | <!-- ... -->
|
279 | </div>
|
280 | ```
|
281 |
|
282 | Stack is revealed at the medium breakpoint.\*
|
283 |
|
284 | _\*Not yet implemented._
|
285 |
|
286 | ```html
|
287 | <div class="hidden md:vstack">
|
288 | <!-- ... -->
|
289 | </div>
|
290 | ```
|
291 |
|
292 | Stack is hidden at the medium breakpoint.\*
|
293 |
|
294 | _\*Not yet implemented._
|
295 |
|
296 | ```html
|
297 | <div class="vstack md:hidden">
|
298 | <!-- ... -->
|
299 | </div>
|
300 | ```
|
301 |
|
302 | ## Spacer
|
303 |
|
304 | Spacers `<div class="spacer">` create negative space between children elements. They can be used to simulate
|
305 | `justify-content: flex-start`, `justify-content: flex-end`, and `justify-content: space-evenly` declaratively.
|
306 |
|
307 | Spacers, unlike HStacks and VStacks, implement no modifiers.
|
308 |
|
309 | **Examples:**
|
310 |
|
311 | Simulates `justify-content: flex-start`.
|
312 |
|
313 | ```html
|
314 | <!--
|
315 | . . .
|
316 | . x x
|
317 | . . .
|
318 | -->
|
319 | <div class="hstack">
|
320 | <div class="spacer"></div>
|
321 | <div class="x"></div>
|
322 | <div class="x"></div>
|
323 | </div>
|
324 | ```
|
325 |
|
326 | Simulates `justify-content: flex-end`.
|
327 |
|
328 | ```html
|
329 | <!--
|
330 | . . .
|
331 | x x .
|
332 | . . .
|
333 | -->
|
334 | <div class="hstack">
|
335 | <div class="x"></div>
|
336 | <div class="x"></div>
|
337 | <div class="spacer"></div>
|
338 | </div>
|
339 | ```
|
340 |
|
341 | Simulates `justify-content: space-evenly`.
|
342 |
|
343 | ```html
|
344 | <!--
|
345 | . . . . .
|
346 | . x . x .
|
347 | . . . . .
|
348 | -->
|
349 | <div class="hstack">
|
350 | <div class="spacer"></div>
|
351 | <div class="x"></div>
|
352 | <div class="spacer"></div>
|
353 | <div class="x"></div>
|
354 | <div class="spacer"></div>
|
355 | </div>
|
356 | ```
|
357 |
|
358 | ## Spacing
|
359 |
|
360 | The spacing modifier `<div class="[h|v]stack space-{px}>` creates consistent spacing between HStack and VStack children
|
361 | elements. Spacing can be any negative\* or positive range value.
|
362 |
|
363 | Note that spacing spaces children elements _horizontally_ or _vertically_ depending on the parent HStack or VStack
|
364 | context. **You don’t need to specifiy x-axis or y-axis-specific spacing**.
|
365 |
|
366 | _\*Not yet implemented._
|
367 |
|
368 | **Examples:**
|
369 |
|
370 | ```html
|
371 | <div class="hstack space-8">
|
372 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
373 | <!-- 8px gap -->
|
374 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
375 | <!-- 8px gap -->
|
376 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
377 | <!-- 8px gap -->
|
378 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
379 | </div>
|
380 | ```
|
381 |
|
382 | ```html
|
383 | <div class="vstack space-16">
|
384 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
385 | <!-- 16px gap -->
|
386 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
387 | <!-- 16px gap -->
|
388 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
389 | <!-- 16px gap -->
|
390 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
391 | </div>
|
392 | ```
|
393 |
|
394 | **Responsive examples:**
|
395 |
|
396 | ```html
|
397 | <div class="hstack space-8 md:space-16">
|
398 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
399 | <!-- 8px gap, 16px gap at the medium breakpoint -->
|
400 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
401 | <!-- 8px gap, 16px gap at the medium breakpoint -->
|
402 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
403 | <!-- 8px gap, 16px gap at the medium breakpoint -->
|
404 | <div class="w-32 h-32 bg-gray-400 rounded-full"></div>
|
405 | </div>
|
406 | ```
|
407 |
|
408 | ## ZStack
|
409 |
|
410 | ZStacks `<div class="zstack">` stack children elements on the z-axis _and_ center children elements across the x- and y-
|
411 | axes. ZStacks make layering elements on top of one another easy. ZStacks are intended to be used _with_ HStacks and or
|
412 | VStacks; they simply layer and center children elements.
|
413 |
|
414 | ZStacks, unlike HStacks and VStacks, implement no modifiers.
|
415 |
|
416 | Note that ZStacks use `position: relative`, so children element that use `position: absolute` are bound to the parent
|
417 | ZStack bounding box.
|
418 |
|
419 | **Examples:**
|
420 |
|
421 | TODO
|
422 |
|
423 |
|
424 |
|
425 | Layers a red, green, and blue element on top of each other. The blue element is visible. The red and green elements are obscured.
|
426 |
|
427 | ```html
|
428 | <div class="zstack">
|
429 | <div class="hstack w-32 h-32 bg-red-400 rounded-full"></div>
|
430 | <div class="hstack w-32 h-32 bg-green-400 rounded-full"></div>
|
431 | <div class="hstack w-32 h-32 bg-blue-400 rounded-full"></div>
|
432 | </div>
|
433 | ```
|
434 |
|
435 | -->
|
436 |
|
437 | ## Range
|
438 |
|
439 | The standard range describes legal range values. Some properties support negative ranges (`margin`) and some properties
|
440 | use a sub-range (`border`, etc.).
|
441 |
|
442 | **The standard range:**
|
443 |
|
444 | ```
|
445 | 0-10 increments by 1 -> 0 1 2 3 4 5 6 7 8 9
|
446 | 10-20 increments by 2 -> 10 12 14 16 18
|
447 | 20-40 increments by 4 -> 20 24 28 32 36
|
448 | 40-80 increments by 8 -> 40 48 56 64 72
|
449 | 80-160 increments by 16 -> 80 96 112 128 144
|
450 | 160-320 increments by 32 -> 160 192 224 256 288
|
451 | 320-640 increments by 64 -> 320 384 448 512 576 640
|
452 | ```
|
453 |
|
454 | <!--
|
455 |
|
456 | ## Ranges
|
457 |
|
458 | Ranges describe all possible numerical values. Some properties support negative ranges (`margin`) and some properties use a sub-range (`border`, etc.).
|
459 |
|
460 | **Standard range:**
|
461 |
|
462 | ```
|
463 | 0-10, increments by 1: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
464 | 10-20, increments by 2: 10, 12, 14, 16, 18
|
465 | 20-40, increments by 4: 20, 24, 28, 32, 36,
|
466 | 40-80, increments by 8: 40, 48, 56, 64, 72,
|
467 | 80-160, increments by 16: 80, 96, 112, 128, 144,
|
468 | 160-320, increments by 32: 160, 192, 224, 256, 288, 320,
|
469 | ```
|
470 |
|
471 |
|
472 |
|
473 |
|
474 | margin:
|
475 |
|
476 | m-{-range|range} margin-all
|
477 | mt- margin-top
|
478 | mr- margin-right
|
479 | mb- margin-bottom
|
480 | ml- margin-left
|
481 | mx- margin-x-axis
|
482 | my- margin-y-axis
|
483 |
|
484 | padding:
|
485 |
|
486 | p-{range} padding-all
|
487 | pt- padding-top
|
488 | pr- padding-right
|
489 | pb- padding-bottom
|
490 | pl- padding-left
|
491 | px- padding-x-axis
|
492 | py- padding-y-axis
|
493 |
|
494 | ```
|
495 |
|
496 | -->
|
497 |
|
498 |
|
499 |
|
500 | ## Rationale and Demos
|
501 |
|
502 | If you’re asking yourself **‘Why did you build this from scratch and how is this different from Tailwind CSS?’**, check out these demos for a primer. Note that these are impromptu demos.
|
503 |
|
504 | <table>
|
505 | <tr>
|
506 | <td>
|
507 | <a href="https://youtube.com/watch?v=4PMPkLHD7Os" target="_blank">
|
508 | <img src="https://raw.githubusercontent.com/zaydek/duomo/main/.github/youtube-cover.png">
|
509 | <p><strong>Demo 1: Introducing Stacks</strong></p>
|
510 | </a>
|
511 | </td>
|
512 | <td>
|
513 | <a href="https://youtube.com/watch?v=vV-A3ywo6v8" target="_blank">
|
514 | <img src="https://raw.githubusercontent.com/zaydek/duomo/main/.github/youtube-cover.png">
|
515 | <p><strong>Demo 2: Introducing Theming</strong></p>
|
516 | </a>
|
517 | </td>
|
518 | </tr>
|
519 | </table>
|
520 |
|
521 | -->
|
522 |
|
523 |
|
524 |
|
525 | ## Table of Contents
|
526 |
|
527 | - [Stack-based layouts](#stack-based-layouts)
|
528 | - [Utility-first classes](#utility-first-classes)
|
529 | - [Emphasis on zero-configuration](#zero-configuration)
|
530 | - [Introspection via CSS variables (custom properties)](#introspection)
|
531 |
|
532 | ## [Stack-Based Layouts](#stack-based-layouts)
|
533 |
|
534 | <sub>Stacks are inspired by [Swift UI](https://developer.apple.com/videos/play/wwdc2020/10031) and [Jon Q’s talk about implementing Swift UI stacks in CSS](https://youtube.com/watch?v=fvOlTDJpNcM).</sub>
|
535 |
|
536 | What are stack-based layouts? Instead of thinking in terms of Flexbox, think in terms of stacks. A stack simply describes a horizontal or vertical axis, and stacks compose a layout. It’s turtles all the way down, for stacks. 🐢<sub>🐢</sub>
|
537 |
|
538 | Why stacks? Stacks are a more natural way of thinking about layout. The trouble with Flexbox is that you need to remember `display`, `flex-direction`, `justify-content`, `align-items`, and `flex`, and remember how these properties change in the context of `flex-direction: row` and `flex-direction: column`. Stacks are a much more simple but powerful primitive for describing layout _that is based on Flexbox_.
|
539 |
|
540 | This is a microcosm of how Duomo works:
|
541 |
|
542 | ```scss
|
543 | .hstack {
|
544 | display: flex;
|
545 | flex-direction: row;
|
546 | justify-content: center;
|
547 | }
|
548 | .hstack > * + * {
|
549 | margin-top: 0;
|
550 | margin-left: var(--space, 0);
|
551 | }
|
552 |
|
553 | .vstack {
|
554 | display: flex;
|
555 | flex-direction: column;
|
556 | justify-content: center;
|
557 | }
|
558 | .vstack > * + * {
|
559 | margin-left: 0;
|
560 | margin-top: var(--space, 0);
|
561 | }
|
562 |
|
563 | .spacer {
|
564 | flex: 1 0 var(--space, 0);
|
565 | }
|
566 | ```
|
567 |
|
568 | -->
|
569 |
|
570 |
|
571 |
|
572 | And this is a macrocosm of how Duomo works:
|
573 |
|
574 | ```scss
|
575 | $separator: "\\:";
|
576 |
|
577 | @function px($value) {
|
578 | @return $value + px;
|
579 | }
|
580 |
|
581 | @function rem($value) {
|
582 | @return $value / 16 + rem;
|
583 | }
|
584 |
|
585 | @function get-dynamic-ampersand() {
|
586 | @if not & {
|
587 | @return ".";
|
588 | }
|
589 | @return & + $separator;
|
590 | }
|
591 |
|
592 | @mixin stacks {
|
593 | $amp: get-dynamic-ampersand();
|
594 |
|
595 | #{$amp}hstack {
|
596 | display: flex;
|
597 | flex-direction: row;
|
598 | justify-content: center;
|
599 | align-items: stretch;
|
600 | }
|
601 | // NOTE: The root stack context resets `--space`.
|
602 | @if not & {
|
603 | .hstack > * {
|
604 | --space: 0;
|
605 | }
|
606 | }
|
607 | #{$amp}hstack > * + * {
|
608 | margin-top: 0;
|
609 | margin-left: var(--space, 0);
|
610 | }
|
611 | // NOTE: Omit `spacer`s and sibling elements from `var(--space)`.
|
612 | #{$amp}hstack > .spacer:empty,
|
613 | #{$amp}hstack > .spacer:empty + * {
|
614 | margin-left: 0;
|
615 | }
|
616 |
|
617 | #{$amp}vstack {
|
618 | display: flex;
|
619 | flex-direction: column;
|
620 | justify-content: center;
|
621 | align-items: stretch;
|
622 | }
|
623 | // NOTE: The root stack context resets `--space`.
|
624 | @if not & {
|
625 | .vstack > * {
|
626 | --space: 0;
|
627 | }
|
628 | }
|
629 | #{$amp}vstack > * + * {
|
630 | margin-left: 0;
|
631 | margin-top: var(--space, 0);
|
632 | }
|
633 | // NOTE: Omit `spacer`s and sibling elements from `var(--space)`.
|
634 | #{$amp}vstack > .spacer:empty,
|
635 | #{$amp}vstack > .spacer:empty + * {
|
636 | margin-top: 0;
|
637 | }
|
638 |
|
639 | #{$amp}align-start {
|
640 | align-items: flex-start;
|
641 | }
|
642 | #{$amp}align-center {
|
643 | align-items: center;
|
644 | }
|
645 | #{$amp}align-end {
|
646 | align-items: flex-end;
|
647 | }
|
648 |
|
649 | @if not & {
|
650 | .spacer {
|
651 | flex-grow: 1;
|
652 | flex-shrink: 0;
|
653 | flex-basis: var(--space, 0);
|
654 | }
|
655 | // NOTE: Edge `spacer`s are collapsible to `0`.
|
656 | .spacer:first-child,
|
657 | .spacer:last-child {
|
658 | flex-basis: 0;
|
659 | }
|
660 | }
|
661 |
|
662 | @each $value in (4, 8, 12, 16, 20, 24, 28, 32) {
|
663 | #{$amp}space-#{$value} > * {
|
664 | --space: #{rem($value)};
|
665 | }
|
666 | }
|
667 | }
|
668 |
|
669 | @mixin reset {
|
670 | *,
|
671 | *::before,
|
672 | *::after {
|
673 | box-sizing: border-box;
|
674 | }
|
675 |
|
676 | body {
|
677 | margin: 0;
|
678 | }
|
679 | }
|
680 |
|
681 | @mixin debugger {
|
682 | * {
|
683 | outline: 2px solid hsla(215, 100%, 50%, 0.2);
|
684 | outline-offset: -1px;
|
685 | }
|
686 | }
|
687 |
|
688 | @at-root {
|
689 | @include reset;
|
690 | @include debugger;
|
691 | @include stacks;
|
692 | @each $key, $value in ("sm": 640, "md": 768, "lg": 1024, "xl": 1280) {
|
693 | @media (min-width: #{px($value)}) {
|
694 | .#{$key} {
|
695 | @at-root {
|
696 | @include stacks;
|
697 | }
|
698 | }
|
699 | }
|
700 | }
|
701 | }
|
702 | ```
|
703 |
|
704 | This is how Duomo works. Duomo includes a CSS reset, debugger, and many utility classes that follow the same naming conventions as Tailwind CSS. Stacks however are the core of _how_ and _why_ Duomo works.
|
705 |
|
706 | -->
|
707 |
|
708 | <!--
|
709 |
|
710 | - `hstack`s implements a horizontal stack. Think `flex-direction: row`.
|
711 | - `vstack`s implements a vertical stack. Think `flex-direction: column`.
|
712 | - `spacer`s implements direction-agnostic spacers. Think `flex: 1`.
|
713 |
|
714 | Stacks in Duomo are easy to reason about because they manage Flexbox for you. 💡 Furthermore, Duomo stacks cover edge cases such as every stack resets `--space` and `spacer`s shrink to `--space` (unless they are the start or end element). **This enables you to think declaratively without worrying about implementation details or corner cases.**
|
715 |
|
716 | ## [Utility-First Classes](#utility-first-classes)
|
717 |
|
718 | TODO
|
719 |
|
720 | ## [Zero-Configuration](#zero-configuration)
|
721 |
|
722 | TODO
|
723 |
|
724 | ## [Introspection](#introspection)
|
725 |
|
726 | TODO
|
727 |
|
728 | -->
|
729 |
|
730 | ## License
|
731 |
|
732 | Licensed as [MIT](./LICENSE).
|
733 |
|
734 | <!--
|
735 |
|
736 | Duomo is a utility-first framework for rapid development. Duomo is most similar to Tailwind CSS but differentiates itself in these key ways:
|
737 |
|
738 | - Emphasis on zero-configuration
|
739 | - SCSS-based, designed to be extended
|
740 | - Limited API set, oriented for responsive skeleton prototyping
|
741 | - Intended to be used in conjunction with CSS or SCSS
|
742 | - Multiple CDN links for prototyping, add breakpoints as needed
|
743 | - Classes map to utilities but can encompass higher-order patterns like `m-gap`
|
744 |
|
745 | Furthermore, Duomo is simpler than Tailwind CSS for the following reasons:
|
746 |
|
747 | - The API surface area is dramatically smaller
|
748 | - More consistent class
|
749 | - Numerical values are specified using `px` equivalents, not Tailwind units
|
750 | - There are intentionally no `hover:`, `focus:`, etc. pseudo classes
|
751 | - You are encouraged to use Duomo and CSS or SCSS, not exclusively Tailwind CSS or Duomo
|
752 |
|
753 | The problem with almost every CSS library and framework is they attempt to _solve_ frontend. Frontend is not a solvable problem. Frontend is the amalgamation of _many_ tools coming together to create user experiences for people. How Duomo fits into this equation is by making it dead-easy to prototype responsive skeletons.
|
754 |
|
755 | The key to understanding Duomo is to understand that it **does not attempt** to map every CSS property to an arbitrary class. What Duomo does is makes it easier to reason about responsive skeletons, and encourages you to lean into CSS or SCSS when you’re ready to retrofit your skeleton-app with content.
|
756 |
|
757 | -->
|
758 |
|
\ | No newline at end of file |