@bookklik/senangstart-css 0.2.3 → 0.2.5

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 (135) hide show
  1. package/dist/senangstart-css.js +100 -6
  2. package/dist/senangstart-css.min.js +26 -22
  3. package/dist/senangstart-tw.js +537 -0
  4. package/dist/senangstart-tw.min.js +2 -0
  5. package/docs/.vitepress/config.js +6 -0
  6. package/docs/guide/cdn.md +1 -1
  7. package/docs/ms/guide/cdn.md +1 -1
  8. package/docs/ms/reference/layout/position.md +4 -4
  9. package/docs/ms/reference/layout/z-index.md +8 -8
  10. package/docs/ms/reference/space/gap.md +1 -1
  11. package/docs/ms/reference/space/height.md +1 -1
  12. package/docs/ms/reference/space/margin.md +1 -1
  13. package/docs/ms/reference/space/padding.md +1 -1
  14. package/docs/ms/reference/space/scale-reference.md +46 -17
  15. package/docs/ms/reference/space/width.md +1 -1
  16. package/docs/ms/reference/space.md +1 -1
  17. package/docs/ms/reference/spacing.md +103 -21
  18. package/docs/ms/reference/visual/animation-fill.md +8 -8
  19. package/docs/ms/reference/visual/backdrop-blur.md +4 -4
  20. package/docs/ms/reference/visual/backdrop-brightness.md +8 -8
  21. package/docs/ms/reference/visual/backdrop-grayscale.md +6 -6
  22. package/docs/ms/reference/visual/backdrop-sepia.md +6 -6
  23. package/docs/ms/reference/visual/background-clip.md +2 -2
  24. package/docs/ms/reference/visual/background-image.md +4 -4
  25. package/docs/ms/reference/visual/filter-brightness.md +4 -4
  26. package/docs/ms/reference/visual/filter-contrast.md +4 -4
  27. package/docs/ms/reference/visual/filter-drop-shadow.md +6 -6
  28. package/docs/ms/reference/visual/filter-grayscale.md +4 -4
  29. package/docs/ms/reference/visual/filter-hue-rotate.md +4 -4
  30. package/docs/ms/reference/visual/filter-invert.md +2 -2
  31. package/docs/ms/reference/visual/filter-saturate.md +4 -4
  32. package/docs/ms/reference/visual/filter-sepia.md +4 -4
  33. package/docs/ms/reference/visual/font-family.md +2 -2
  34. package/docs/ms/reference/visual/gradient-from.md +57 -0
  35. package/docs/ms/reference/visual/gradient-to.md +57 -0
  36. package/docs/ms/reference/visual/gradient-via.md +54 -0
  37. package/docs/ms/reference/visual/letter-spacing.md +2 -2
  38. package/docs/ms/reference/visual/line-clamp.md +2 -2
  39. package/docs/ms/reference/visual/line-height.md +2 -2
  40. package/docs/ms/reference/visual/outline.md +2 -2
  41. package/docs/ms/reference/visual/ring-color.md +29 -0
  42. package/docs/ms/reference/visual/ring-offset.md +30 -0
  43. package/docs/ms/reference/visual/ring.md +62 -0
  44. package/docs/ms/reference/visual/stroke-width.md +6 -6
  45. package/docs/ms/reference/visual/stroke.md +4 -4
  46. package/docs/ms/reference/visual/text-indent.md +2 -2
  47. package/docs/ms/reference/visual/text-overflow.md +2 -2
  48. package/docs/ms/reference/visual/text-size.md +84 -84
  49. package/docs/ms/reference/visual/text-wrap.md +2 -2
  50. package/docs/ms/reference/visual/transform-backface.md +4 -4
  51. package/docs/ms/reference/visual/transform-perspective-origin.md +6 -6
  52. package/docs/ms/reference/visual/transform-perspective.md +6 -6
  53. package/docs/ms/reference/visual/transform-rotate-3d.md +6 -6
  54. package/docs/ms/reference/visual/transform-style.md +4 -4
  55. package/docs/ms/reference/visual/transform-translate-z.md +6 -6
  56. package/docs/ms/reference/visual/transform-translate.md +2 -2
  57. package/docs/ms/reference/visual/whitespace.md +2 -2
  58. package/docs/ms/reference/visual/word-break.md +2 -2
  59. package/docs/public/assets/senangstart-css.min.js +213 -1545
  60. package/docs/public/llms.txt +1718 -0
  61. package/docs/reference/layout/position.md +4 -4
  62. package/docs/reference/layout/z-index.md +8 -8
  63. package/docs/reference/space/gap.md +1 -1
  64. package/docs/reference/space/height.md +1 -1
  65. package/docs/reference/space/margin.md +1 -1
  66. package/docs/reference/space/padding.md +1 -1
  67. package/docs/reference/space/scale-reference.md +46 -17
  68. package/docs/reference/space/width.md +1 -1
  69. package/docs/reference/space.md +1 -1
  70. package/docs/reference/spacing.md +103 -21
  71. package/docs/reference/visual/animation-fill.md +8 -8
  72. package/docs/reference/visual/backdrop-blur.md +4 -4
  73. package/docs/reference/visual/backdrop-brightness.md +8 -8
  74. package/docs/reference/visual/backdrop-grayscale.md +6 -6
  75. package/docs/reference/visual/backdrop-sepia.md +6 -6
  76. package/docs/reference/visual/background-clip.md +2 -2
  77. package/docs/reference/visual/background-image.md +4 -4
  78. package/docs/reference/visual/filter-brightness.md +4 -4
  79. package/docs/reference/visual/filter-contrast.md +4 -4
  80. package/docs/reference/visual/filter-drop-shadow.md +6 -6
  81. package/docs/reference/visual/filter-grayscale.md +4 -4
  82. package/docs/reference/visual/filter-hue-rotate.md +4 -4
  83. package/docs/reference/visual/filter-invert.md +2 -2
  84. package/docs/reference/visual/filter-saturate.md +4 -4
  85. package/docs/reference/visual/filter-sepia.md +4 -4
  86. package/docs/reference/visual/font-family.md +2 -2
  87. package/docs/reference/visual/gradient-from.md +57 -0
  88. package/docs/reference/visual/gradient-to.md +57 -0
  89. package/docs/reference/visual/gradient-via.md +54 -0
  90. package/docs/reference/visual/letter-spacing.md +2 -2
  91. package/docs/reference/visual/line-clamp.md +2 -2
  92. package/docs/reference/visual/line-height.md +2 -2
  93. package/docs/reference/visual/outline.md +2 -2
  94. package/docs/reference/visual/ring-color.md +29 -0
  95. package/docs/reference/visual/ring-offset.md +30 -0
  96. package/docs/reference/visual/ring.md +62 -0
  97. package/docs/reference/visual/stroke-width.md +6 -6
  98. package/docs/reference/visual/stroke.md +4 -4
  99. package/docs/reference/visual/text-indent.md +2 -2
  100. package/docs/reference/visual/text-overflow.md +2 -2
  101. package/docs/reference/visual/text-size.md +84 -84
  102. package/docs/reference/visual/text-wrap.md +2 -2
  103. package/docs/reference/visual/transform-backface.md +4 -4
  104. package/docs/reference/visual/transform-perspective-origin.md +6 -6
  105. package/docs/reference/visual/transform-perspective.md +6 -6
  106. package/docs/reference/visual/transform-rotate-3d.md +6 -6
  107. package/docs/reference/visual/transform-style.md +4 -4
  108. package/docs/reference/visual/transform-translate-z.md +6 -6
  109. package/docs/reference/visual/transform-translate.md +2 -2
  110. package/docs/reference/visual/whitespace.md +2 -2
  111. package/docs/reference/visual/word-break.md +2 -2
  112. package/package.json +4 -2
  113. package/playground/tw-convertor.html +103 -589
  114. package/scripts/build-dist.js +45 -3
  115. package/scripts/bundle-jit.js +3 -3
  116. package/scripts/convert-tailwind.js +180 -1
  117. package/scripts/generate-llms-txt.js +264 -0
  118. package/src/cdn/{jit.js → senangstart-engine.js} +97 -8
  119. package/src/cdn/tw-conversion-engine.js +632 -0
  120. package/src/compiler/generators/css.js +27 -0
  121. package/src/config/defaults.js +37 -11
  122. package/src/core/constants.js +37 -8
  123. package/src/definitions/layout-positioning.js +6 -6
  124. package/src/definitions/space.js +46 -5
  125. package/src/definitions/visual-backgrounds.js +113 -15
  126. package/src/definitions/visual-borders.js +81 -2
  127. package/src/definitions/visual-filters.js +16 -16
  128. package/src/definitions/visual-svg.js +5 -5
  129. package/src/definitions/visual-transform3d.js +16 -16
  130. package/src/definitions/visual-transforms.js +1 -1
  131. package/src/definitions/visual-transitions.js +4 -4
  132. package/src/definitions/visual-typography.js +6 -6
  133. package/src/definitions/visual.js +4 -4
  134. package/tests/unit/compiler/generators/css.test.js +192 -0
  135. package/tests/unit/convert-tailwind.test.js +8 -0
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import * as esbuild from 'esbuild';
9
- import { mkdirSync, statSync } from 'fs';
9
+ import { mkdirSync, statSync, copyFileSync } from 'fs';
10
10
  import { dirname, join } from 'path';
