@bookklik/senangstart-css 0.2.4 → 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.
- package/dist/senangstart-css.js +82 -6
- package/dist/senangstart-css.min.js +24 -20
- package/dist/senangstart-tw.js +200 -52
- package/dist/senangstart-tw.min.js +1 -1
- package/docs/guide/cdn.md +1 -1
- package/docs/ms/guide/cdn.md +1 -1
- package/docs/ms/reference/layout/position.md +4 -4
- package/docs/ms/reference/layout/z-index.md +8 -8
- package/docs/ms/reference/space/gap.md +1 -1
- package/docs/ms/reference/space/height.md +1 -1
- package/docs/ms/reference/space/margin.md +1 -1
- package/docs/ms/reference/space/padding.md +1 -1
- package/docs/ms/reference/space/scale-reference.md +46 -17
- package/docs/ms/reference/space/width.md +1 -1
- package/docs/ms/reference/space.md +1 -1
- package/docs/ms/reference/spacing.md +103 -21
- package/docs/ms/reference/visual/animation-fill.md +8 -8
- package/docs/ms/reference/visual/backdrop-blur.md +4 -4
- package/docs/ms/reference/visual/backdrop-brightness.md +8 -8
- package/docs/ms/reference/visual/backdrop-grayscale.md +6 -6
- package/docs/ms/reference/visual/backdrop-sepia.md +6 -6
- package/docs/ms/reference/visual/background-clip.md +2 -2
- package/docs/ms/reference/visual/background-image.md +4 -4
- package/docs/ms/reference/visual/filter-brightness.md +4 -4
- package/docs/ms/reference/visual/filter-contrast.md +4 -4
- package/docs/ms/reference/visual/filter-drop-shadow.md +6 -6
- package/docs/ms/reference/visual/filter-grayscale.md +4 -4
- package/docs/ms/reference/visual/filter-hue-rotate.md +4 -4
- package/docs/ms/reference/visual/filter-invert.md +2 -2
- package/docs/ms/reference/visual/filter-saturate.md +4 -4
- package/docs/ms/reference/visual/filter-sepia.md +4 -4
- package/docs/ms/reference/visual/font-family.md +2 -2
- package/docs/ms/reference/visual/gradient-from.md +57 -57
- package/docs/ms/reference/visual/gradient-to.md +57 -57
- package/docs/ms/reference/visual/gradient-via.md +54 -54
- package/docs/ms/reference/visual/letter-spacing.md +2 -2
- package/docs/ms/reference/visual/line-clamp.md +2 -2
- package/docs/ms/reference/visual/line-height.md +2 -2
- package/docs/ms/reference/visual/outline.md +2 -2
- package/docs/ms/reference/visual/ring-color.md +29 -0
- package/docs/ms/reference/visual/ring-offset.md +30 -0
- package/docs/ms/reference/visual/ring.md +62 -0
- package/docs/ms/reference/visual/stroke-width.md +6 -6
- package/docs/ms/reference/visual/stroke.md +4 -4
- package/docs/ms/reference/visual/text-indent.md +2 -2
- package/docs/ms/reference/visual/text-overflow.md +2 -2
- package/docs/ms/reference/visual/text-size.md +2 -2
- package/docs/ms/reference/visual/text-wrap.md +2 -2
- package/docs/ms/reference/visual/transform-backface.md +4 -4
- package/docs/ms/reference/visual/transform-perspective-origin.md +6 -6
- package/docs/ms/reference/visual/transform-perspective.md +6 -6
- package/docs/ms/reference/visual/transform-rotate-3d.md +6 -6
- package/docs/ms/reference/visual/transform-style.md +4 -4
- package/docs/ms/reference/visual/transform-translate-z.md +6 -6
- package/docs/ms/reference/visual/transform-translate.md +2 -2
- package/docs/ms/reference/visual/whitespace.md +2 -2
- package/docs/ms/reference/visual/word-break.md +2 -2
- package/docs/public/assets/senangstart-css.min.js +24 -20
- package/docs/public/llms.txt +1718 -0
- package/docs/reference/layout/position.md +4 -4
- package/docs/reference/layout/z-index.md +8 -8
- package/docs/reference/space/gap.md +1 -1
- package/docs/reference/space/height.md +1 -1
- package/docs/reference/space/margin.md +1 -1
- package/docs/reference/space/padding.md +1 -1
- package/docs/reference/space/scale-reference.md +46 -17
- package/docs/reference/space/width.md +1 -1
- package/docs/reference/space.md +1 -1
- package/docs/reference/spacing.md +103 -21
- package/docs/reference/visual/animation-fill.md +8 -8
- package/docs/reference/visual/backdrop-blur.md +4 -4
- package/docs/reference/visual/backdrop-brightness.md +8 -8
- package/docs/reference/visual/backdrop-grayscale.md +6 -6
- package/docs/reference/visual/backdrop-sepia.md +6 -6
- package/docs/reference/visual/background-clip.md +2 -2
- package/docs/reference/visual/background-image.md +4 -4
- package/docs/reference/visual/filter-brightness.md +4 -4
- package/docs/reference/visual/filter-contrast.md +4 -4
- package/docs/reference/visual/filter-drop-shadow.md +6 -6
- package/docs/reference/visual/filter-grayscale.md +4 -4
- package/docs/reference/visual/filter-hue-rotate.md +4 -4
- package/docs/reference/visual/filter-invert.md +2 -2
- package/docs/reference/visual/filter-saturate.md +4 -4
- package/docs/reference/visual/filter-sepia.md +4 -4
- package/docs/reference/visual/font-family.md +2 -2
- package/docs/reference/visual/gradient-from.md +57 -57
- package/docs/reference/visual/gradient-to.md +57 -57
- package/docs/reference/visual/gradient-via.md +54 -54
- package/docs/reference/visual/letter-spacing.md +2 -2
- package/docs/reference/visual/line-clamp.md +2 -2
- package/docs/reference/visual/line-height.md +2 -2
- package/docs/reference/visual/outline.md +2 -2
- package/docs/reference/visual/ring-color.md +29 -0
- package/docs/reference/visual/ring-offset.md +30 -0
- package/docs/reference/visual/ring.md +62 -0
- package/docs/reference/visual/stroke-width.md +6 -6
- package/docs/reference/visual/stroke.md +4 -4
- package/docs/reference/visual/text-indent.md +2 -2
- package/docs/reference/visual/text-overflow.md +2 -2
- package/docs/reference/visual/text-size.md +2 -2
- package/docs/reference/visual/text-wrap.md +2 -2
- package/docs/reference/visual/transform-backface.md +4 -4
- package/docs/reference/visual/transform-perspective-origin.md +6 -6
- package/docs/reference/visual/transform-perspective.md +6 -6
- package/docs/reference/visual/transform-rotate-3d.md +6 -6
- package/docs/reference/visual/transform-style.md +4 -4
- package/docs/reference/visual/transform-translate-z.md +6 -6
- package/docs/reference/visual/transform-translate.md +2 -2
- package/docs/reference/visual/whitespace.md +2 -2
- package/docs/reference/visual/word-break.md +2 -2
- package/package.json +4 -2
- package/scripts/build-dist.js +2 -2
- package/scripts/bundle-jit.js +3 -3
- package/scripts/convert-tailwind.js +157 -2
- package/scripts/generate-llms-txt.js +264 -0
- package/src/cdn/{jit.js → senangstart-engine.js} +81 -11
- package/src/cdn/tw-conversion-engine.js +203 -68
- package/src/compiler/generators/css.js +27 -0
- package/src/config/defaults.js +37 -11
- package/src/core/constants.js +37 -8
- package/src/definitions/space.js +46 -5
- package/src/definitions/visual-borders.js +80 -1
- package/src/definitions/visual-transform3d.js +16 -16
- package/src/definitions/visual-transforms.js +1 -1
- package/src/definitions/visual-transitions.js +4 -4
- package/src/definitions/visual-typography.js +6 -6
- package/src/definitions/visual.js +4 -4
- package/tests/unit/compiler/generators/css.test.js +192 -0
|
@@ -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
|
// ======================
|
|
@@ -606,7 +620,148 @@ function convertClass(twClass, options = {}) {
|
|
|
606
620
|
if (toMatch) {
|
|
607
621
|
return { category: 'visual', value: prefix + "to:" + toMatch[1] };
|
|
608
622
|
}
|
|
609
|
-
|
|
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
|
+
|
|
610
765
|
return null;
|
|
611
766
|
}
|
|
612
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();
|
|
@@ -24,16 +24,42 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
|
|
|
24
24
|
const defaultConfig = {
|
|
25
25
|
theme: {
|
|
26
26
|
spacing: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
27
|
+
'none': '0px', // No space
|
|
28
|
+
'thin': '1px', // Hairline (for borders)
|
|
29
|
+
'regular': '2px', // Standard border
|
|
30
|
+
'thick': '3px', // Bold border
|
|
31
|
+
'tiny': '4px', // Small offsets
|
|
32
|
+
'tiny-2x': '6px', // Tiny multiplied
|
|
33
|
+
'small': '8px',
|
|
34
|
+
'small-2x': '10px',
|
|
35
|
+
'small-3x': '12px',
|
|
36
|
+
'small-4x': '14px',
|
|
37
|
+
'medium': '16px',
|
|
38
|
+
'medium-2x': '20px',
|
|
39
|
+
'medium-3x': '24px',
|
|
40
|
+
'medium-4x': '28px',
|
|
41
|
+
'large': '32px',
|
|
42
|
+
'large-2x': '36px',
|
|
43
|
+
'large-3x': '40px',
|
|
44
|
+
'large-4x': '44px',
|
|
45
|
+
'big': '48px',
|
|
46
|
+
'big-2x': '56px',
|
|
47
|
+
'big-3x': '64px',
|
|
48
|
+
'big-4x': '80px',
|
|
49
|
+
'giant': '96px',
|
|
50
|
+
'giant-2x': '112px',
|
|
51
|
+
'giant-3x': '128px',
|
|
52
|
+
'giant-4x': '144px',
|
|
53
|
+
'vast': '160px',
|
|
54
|
+
'vast-2x': '176px',
|
|
55
|
+
'vast-3x': '192px',
|
|
56
|
+
'vast-4x': '208px',
|
|
57
|
+
'vast-5x': '224px',
|
|
58
|
+
'vast-6x': '240px',
|
|
59
|
+
'vast-7x': '256px',
|
|
60
|
+
'vast-8x': '288px',
|
|
61
|
+
'vast-9x': '320px',
|
|
62
|
+
'vast-10x': '384px'
|
|
37
63
|
},
|
|
38
64
|
radius: {
|
|
39
65
|
'none': '0px',
|
|
@@ -205,6 +231,15 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
|
|
|
205
231
|
'mid': '50',
|
|
206
232
|
'high': '100',
|
|
207
233
|
'top': '9999'
|
|
234
|
+
},
|
|
235
|
+
ring: {
|
|
236
|
+
'none': '0px',
|
|
237
|
+
'thin': '1px',
|
|
238
|
+
'regular': '2px',
|
|
239
|
+
'thick': '3px',
|
|
240
|
+
'small': '4px',
|
|
241
|
+
'medium': '6px',
|
|
242
|
+
'big': '8px'
|
|
208
243
|
}
|
|
209
244
|
},
|
|
210
245
|
// Dark mode configuration
|
|
@@ -232,7 +267,8 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
|
|
|
232
267
|
fontWeight: { type: 'object' },
|
|
233
268
|
screens: { type: 'object' },
|
|
234
269
|
colors: { type: 'object' },
|
|
235
|
-
zIndex: { type: 'object' }
|
|
270
|
+
zIndex: { type: 'object' },
|
|
271
|
+
ring: { type: 'object' }
|
|
236
272
|
}
|
|
237
273
|
},
|
|
238
274
|
darkMode: { type: 'string', enum: ['media', 'selector'] },
|
|
@@ -358,6 +394,17 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
|
|
|
358
394
|
css += ` --z-${key}: ${value};\n`;
|
|
359
395
|
}
|
|
360
396
|
|
|
397
|
+
// Ring (focus ring utilities)
|
|
398
|
+
if (theme.ring) {
|
|
399
|
+
for (const [key, value] of Object.entries(theme.ring)) {
|
|
400
|
+
css += ` --ring-${key}: ${value};\n`;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Ring default values
|
|
404
|
+
css += ` --ring-color: var(--c-primary);\n`;
|
|
405
|
+
css += ` --ring-offset: 0px;\n`;
|
|
406
|
+
css += ` --ring-offset-color: #fff;\n`;
|
|
407
|
+
|
|
361
408
|
// ============================================
|
|
362
409
|
// TAILWIND SCALE COMPATIBILITY (tw-* prefix)
|
|
363
410
|
// ============================================
|
|
@@ -1894,6 +1941,29 @@ img, video {
|
|
|
1894
1941
|
return `outline-offset: ${cssValue};`;
|
|
1895
1942
|
},
|
|
1896
1943
|
|
|
1944
|
+
// ============================================
|
|
1945
|
+
// RING UTILITIES (Focus Ring)
|
|
1946
|
+
// ============================================
|
|
1947
|
+
'ring': () => {
|
|
1948
|
+
if (value === 'none') {
|
|
1949
|
+
return `box-shadow: 0 0 0 0 transparent;`;
|
|
1950
|
+
}
|
|
1951
|
+
const cssValue = isArbitrary ? value : `var(--ring-${value})`;
|
|
1952
|
+
return `box-shadow: 0 0 0 var(--ring-offset) var(--ring-offset-color), 0 0 0 calc(${cssValue} + var(--ring-offset)) var(--ring-color);`;
|
|
1953
|
+
},
|
|
1954
|
+
'ring-color': () => {
|
|
1955
|
+
const cssValue = isArbitrary ? value : `var(--c-${value})`;
|
|
1956
|
+
return `--ring-color: ${cssValue};`;
|
|
1957
|
+
},
|
|
1958
|
+
'ring-offset': () => {
|
|
1959
|
+
const cssValue = isArbitrary ? value : `${value}px`;
|
|
1960
|
+
return `--ring-offset: ${cssValue};`;
|
|
1961
|
+
},
|
|
1962
|
+
'ring-offset-color': () => {
|
|
1963
|
+
const cssValue = isArbitrary ? value : `var(--c-${value})`;
|
|
1964
|
+
return `--ring-offset-color: ${cssValue};`;
|
|
1965
|
+
},
|
|
1966
|
+
|
|
1897
1967
|
// ============================================
|
|
1898
1968
|
// SVG UTILITIES
|
|
1899
1969
|
// ============================================
|