swatchkit 1.1.0 → 2.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 (58) hide show
  1. package/build.js +82 -90
  2. package/package.json +2 -2
  3. package/src/blueprints/colors.json +11 -0
  4. package/src/blueprints/compositions/cluster.css +20 -0
  5. package/src/blueprints/compositions/flow.css +10 -0
  6. package/src/blueprints/compositions/grid.css +36 -0
  7. package/src/blueprints/compositions/index.css +12 -0
  8. package/src/blueprints/compositions/prose.css +89 -0
  9. package/src/blueprints/compositions/repel.css +23 -0
  10. package/src/blueprints/compositions/sidebar.css +44 -0
  11. package/src/blueprints/compositions/switcher.css +32 -0
  12. package/src/blueprints/compositions/wrapper.css +14 -0
  13. package/src/blueprints/fonts.json +24 -0
  14. package/src/blueprints/global/elements.css +609 -0
  15. package/src/blueprints/global/index.css +13 -0
  16. package/src/blueprints/global/reset.css +91 -0
  17. package/src/blueprints/global/variables.css +58 -0
  18. package/src/blueprints/main.css +27 -0
  19. package/src/blueprints/spacing.json +19 -0
  20. package/src/blueprints/swatches/hello.css +11 -0
  21. package/src/blueprints/swatches/index.css +7 -0
  22. package/src/blueprints/swatchkit-ui.css +79 -0
  23. package/src/blueprints/text-leading.json +13 -0
  24. package/src/blueprints/text-sizes.json +21 -0
  25. package/src/blueprints/text-weights.json +11 -0
  26. package/src/blueprints/utilities/index.css +9 -0
  27. package/src/blueprints/utilities/region.css +12 -0
  28. package/src/blueprints/utilities/visually-hidden.css +18 -0
  29. package/src/blueprints/viewports.json +10 -0
  30. package/src/generators/index.js +437 -0
  31. package/src/layout.html +0 -1
  32. package/src/preview-layout.html +13 -0
  33. package/src/templates/compositions/cluster/description.html +7 -0
  34. package/src/templates/compositions/cluster/index.html +7 -0
  35. package/src/templates/compositions/flow/description.html +8 -0
  36. package/src/templates/compositions/flow/index.html +6 -0
  37. package/src/templates/compositions/grid/description.html +12 -0
  38. package/src/templates/compositions/grid/index.html +7 -0
  39. package/src/templates/compositions/prose/description.html +8 -0
  40. package/src/templates/compositions/prose/index.html +6 -0
  41. package/src/templates/compositions/repel/description.html +9 -0
  42. package/src/templates/compositions/repel/index.html +4 -0
  43. package/src/templates/compositions/sidebar/description.html +13 -0
  44. package/src/templates/compositions/sidebar/index.html +4 -0
  45. package/src/templates/compositions/switcher/description.html +8 -0
  46. package/src/templates/compositions/switcher/index.html +29 -0
  47. package/src/templates/compositions/wrapper/description.html +8 -0
  48. package/src/templates/compositions/wrapper/index.html +5 -0
  49. package/src/templates/hello/README.md +83 -0
  50. package/src/templates/hello/index.html +1 -0
  51. package/src/templates/prose.html +366 -0
  52. package/src/templates/script.js +41 -0
  53. package/src/templates/utilities/region/description.html +8 -0
  54. package/src/templates/utilities/region/index.html +5 -0
  55. package/src/templates/utilities/visually-hidden/description.html +7 -0
  56. package/src/templates/utilities/visually-hidden/index.html +7 -0
  57. package/src/tokens.js +428 -0
  58. package/src/utils/clamp-generator.js +38 -0
package/build.js CHANGED
@@ -175,10 +175,8 @@ function resolveSettings(cliOptions, fileConfig) {
175
175
  // Derived paths
176
176
  distCssDir: path.join(outDir, "css"),
177
177
  distTokensCssFile: path.join(outDir, "css", "tokens.css"),
178
- distJsDir: path.join(outDir, "js"),
179
178
  distPreviewDir: path.join(outDir, "preview"),
180
179
  outputFile: path.join(outDir, "index.html"),
181
- outputJsFile: path.join(outDir, "js/swatches.js"),
182
180
  tokensCssFile: path.join(cssDir, "global", "tokens.css"),
183
181
  mainCssFile: path.join(cssDir, "main.css"),
184
182
  };