11
11
  import { fileURLToPath } from 'url';
12
12
 
@@ -21,7 +21,7 @@ console.log('📦 Building SenangStart CSS...\n');
21
21
 
22
22
  // Build unminified version
23
23
  await esbuild.build({
24
- entryPoints: [join(root, 'src', 'cdn', 'jit.js')],
24
+ entryPoints: [join(root, 'src', 'cdn', 'senangstart-engine.js')],
25
25
  bundle: true,
26
26
  format: 'iife',
27
27
  outfile: join(distDir, 'senangstart-css.js'),
@@ -36,7 +36,7 @@ console.log(`✓ Created senangstart-css.js (${(unminSize / 1024).toFixed(1)} KB
36
36
 
37
37
  // Build minified version
38
38
  await esbuild.build({
39
- entryPoints: [join(root, 'src', 'cdn', 'jit.js')],
39
+ entryPoints: [join(root, 'src', 'cdn', 'senangstart-engine.js')],
40
40
  bundle: true,
41
41
  format: 'iife',
42
42
  outfile: join(distDir, 'senangstart-css.min.js'),
@@ -49,6 +49,48 @@ await esbuild.build({
49
49
  const minSize = statSync(join(distDir, 'senangstart-css.min.js')).size;
50
50
  console.log(`✓ Created senangstart-css.min.js (${(minSize / 1024).toFixed(1)} KB)`);
51
51
 
52
+ // Build Tailwind converter - unminified
53
+ await esbuild.build({
54
+ entryPoints: [join(root, 'src', 'cdn', 'tw-conversion-engine.js')],
55
+ bundle: true,
56
+ format: 'iife',
57
+ outfile: join(distDir, 'senangstart-tw.js'),
58
+ minify: false,
59
+ banner: {
60
+ js: '/* SenangStart CSS - Tailwind Converter v0.2.0 | MIT License */'
61
+ }
62
+ });
63
+
64
+ const twUnminSize = statSync(join(distDir, 'senangstart-tw.js')).size;
65
+ console.log(`✓ Created senangstart-tw.js (${(twUnminSize / 1024).toFixed(1)} KB)`);
66
+
67
+ // Build Tailwind converter - minified
68
+ await esbuild.build({
69
+ entryPoints: [join(root, 'src', 'cdn', 'tw-conversion-engine.js')],
70
+ bundle: true,
71
+ format: 'iife',
72
+ outfile: join(distDir, 'senangstart-tw.min.js'),
73
+ minify: true,
74
+ banner: {
75
+ js: '/* SenangStart TW v0.2.0 | MIT */'
76
+ }
77
+ });
78
+
79
+ const twMinSize = statSync(join(distDir, 'senangstart-tw.min.js')).size;
80
+ console.log(`✓ Created senangstart-tw.min.js (${(twMinSize / 1024).toFixed(1)} KB)`);
81
+
82
+ // Copy to docs/public/assets for VitePress
83
+ const docsAssetsDir = join(root, 'docs', 'public', 'assets');
84
+ mkdirSync(docsAssetsDir, { recursive: true });
85
+ copyFileSync(
86
+ join(distDir, 'senangstart-css.min.js'),
87
+ join(docsAssetsDir, 'senangstart-css.min.js')
88
+ );
89
+ console.log(`✓ Copied to docs/public/assets/senangstart-css.min.js`);
90
+
52
91
  console.log('\n📦 Dist build complete!');
53
92
  console.log(' dist/senangstart-css.js');
54
93
  console.log(' dist/senangstart-css.min.js');
94
+ console.log(' dist/senangstart-tw.js');
95
+ console.log(' dist/senangstart-tw.min.js');
96
+
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * Bundle JIT Runtime with esbuild
5
- * Bundles src/cdn/jit.js into a self-contained IIFE for browser use
5
+ * Bundles src/cdn/senangstart-engine.js into a self-contained IIFE for browser use
6
6
  */
7
7
 
8
8
  import * as esbuild from 'esbuild';
@@ -16,7 +16,7 @@ console.log('📦 Bundling JIT runtime...');
16
16
 
17
17
  // Build unminified version
18
18
  await esbuild.build({
19
- entryPoints: [join(root, 'src', 'cdn', 'jit.js')],
19
+ entryPoints: [join(root, 'src', 'cdn', 'senangstart-engine.js')],
20
20
  bundle: true,
21
21
  format: 'iife',
22
22
  outfile: join(root, 'dist', 'senangstart-css.js'),
@@ -30,7 +30,7 @@ console.log('✓ Created dist/senangstart-css.js');
30
30
 
31
31
  // Build minified version
32
32
  await esbuild.build({
33
- entryPoints: [join(root, 'src', 'cdn', 'jit.js')],
33
+ entryPoints: [join(root, 'src', 'cdn', 'senangstart-engine.js')],
34
34
  bundle: true,
35
35
  format: 'iife',
36
36
  outfile: join(root, 'dist', 'senangstart-css.min.js'),
@@ -318,7 +318,21 @@ const visualKeywordMappings = {
318
318
 
319
319
  // Appearance
320
320
  'appearance-none': 'appearance:none',
321
- 'appearance-auto': 'appearance:auto'
321
+ 'appearance-auto': 'appearance:auto',
322
+
323
+ // 3D Transforms
324
+ 'perspective': 'perspective',
325
+ 'perspective-origin': 'perspective-origin',
326
+ 'transform-style': 'transform-style',
327
+ 'backface-visibility': 'backface',
328
+ 'mask': 'mask',
329
+ 'mask-image': 'mask-image',
330
+ 'mask-mode': 'mask-mode',
331
+ 'mask-origin': 'mask-origin',
332
+ 'mask-position': 'mask-position',
333
+ 'mask-repeat': 'mask-repeat',
334
+ 'mask-size': 'mask-size',
335
+ 'mask-type': 'mask-type'
322
336
  };
323
337
 
324
338
  // ======================
@@ -583,6 +597,171 @@ function convertClass(twClass, options = {}) {
583
597
  return { category: 'visual', value: prefix + "opacity:" + opacityMatch[1] };
584
598
  }
585
599
 
600
+ // Gradient direction (bg-gradient-to-*)
601
+ const bgGradientMatch = baseClass.match(/^bg-gradient-to-(t|tr|r|br|b|bl|l|tl)$/);
602
+ if (bgGradientMatch) {
603
+ return { category: 'visual', value: prefix + "bg-image:gradient-to-" + bgGradientMatch[1] };
604
+ }
605
+
606
+ // Gradient from-* (starting color)
607
+ const fromMatch = baseClass.match(/^from-(.+)$/);
608
+ if (fromMatch) {
609
+ return { category: 'visual', value: prefix + "from:" + fromMatch[1] };
610
+ }
611
+
612
+ // Gradient via-* (middle color)
613
+ const viaMatch = baseClass.match(/^via-(.+)$/);
614
+ if (viaMatch) {
615
+ return { category: 'visual', value: prefix + "via:" + viaMatch[1] };
616
+ }
617
+
618
+ // Gradient to-* (ending color) - Note: must come after bg-gradient-to-*
619
+ const toMatch = baseClass.match(/^to-(.+)$/);
620
+ if (toMatch) {
621
+ return { category: 'visual', value: prefix + "to:" + toMatch[1] };
622
+ }
623
+
624
+ // ======================
625
+ // 3D TRANSFORMS
626
+ // ======================
627
+
628
+ // Perspective
629
+ const perspectiveMatch = baseClass.match(/^perspective(?:-(.+))?$/);
630
+ if (perspectiveMatch) {
631
+ const val = perspectiveMatch[1] || 'normal';
632
+ return { category: 'visual', value: prefix + "perspective:" + val };
633
+ }
634
+
635
+ // Perspective origin
636
+ const perspectiveOriginMatch = baseClass.match(/^perspective-origin(?:-(.+))?$/);
637
+ if (perspectiveOriginMatch) {
638
+ const val = perspectiveOriginMatch[1] || 'center';
639
+ return { category: 'visual', value: prefix + "perspective-origin:" + val };
640
+ }
641
+
642
+ // Rotate X/Y/Z (3D rotation)
643
+ const rotateAxisMatch = baseClass.match(/^rotate-([xyz])(?:-(.+))?$/);
644
+ if (rotateAxisMatch) {
645
+ const axis = rotateAxisMatch[1].toLowerCase();
646
+ const val = rotateAxisMatch[2] || '0';
647
+ return { category: 'visual', value: prefix + `rotate-${axis}:${val}` };
648
+ }
649
+
650
+ // Rotate (2D)
651
+ const rotateMatch = baseClass.match(/^rotate(?:-(.+))?$/);
652
+ if (rotateMatch && !rotateAxisMatch) {
653
+ const val = rotateMatch[1] || '0';
654
+ return { category: 'visual', value: prefix + `rotate:${val}` };
655
+ }
656
+
657
+ // Scale X/Y
658
+ const scaleAxisMatch = baseClass.match(/^scale-([xy])(?:-(.+))?$/);
659
+ if (scaleAxisMatch) {
660
+ const axis = scaleAxisMatch[1].toLowerCase();
661
+ const val = scaleAxisMatch[2] || '100';
662
+ return { category: 'visual', value: prefix + `scale-${axis}:${val}` };
663
+ }
664
+
665
+ // Scale (uniform)
666
+ const scaleMatch = baseClass.match(/^scale(?:-(.+))?$/);
667
+ if (scaleMatch && !scaleAxisMatch) {
668
+ const val = scaleMatch[1] || '100';
669
+ return { category: 'visual', value: prefix + `scale:${val}` };
670
+ }
671
+
672
+ // Skew X/Y
673
+ const skewAxisMatch = baseClass.match(/^skew-([xy])(?:-(.+))?$/);
674
+ if (skewAxisMatch) {
675
+ const axis = skewAxisMatch[1].toLowerCase();
676
+ const val = skewAxisMatch[2] || '0';
677
+ return { category: 'visual', value: prefix + `skew-${axis}:${val}` };
678
+ }
679
+
680
+ // Translate X/Y/Z
681
+ const translateAxisMatch = baseClass.match(/^translate-([xyz])(?:-(.+))?$/);
682
+ if (translateAxisMatch) {
683
+ const axis = translateAxisMatch[1].toLowerCase();
684
+ const val = translateAxisMatch[2] || '0';
685
+ return { category: 'visual', value: prefix + `translate-${axis}:${val}` };
686
+ }
687
+
688
+ // Transform style
689
+ const transformStyleMatch = baseClass.match(/^transform-style(?:-(.+))?$/);
690
+ if (transformStyleMatch) {
691
+ const val = transformStyleMatch[1] || 'flat';
692
+ return { category: 'visual', value: prefix + "transform-style:" + val };
693
+ }
694
+
695
+ // Backface visibility
696
+ const backfaceMatch = baseClass.match(/^backface(?:-(.+))?$/);
697
+ if (backfaceMatch) {
698
+ const val = backfaceMatch[1] || 'hidden';
699
+ return { category: 'visual', value: prefix + "backface:" + val };
700
+ }
701
+
702
+ // Transform origin
703
+ const originMatch = baseClass.match(/^origin(?:-(.+))?$/);
704
+ if (originMatch) {
705
+ const val = originMatch[1] || 'center';
706
+ return { category: 'visual', value: prefix + "origin:" + val };
707
+ }
708
+
709
+ // Mask
710
+ const maskMatch = baseClass.match(/^mask(?:-(.+))?$/);
711
+ if (maskMatch) {
712
+ const val = maskMatch[1] || 'none';
713
+ return { category: 'visual', value: prefix + "mask:" + val };
714
+ }
715
+
716
+ // Mask image
717
+ const maskImageMatch = baseClass.match(/^mask-image(?:-(.+))?$/);
718
+ if (maskImageMatch) {
719
+ const val = maskImageMatch[1] || 'none';
720
+ return { category: 'visual', value: prefix + "mask-image:" + val };
721
+ }
722
+
723
+ // Mask mode
724
+ const maskModeMatch = baseClass.match(/^mask-mode(?:-(.+))?$/);
725
+ if (maskModeMatch) {
726
+ const val = maskModeMatch[1] || 'match';
727
+ return { category: 'visual', value: prefix + "mask-mode:" + val };
728
+ }
729
+
730
+ // Mask origin
731
+ const maskOriginMatch = baseClass.match(/^mask-origin(?:-(.+))?$/);
732
+ if (maskOriginMatch) {
733
+ const val = maskOriginMatch[1] || 'center';
734
+ return { category: 'visual', value: prefix + "mask-origin:" + val };
735
+ }
736
+
737
+ // Mask position
738
+ const maskPositionMatch = baseClass.match(/^mask-position(?:-(.+))?$/);
739
+ if (maskPositionMatch) {
740
+ const val = maskPositionMatch[1] || 'center';
741
+ return { category: 'visual', value: prefix + "mask-position:" + val };
742
+ }
743
+
744
+ // Mask repeat
745
+ const maskRepeatMatch = baseClass.match(/^mask-repeat(?:-(.+))?$/);
746
+ if (maskRepeatMatch) {
747
+ const val = maskRepeatMatch[1] || 'repeat';
748
+ return { category: 'visual', value: prefix + "mask-repeat:" + val };
749
+ }
750
+
751
+ // Mask size
752
+ const maskSizeMatch = baseClass.match(/^mask-size(?:-(.+))?$/);
753
+ if (maskSizeMatch) {
754
+ const val = maskSizeMatch[1] || 'auto';
755
+ return { category: 'visual', value: prefix + "mask-size:" + val };
756
+ }
757
+
758
+ // Mask type
759
+ const maskTypeMatch = baseClass.match(/^mask-type(?:-(.+))?$/);
760
+ if (maskTypeMatch) {
761
+ const val = maskTypeMatch[1] || 'luminance';
762
+ return { category: 'visual', value: prefix + "mask-type:" + val };
763
+ }
764
+
586
765
  return null;
587
766
  }
588
767
 
@@ -0,0 +1,264 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { fileURLToPath } from 'node:url';
5
+ import { pathToFileURL } from 'node:url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+
11
+
12
+ const PACKAGE_JSON_PATH = path.resolve(__dirname, '../package.json');
13
+ const DEFINITIONS_DIR = path.resolve(__dirname, '../src/definitions');
14
+ const OUTPUT_PATH = path.resolve(__dirname, '../docs/public/llms.txt');
15
+
16
+ // Load defaults from package.json
17
+ let defaults = {
18
+ name: 'SenangStart CSS',
19
+ description: '',
20
+ license: 'MIT',
21
+ homepage: ''
22
+ };
23
+
24
+ try {
25
+ if (fs.existsSync(PACKAGE_JSON_PATH)) {
26
+ const pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf-8'));
27
+ if (pkg.name) defaults.name = pkg.name;
28
+ if (pkg.description) defaults.description = pkg.description;
29
+ if (pkg.license) defaults.license = pkg.license;
30
+ if (pkg.homepage) defaults.homepage = pkg.homepage;
31
+ }
32
+ } catch (e) {
33
+ console.warn('Warning: Could not read package.json for defaults.');
34
+ }
35
+
36
+
37
+
38
+ function formatDefinition(key, def) {
39
+ let output = `## ${def.title || def.name || key}\n`;
40
+ if (def.description) {
41
+ output += `> ${def.description}\n`;
42
+ }
43
+
44
+ // Add Syntax/Usage if available
45
+ if (def.syntax) {
46
+ output += `\n**Syntax:** \`${def.syntax}\`\n`;
47
+ }
48
+
49
+ if (def.values && Array.isArray(def.values)) {
50
+ output += `\n`;
51
+ def.values.forEach(val => {
52
+ let valDesc = val.description || '';
53
+ // If CSS is present, maybe show it, or keep it high level?
54
+ // Tailwind example had: `bg-none`: Removes background image (`background-image: none;`).
55
+ // Our values are like { value: 'none', css: '...', description: '...' }
56
+ // The utility class is constructed via syntax, usually properties like `text:left` or `bg:primary`.
57
+ // The 'value' field is just the suffix/argument.
58
+
59
+ // Let's try to infer the full utility format if possible, or just list the value.
60
+ // If syntax is visual="text:[alignment]", and value is 'left', then utility is text:left.
61
+
62
+ let displayValue = val.value;
63
+ // Attempt to contextualize the value based on syntax
64
+ // e.g. syntax="visual="text:[alignment]"", value="left" -> text:left
65
+ // This might be complex to regex universally, but let's try a simple approach if possible.
66
+ // For now, just listing the value is safe.
67
+
68
+ let line = `* \`${displayValue}\``;
69
+ if (valDesc) line += `: ${valDesc}`;
70
+ if (val.css && val.css.length < 50) line += ` (\`${val.css}\`)`; // only show if short
71
+
72
+ output += `${line}\n`;
73
+ });
74
+ }
75
+ output += `\n`;
76
+ return output;
77
+ }
78
+
79
+ async function loadDefinitions() {
80
+ const definitions = new Map();
81
+ if (!fs.existsSync(DEFINITIONS_DIR)) return [];
82
+
83
+ const files = fs.readdirSync(DEFINITIONS_DIR).filter(f => f.endsWith('.js'));
84
+
85
+ for (const file of files) {
86
+ try {
87
+ const filePath = path.join(DEFINITIONS_DIR, file);
88
+ const fileUrl = pathToFileURL(filePath).href;
89
+ const module = await import(fileUrl);
90
+
91
+ // Iterate over exports, skipping default if it's just a collection of others
92
+ for (const [key, value] of Object.entries(module)) {
93
+ if (key === 'default') continue;
94
+ // Check if it looks like a definition (has name/property/values)
95
+ if (value && value.name && value.property && Array.isArray(value.values)) {
96
+ // Use definition name as key to prevent duplicates from re-exports
97
+ // e.g. layout.js re-exports definition from layout-flex.js
98
+ const defName = value.name;
99
+ if (!definitions.has(defName)) {
100
+ definitions.set(defName, { key, ...value });
101
+ }
102
+ }
103
+ }
104
+ } catch (e) {
105
+ console.error(`Error loading definition ${file}:`, e);
106
+ }
107
+ }
108
+ return Array.from(definitions.values());
109
+ }
110
+
111
+ function getGuideContent() {
112
+ return `
113
+ # Framework Overview
114
+
115
+ SenangStart CSS is a utility-first framework that uses **Natural Adjectives** instead of abstract numbers.
116
+
117
+ ## Core Philosophy
118
+ - **Natural Scale**: Sizes map to physical mental models (e.g., \`tiny\` = pebble/4px, \`medium\` = smartphone/16px, \`giant\` = door/64px).
119
+ - **Intent-First**: Describe *what* you want ("give it air" -> scale up), not pixels.
120
+ - **Tri-Attribute Syntax**: Separation of concerns into three attributes:
121
+ 1. \`layout\`: Structure & position (flex, grid, block, sticky).
122
+ 2. \`space\`: Sizing, padding, margin, gap.
123
+ 3. \`visual\`: Colors, typography, borders, shadows, effects.
124
+
125
+ ## Syntax Reference
126
+
127
+ ### 1. Layout Attribute
128
+ Controls internal flow and external positioning.
129
+ - **Flex**: \`layout="flex col center"\` (Flexbox, column direction, centered).
130
+ - **Grid**: \`layout="grid"\`
131
+ - **Position**: \`layout="absolute z:top"\`
132
+
133
+ ### 2. Space Attribute
134
+ Controls dimensions and spacing using the Natural Scale.
135
+ - **Syntax**: \`[breakpoint]:[property]:[scale]\`
136
+ - **Properties**: \`p\` (padding), \`m\` (margin), \`g\` (gap), \`w\` (width), \`h\` (height).
137
+ - **Values**:
138
+ - \`none\` (0px)
139
+ - \`thin\` (1px), \`regular\` (2px), \`thick\` (3px)
140
+ - \`tiny\` (4px), \`tiny-2x\` (6px)
141
+ - \`small\` (8px), \`small-2x\` (10px), \`small-3x\` (12px), \`small-4x\` (14px)
142
+ - \`medium\` (16px), \`medium-2x\` (20px), \`medium-3x\` (24px), \`medium-4x\` (28px)
143
+ - \`large\` (32px), \`large-2x\` (36px), \`large-3x\` (40px), \`large-4x\` (44px)
144
+ - \`big\` (48px), \`big-2x\` (56px), \`big-3x\` (64px), \`big-4x\` (80px)
145
+ - \`giant\` (96px), \`giant-2x\` (112px), \`giant-3x\` (128px), \`giant-4x\` (144px)
146
+ - \`vast\` (160px), \`vast-2x\` (176px), \`vast-3x\` (192px), \`vast-4x\` (208px)
147
+ - \`vast-5x\` (224px), \`vast-6x\` (240px), \`vast-7x\` (256px), \`vast-8x\` (288px)
148
+ - \`vast-9x\` (320px), \`vast-10x\` (384px)
149
+ - **Arbitrary**: \`space="w:[350px]"\`
150
+
151
+ ### 3. Visual Attribute
152
+ Controls appearance.
153
+ - **Colors**: \`bg:primary\`, \`text:white\`, \`border:grey\`.
154
+ - **Typography**: \`font:bold\`, \`text-size:big\`.
155
+ - **Effects**: \`rounded:medium\`, \`shadow:big\`, \`opacity:[0.5]\`.
156
+
157
+ ## Modifiers
158
+
159
+ ### Responsive Prefixes
160
+ Mobile-first breakpoints:
161
+ - (default): 0px+
162
+ - \`mob:\`: 480px+ ("Large Mobile")
163
+ - \`tab:\`: 768px+ ("Tablet")
164
+ - \`lap:\`: 1024px+ ("Laptop")
165
+ - \`desk:\`: 1280px+ ("Desktop")
166
+
167
+ Example: \`space="p:small tab:p:medium lap:p:big"\`
168
+
169
+ ### State Prefixes
170
+ - \`hover:\`: \`visual="bg:primary hover:bg:primary-dark"\`
171
+ - \`focus:\`: \`visual="border:grey focus:border:brand"\`
172
+ - \`active:\`, \`disabled:\`, \`group-hover:\`
173
+ - \`dark:\`: \`visual="bg:white dark:bg:slate-900"\`
174
+
175
+ ## Configuration
176
+ Use \`senangstart.config.js\` to override defaults.
177
+ \`\`\`js
178
+ export default {
179
+ theme: {
180
+ colors: { brand: '#8B5CF6' },
181
+ spacing: { huge: '256px' }
182
+ }
183
+ }
184
+ \`\`\`
185
+ `.trim();
186
+ }
187
+
188
+ async function generate() {
189
+ console.log('Generating docs/public/llms.txt with references...\n');
190
+
191
+ const name = defaults.name;
192
+ const description = defaults.description;
193
+ const domain = defaults.homepage || 'https://bookklik-technologies.github.io/senangstart-css';
194
+ const docsUrls = `${domain}/guide`;
195
+ const apiEndpoints = '';
196
+ const repo = 'https://github.com/bookklik-technologies/senangstart-css';
197
+ const email = '';
198
+ const license = defaults.license;
199
+
200
+ let content = `# ${name}\n`;
201
+ content += `> ${description}\n\n`;
202
+
203
+ if (docsUrls) {
204
+ content += `## Docs\n`;
205
+ docsUrls.split(',').map(url => url.trim()).forEach(url => {
206
+ if (url) content += `- [Documentation](${url})\n`;
207
+ });
208
+ content += `\n`;
209
+ }
210
+
211
+ if (apiEndpoints) {
212
+ content += `## API\n`;
213
+ apiEndpoints.split(',').map(url => url.trim()).forEach(url => {
214
+ if (url) content += `- [API Endpoint](${url})\n`;
215
+ });
216
+ content += `\n`;
217
+ }
218
+
219
+ if (repo) {
220
+ content += `## Source\n`;
221
+ content += `- [Repository](${repo})\n\n`;
222
+ }
223
+
224
+ if (email) {
225
+ content += `## Contact\n`;
226
+ content += `- [Email](mailto:${email})\n`;
227
+ }
228
+
229
+ // Append Guide Content
230
+ console.log('Adding curated guide content...');
231
+ const guidesContent = getGuideContent();
232
+ if (guidesContent) {
233
+ content += `\n# Documentation Guides\n\n${guidesContent}\n`;
234
+ }
235
+
236
+ // Load and Append Definitions
237
+ const definitions = await loadDefinitions();
238
+ if (definitions.length > 0) {
239
+ content += `\n# Utility Definitions\n\n`;
240
+ // Sort by name or category?
241
+ definitions.sort((a, b) => (a.name || a.key).localeCompare(b.name || b.key));
242
+
243
+ for (const def of definitions) {
244
+ content += formatDefinition(def.key, def);
245
+ }
246
+ }
247
+
248
+ // Ensure directory exists
249
+ const dir = path.dirname(OUTPUT_PATH);
250
+ if (!fs.existsSync(dir)) {
251
+ fs.mkdirSync(dir, { recursive: true });
252
+ }
253
+
254
+ fs.writeFileSync(OUTPUT_PATH, content, 'utf-8');
255
+ console.log(`\nSuccessfully generated ${OUTPUT_PATH}`);
256
+ console.log(`Included guide content and ${definitions.length} utility definitions.`);
257
+ // console.log('-----------------------------------');
258
+ // console.log(content.substring(0, 500) + '...');
259
+ // console.log('-----------------------------------');
260
+
261
+
262
+ }
263
+
264
+ generate();