@@ -231,6 +229,22 @@ function buildInitManifest(settings) {
231
229
  });
232
230
  }
233
231
 
232
+ // Hello swatch (default example in swatchkit/swatches/hello/)
233
+ for (const file of ["index.html", "README.md"]) {
234
+ manifest.push({
235
+ src: path.join(templatesDir, "hello", file),
236
+ dest: path.join(settings.swatchkitDir, "swatches", "hello", file),
237
+ });
238
+ }
239
+
240
+ // Swatches CSS folder (css/swatches/)
241
+ for (const file of ["index.css", "hello.css"]) {
242
+ manifest.push({
243
+ src: path.join(blueprintsDir, "swatches", file),
244
+ dest: path.join(settings.cssDir, "swatches", file),
245
+ });
246
+ }
247
+
234
248
  // Utility and composition display templates — walk each subfolder
235
249
  for (const section of ["utilities", "compositions"]) {
236
250
  const sectionSrc = path.join(templatesDir, section);
@@ -301,8 +315,11 @@ function getInitDirs(settings) {
301
315
  path.join(settings.swatchkitDir, "tokens"),
302
316
  path.join(settings.swatchkitDir, "utilities"),
303
317
  path.join(settings.swatchkitDir, "compositions"),
318
+ path.join(settings.swatchkitDir, "swatches"),
319
+ path.join(settings.swatchkitDir, "swatches", "hello"),
304
320
  settings.cssDir,
305
321
  path.join(settings.cssDir, "global"),
322
+ path.join(settings.cssDir, "swatches"),
306
323
  ];
307
324
  }
308
325
 
@@ -550,7 +567,26 @@ function copyDir(src, dest, force = false) {
550
567
  }
551
568
  }
552
569
 
553
- function scanSwatches(dir, scriptsCollector, exclude = []) {
570
+ // Special filenames that SwatchKit reads and treats differently — not copied verbatim.
571
+ const SWATCH_SPECIAL_FILES = new Set(["index.html", "description.html"]);
572
+
573
+ // Recursively copy a swatch's assets (all files and subdirs except index.html,
574
+ // description.html, and anything prefixed with _ or .) to destDir.
575
+ function copySwatchAssets(srcDir, destDir) {
576
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
577
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
578
+ if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
579
+ const src = path.join(srcDir, entry.name);
580
+ const dest = path.join(destDir, entry.name);
581
+ if (entry.isDirectory()) {
582
+ copySwatchAssets(src, dest);
583
+ } else if (!SWATCH_SPECIAL_FILES.has(entry.name)) {
584
+ fs.copyFileSync(src, dest);
585
+ }
586
+ }
587
+ }
588
+
589
+ function scanSwatches(dir, destDir, exclude = []) {
554
590
  const swatches = [];
555
591
  if (!fs.existsSync(dir)) return swatches;
556
592
 
@@ -583,23 +619,14 @@ function scanSwatches(dir, scriptsCollector, exclude = []) {
583
619
  description = fs.readFileSync(descriptionFile, "utf-8");
584
620
  }
585
621
 
586
- // Find all .js files
587
- const jsFiles = fs
588
- .readdirSync(itemPath)
589
- .filter((file) => file.endsWith(".js"));
590
-
591
- jsFiles.forEach((jsFile) => {
592
- const scriptContent = fs.readFileSync(
593
- path.join(itemPath, jsFile),
594
- "utf-8",
595
- );
596
- scriptsCollector.push(`
597
- /* --- Swatch: ${name} / File: ${jsFile} --- */
598
- (function() {
599
- ${scriptContent}
600
- })();
601
- `);
602
- });
622
+ // Copy all non-special files and subdirectories from the component
623
+ // folder into its preview output directory so index.html can reference
624
+ // them with relative paths (e.g. ./styles.css, ./script.js, ./img/).
625
+ // Files and directories prefixed with _ or . are skipped.
626
+ if (destDir) {
627
+ const swatchDestDir = path.join(destDir, item);
628
+ copySwatchAssets(itemPath, swatchDestDir);
629
+ }
603
630
  }
604
631
  }
605
632
  // Handle Single File
@@ -608,18 +635,6 @@ ${scriptContent}
608
635
  id = name;
609
636
  content = fs.readFileSync(itemPath, "utf-8");
610
637
  }
611
- // Handle Loose JS Files (e.g. script.js in tokens/)
612
- else if (item.endsWith(".js")) {
613
- const scriptContent = fs.readFileSync(itemPath, "utf-8");
614
- scriptsCollector.push(`
615
- /* --- File: ${item} --- */
616
- (function() {
617
- ${scriptContent}
618
- })();
619
- `);
620
- // Don't add to swatches list, just scripts
621
- return;
622
- }
623
638
 
624
639
  if (name && content) {
625
640
  swatches.push({ name, id, content, description: description || null });
@@ -668,7 +683,7 @@ function build(settings) {
668
683
  }
669
684
 
670
685
  // 3. Ensure dist directories exist
671
- const distDirs = [settings.outDir, settings.distJsDir];
686
+ const distDirs = [settings.outDir];
672
687
  if (settings.cssCopy) distDirs.push(settings.distCssDir);
673
688
  distDirs.forEach((dir) => {
674
689
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
@@ -701,9 +716,8 @@ function build(settings) {
701
716
  console.log(`Skipping CSS copy (cssCopy: false). CSS referenced at: ${settings.cssPath}`);
702
717
  }
703
718
 
704
- // 4. Read swatches & JS
719
+ // 4. Read swatches
705
720
  console.log("Scanning HTML patterns (swatchkit/**/*.html)...");
706
- const scripts = [];
707
721
  const sections = {}; // Map<SectionName, Array<Swatch>>
708
722
 
709
723
  if (fs.existsSync(settings.swatchkitDir)) {
@@ -723,7 +737,9 @@ function build(settings) {
723
737
  // It is a Section Container (e.g. "Utilities")
724
738
  const sectionName =
725
739
  item === "tokens" ? "Design Tokens" : toTitleCase(item);
726
- const swatches = scanSwatches(itemPath, scripts, exclude);
740
+ // Pass the preview dest dir so extra files get copied alongside each swatch
741
+ const sectionDestDir = path.join(settings.distPreviewDir, item);
742
+ const swatches = scanSwatches(itemPath, sectionDestDir, exclude);
727
743
  // Tag each swatch with its section slug for preview paths
728
744
  swatches.forEach((s) => (s.sectionSlug = item));
729
745
  if (swatches.length > 0) {
@@ -749,24 +765,19 @@ function build(settings) {
749
765
  } else if (stat.isDirectory()) {
750
766
  const indexFile = path.join(itemPath, "index.html");
751
767
  if (fs.existsSync(indexFile)) {
752
- // Component folder swatch at root
768
+ // Component folder swatch at root — copy extra files to preview dest
753
769
  const name = item;
754
770
  const content = fs.readFileSync(indexFile, "utf-8");
755
- rootSwatches.push({ name, id: name, content, sectionSlug: null });
756
-
757
- // Collect JS
758
- const jsFiles = fs
759
- .readdirSync(itemPath)
760
- .filter((f) => f.endsWith(".js"));
761
- jsFiles.forEach((jsFile) => {
762
- const scriptContent = fs.readFileSync(
763
- path.join(itemPath, jsFile),
764
- "utf-8",
765
- );
766
- scripts.push(
767
- `/* ${name}/${jsFile} */ (function(){${scriptContent}})();`,
768
- );
769
- });
771
+ const descriptionFile = path.join(itemPath, "description.html");
772
+ const description = fs.existsSync(descriptionFile)
773
+ ? fs.readFileSync(descriptionFile, "utf-8")
774
+ : null;
775
+
776
+ // Copy extra files into preview/id/
777
+ const swatchDestDir = path.join(settings.distPreviewDir, name);
778
+ copySwatchAssets(itemPath, swatchDestDir);
779
+
780
+ rootSwatches.push({ name, id: name, content, description, sectionSlug: null });
770
781
  }
771
782
  }
772
783
  });
@@ -810,11 +821,13 @@ function build(settings) {
810
821
  .replace(/"/g, "&quot;")
811
822
  .replace(/'/g, "&#039;");
812
823
 
813
- // Build preview path: preview/{section}/{name}.html or preview/{name}.html
824
+ // Build preview path: preview/{section}/{id}/ or preview/{id}/
825
+ // Each swatch is a directory with its own index.html so sibling assets
826
+ // (css, js, images, etc.) can be referenced with relative paths.
814
827
  const previewPath = p.sectionSlug
815
- ? `preview/${p.sectionSlug}/${p.id}.html`
816
- : `preview/${p.id}.html`;
817
- const previewLink = previewPath.replace(/\.html$/, '');
828
+ ? `preview/${p.sectionSlug}/${p.id}/`
829
+ : `preview/${p.id}/`;
830
+ const previewLink = previewPath;
818
831
 
819
832
  return `
820
833
  <section id="${p.id}" class="region flow">
@@ -832,23 +845,9 @@ function build(settings) {
832
845
  .join("\n");
833
846
  });
834
847
 
835
- // 6. Write JS Bundle
836
- // Always prepend the internal token display script (resolves CSS custom
837
- // property values shown in token documentation pages).
838
- const tokenDisplayScript = fs.readFileSync(
839
- path.join(__dirname, "src/templates/script.js"),
840
- "utf-8",
841
- );
842
- const internalScript = `/* --- SwatchKit: token display --- */\n(function() {\n${tokenDisplayScript}\n})();`;
843
- const allScripts = [internalScript, ...scripts];
844
- fs.writeFileSync(settings.outputJsFile, allScripts.join("\n"));
845
- if (scripts.length > 0) {
846
- console.log(
847
- `Bundled ${scripts.length} swatch scripts to ${settings.outputJsFile}`,
848
- );
849
- }
850
-
851
- // 7. Generate preview pages (standalone full-screen view of each swatch)
848
+ // 6. Generate preview pages (standalone full-screen view of each swatch)
849
+ // Each swatch gets its own directory: preview/{section}/{id}/index.html
850
+ // This allows index.html to reference sibling assets with relative paths.
852
851
  let previewLayoutContent;
853
852
  if (fs.existsSync(settings.projectPreviewLayout)) {
854
853
  previewLayoutContent = fs.readFileSync(
@@ -867,32 +866,25 @@ function build(settings) {
867
866
  sortedKeys.forEach((section) => {
868
867
  const swatches = sections[section];
869
868
  swatches.forEach((p) => {
870
- // Determine output path and relative CSS path.
871
- // Preview pages need to navigate up to the swatchkit output root,
872
- // then follow cssPath to reach the CSS files.
873
- let previewFile, cssPath;
869
+ // Each swatch is output as a directory with index.html inside.
870
+ // preview/{section}/{id}/index.html — depth: 3 levels from outDir
871
+ // preview/{id}/index.html — depth: 2 levels from outDir
872
+ let swatchDir, cssPath;
874
873
  if (p.sectionSlug) {
875
- const sectionDir = path.join(settings.distPreviewDir, p.sectionSlug);
876
- if (!fs.existsSync(sectionDir))
877
- fs.mkdirSync(sectionDir, { recursive: true });
878
- previewFile = path.join(sectionDir, `${p.id}.html`);
879
- cssPath = "../../" + settings.cssPath; // preview/section/file.html -> ../../ + cssPath
874
+ swatchDir = path.join(settings.distPreviewDir, p.sectionSlug, p.id);
875
+ cssPath = "../../../" + settings.cssPath; // preview/section/id/index.html -> ../../../ + cssPath
880
876
  } else {
881
- if (!fs.existsSync(settings.distPreviewDir))
882
- fs.mkdirSync(settings.distPreviewDir, { recursive: true });
883
- previewFile = path.join(settings.distPreviewDir, `${p.id}.html`);
884
- cssPath = "../" + settings.cssPath; // preview/file.html -> ../ + cssPath
877
+ swatchDir = path.join(settings.distPreviewDir, p.id);
878
+ cssPath = "../../" + settings.cssPath; // preview/id/index.html -> ../../ + cssPath
885
879
  }
886
880
 
887
- // JS always lives in the swatchkit output dir, so jsPath just
888
- // navigates back to the output root (not to the user's CSS dir).
889
- const jsPath = p.sectionSlug ? "../../" : "../";
881
+ if (!fs.existsSync(swatchDir)) fs.mkdirSync(swatchDir, { recursive: true });
882
+ const previewFile = path.join(swatchDir, "index.html");
890
883
 
891
884
  const previewHtml = previewLayoutContent
892
885
  .replace("<!-- PREVIEW_TITLE -->", p.name)
893
886
  .replace("<!-- PREVIEW_CONTENT -->", p.content)
894
887
  .replaceAll("<!-- CSS_PATH -->", cssPath)
895
- .replaceAll("<!-- JS_PATH -->", jsPath)
896
888
  .replace("<!-- HEAD_EXTRAS -->", "");
897
889
 
898
890
  fs.writeFileSync(previewFile, previewHtml);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swatchkit",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "A lightweight tool for creating HTML pattern libraries.",
5
5
  "main": "build.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "files": [
10
10
  "build.js",
11
- "src/layout.html"
11
+ "src/"
12
12
  ],
13
13
  "scripts": {
14
14
  "start": "node build.js",
@@ -0,0 +1,11 @@
1
+ {
2
+ "title": "Colors",
3
+ "description": "Hex color codes that can be shared, cross-platform. They can be converted at point of usage, such as HSL for web or CMYK for print.",
4
+ "items": [
5
+ { "name": "color-dark", "value": "#1a2420" },
6
+ { "name": "color-dark-glare", "value": "#2d3830" },
7
+ { "name": "color-mid", "value": "#8a9a8e" },
8
+ { "name": "color-light", "value": "#f8faf7" },
9
+ { "name": "color-primary", "value": "#e07a5f" }
10
+ ]
11
+ }
@@ -0,0 +1,20 @@
1
+ /*
2
+ CLUSTER
3
+ Distributes items with consistent spacing, regardless of their size.
4
+
5
+ Credit: Adapted from Every Layout (The Cluster)
6
+ Docs: https://every-layout.dev/layouts/cluster/
7
+
8
+ CUSTOM PROPERTIES:
9
+ --gutter: Space between items (default: --space-m)
10
+ --cluster-horizontal-alignment: Horizontal alignment (default: flex-start)
11
+ --cluster-vertical-alignment: Vertical alignment (default: center)
12
+ */
13
+
14
+ .cluster {
15
+ display: flex;
16
+ flex-wrap: wrap;
17
+ gap: var(--gutter, var(--space-m));
18
+ justify-content: var(--cluster-horizontal-alignment, flex-start);
19
+ align-items: var(--cluster-vertical-alignment, center);
20
+ }
@@ -0,0 +1,10 @@
1
+ /*
2
+ FLOW
3
+ Adds vertical rhythm between direct siblings.
4
+
5
+ Credit: Adapted from Every Layout (The Stack)
6
+ Docs: https://every-layout.dev/layouts/stack/
7
+ */
8
+ .flow > * + * {
9
+ margin-block-start: var(--flow-space, 1em);
10
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Auto Grid Swatch
3
+ *
4
+ * A flexible layout that creates an auto-filling grid with configurable item sizes.
5
+ * Implements the "RAM" (Repeat, Auto, Minmax) pattern to adapt without media queries.
6
+ *
7
+ * Related: https://every-layout.dev/layouts/grid/
8
+ *
9
+ * Usage: <div class="grid">...</div>
10
+ */
11
+
12
+ .grid {
13
+ /*
14
+ * --gutter: Space between items
15
+ * --grid-min-item-size: Minimum width of an item before wrapping
16
+ * --grid-placement: auto-fill (default) or auto-fit
17
+ */
18
+ display: grid;
19
+ grid-template-columns: repeat(
20
+ var(--grid-placement, auto-fill),
21
+ minmax(var(--grid-min-item-size, 16rem), 1fr)
22
+ );
23
+ gap: var(--gutter, var(--space-l));
24
+ }
25
+
26
+ /* A split 50/50 layout */
27
+ .grid[data-layout="50-50"] {
28
+ --grid-placement: auto-fit;
29
+ --grid-min-item-size: clamp(16rem, 50vw, 33rem);
30
+ }
31
+
32
+ /* Three column grid layout */
33
+ .grid[data-layout="thirds"] {
34
+ --grid-placement: auto-fit;
35
+ --grid-min-item-size: clamp(16rem, 33%, 20rem);
36
+ }
@@ -0,0 +1,12 @@
1
+ /* === CSS Compositions === */
2
+
3
+ /* Layout primitives based on CUBE CSS / Every Layout */
4
+
5
+ @import "flow.css";
6
+ @import "sidebar.css";
7
+ @import "wrapper.css";
8
+ @import "cluster.css";
9
+ @import "repel.css";
10
+ @import "switcher.css";
11
+ @import "prose.css";
12
+ @import "grid.css";
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Prose Swatch
3
+ *
4
+ * A CUBE CSS "Block" designed to optimize the reading experience for long-form content.
5
+ * It manages spacing, line length, and typography for a comfortable rhythm.
6
+ *
7
+ * Usage: <article class="prose flow">...</article>
8
+ */
9
+
10
+ .prose {
11
+ /* Increase flow spacing for better reading rhythm */
12
+ --flow-space: var(--space-l);
13
+ }
14
+
15
+ /**
16
+ * Prevent large headings from breaking layout on small screens.
17
+ * hyphenation and break-word handling ensures text wraps gracefully.
18
+ */
19
+ .prose :is(h1, h2, h3) {
20
+ overflow-wrap: anywhere;
21
+ hyphens: auto;
22
+ }
23
+
24
+ /**
25
+ * Constrain line length for optimal readability (measure).
26
+ * text-wrap: pretty prevents orphans and awkward breaks.
27
+ */
28
+ .prose :is(p, li, dl, figcaption, blockquote) {
29
+ max-width: 60ch;
30
+ text-wrap: pretty;
31
+ }
32
+
33
+ /**
34
+ * Reduce spacing after headings to visually group them with their content.
35
+ */
36
+ .prose :is(h1, h2, h3, h4) + *:not([class]) {
37
+ --flow-space: var(--space-m);
38
+ }
39
+
40
+ /**
41
+ * Add more breathing room around heavy elements like figures and tables.
42
+ */
43
+ .prose :is(figure, table),
44
+ .prose :is(figure, table) + * {
45
+ --flow-space: var(--space-2xl);
46
+ }
47
+
48
+ /**
49
+ * Add extra space before headings to clearly separate sections.
50
+ */
51
+ .prose * + :is(h1, h2, h3, h4):not([class]) {
52
+ --flow-space: var(--space-xl);
53
+ }
54
+
55
+ /**
56
+ * Tighter spacing for list items to keep lists cohesive.
57
+ */
58
+ .prose :is(ul, ol):not([class]) li + li,
59
+ .prose :is(ul, ol):not([class]) li > :is(ol, ul) {
60
+ --flow-space: var(--space-xs);
61
+ }
62
+
63
+ /**
64
+ * Horizontal rules act as major section breaks, so give them plenty of space.
65
+ */
66
+ .prose hr {
67
+ --flow-space: var(--space-2xl);
68
+ }
69
+
70
+ /**
71
+ * Add a border to media elements to prevent them from blending into the background,
72
+ * especially in light mode.
73
+ */
74
+ .prose :is(img, picture, video) {
75
+ border: var(--stroke-solid);
76
+ }
77
+
78
+ /**
79
+ * On larger screens, relax the aggressive wrapping rules for headings.
80
+ * 47.5em matches 760px, the default 'viewport-mid' token.
81
+ * Preferring em here to catch the case where a user adjusts their browser default font size.
82
+ * Note: CSS variables cannot be used in media queries in standard CSS.
83
+ */
84
+ @media (min-width: 47.5em) {
85
+ .prose :is(h1, h2, h3) {
86
+ overflow-wrap: unset;
87
+ hyphens: unset;
88
+ }
89
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ REPEL
3
+ Pushes items away from each other where space allows, stacking on small viewports.
4
+
5
+ Credit: Adapted from Every Layout (The Cluster)
6
+ Docs: https://every-layout.dev/layouts/cluster/
7
+
8
+ CUSTOM PROPERTIES:
9
+ --gutter: Space between items (default: --space-m)
10
+ --repel-vertical-alignment: Vertical alignment (default: center)
11
+ */
12
+
13
+ .repel {
14
+ display: flex;
15
+ flex-wrap: wrap;
16
+ justify-content: space-between;
17
+ align-items: var(--repel-vertical-alignment, center);
18
+ gap: var(--gutter, var(--space-m));
19
+ }
20
+
21
+ .repel[data-nowrap] {
22
+ flex-wrap: nowrap;
23
+ }
@@ -0,0 +1,44 @@
1
+ /*
2
+ SIDEBAR
3
+ Layout with a flexible main content area and a fixed-width sidebar.
4
+
5
+ Credit: Adapted from Every Layout (The Sidebar)
6
+ Docs: https://every-layout.dev/layouts/sidebar/
7
+
8
+ CUSTOM PROPERTIES:
9
+ --gutter: Space between sidebar and content (default: --space-s-l)
10
+ --sidebar-target-width: Target width of sidebar (default: 20rem)
11
+ --sidebar-content-min-width: Min width of content before stacking (default: 50%)
12
+ */
13
+
14
+ .sidebar {
15
+ display: flex;
16
+ flex-wrap: wrap;
17
+ gap: var(--gutter, var(--space-s-l));
18
+ }
19
+
20
+ .sidebar:not([data-direction]) > :first-child {
21
+ flex-basis: var(--sidebar-target-width, 20rem);
22
+ flex-grow: 1;
23
+ }
24
+
25
+ .sidebar:not([data-direction]) > :last-child {
26
+ flex-basis: 0;
27
+ flex-grow: 999;
28
+ min-width: var(--sidebar-content-min-width, 50%);
29
+ }
30
+
31
+ .sidebar[data-reversed] {
32
+ flex-direction: row-reverse;
33
+ }
34
+
35
+ .sidebar[data-direction="rtl"] > :last-child {
36
+ flex-basis: var(--sidebar-target-width, 20rem);
37
+ flex-grow: 1;
38
+ }
39
+
40
+ .sidebar[data-direction="rtl"] > :first-child {
41
+ flex-basis: 0;
42
+ flex-grow: 999;
43
+ min-width: var(--sidebar-content-min-width, 50%);
44
+ }
@@ -0,0 +1,32 @@
1
+ /*
2
+ SWITCHER
3
+ Lays out items horizontally until there is insufficient space, then stacks them.
4
+ Optimized for 3 items.
5
+
6
+ Credit: Adapted from Every Layout (The Switcher)
7
+ Docs: https://every-layout.dev/layouts/switcher/
8
+
9
+ CUSTOM PROPERTIES:
10
+ --gutter: Space between items (default: --space-l)
11
+ --switcher-target-container-width: Container breakpoint width (default: 40rem)
12
+ --switcher-vertical-alignment: Vertical alignment (default: flex-start)
13
+ */
14
+
15
+ .switcher {
16
+ display: flex;
17
+ flex-wrap: wrap;
18
+ gap: var(--gutter, var(--space-l));
19
+ align-items: var(--switcher-vertical-alignment, flex-start);
20
+ }
21
+
22
+ .switcher > * {
23
+ flex-grow: 1;
24
+ flex-basis: calc(
25
+ (var(--switcher-target-container-width, 40rem) - 100%) * 999
26
+ );
27
+ }
28
+
29
+ /* Max 3 items, so anything greater than 3 is full width */
30
+ .switcher > :nth-child(n + 4) {
31
+ flex-basis: 100%;
32
+ }
@@ -0,0 +1,14 @@
1
+ /*
2
+ WRAPPER
3
+
4
+ Credit: More or less, adapted from Every Layout (The Center)
5
+ Docs: https://every-layout.dev/layouts/center/
6
+ */
7
+
8
+ .wrapper {
9
+ margin-inline: auto;
10
+ max-inline-size: var(--wrapper-max-width, 1360px);
11
+ padding-inline-start: var(--gutter);
12
+ padding-inline-end: var(--gutter);
13
+ position: relative;
14
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "title": "Fonts",
3
+ "description": "Each array of fonts creates a priority-based order. The first font in the array should be the ideal font, followed by sensible, web-safe fallbacks",
4
+ "items": [
5
+ {
6
+ "name": "font-base",
7
+ "description": "System fonts for body copy and globally set text.",
8
+ "value": [
9
+ "Satoshi",
10
+ "Inter",
11
+ "Segoe UI",
12
+ "Roboto",
13
+ "Helvetica Neue",
14
+ "Arial",
15
+ "sans-serif"
16
+ ]
17
+ },
18
+ {
19
+ "name": "font-mono",
20
+ "description": "Monospace font for code samples etc",
21
+ "value": ["DM Mono", "monospace"]
22
+ }
23
+ ]
24
+ }