clampography 2.0.0-beta.10 → 2.0.0-beta.11
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/package.json +1 -1
- package/src/base.css +1 -1
- package/src/base.js +3 -6
- package/src/convert.js +185 -0
- package/src/extra.js +60 -28
- package/src/index.js +111 -85
- package/src/theme-plugin.js +7 -3
- package/src/themes.js +52 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clampography",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.11",
|
|
4
4
|
"description": "Fluid typography system based on CSS clamp() with optional themes and extra styles. A feature-rich alternative to Tailwind CSS Typography plugin.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
package/src/base.css
CHANGED
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
/* Time element */
|
|
253
253
|
time {
|
|
254
254
|
font-style: normal;
|
|
255
|
-
font-variant-numeric: tabular-nums;
|
|
255
|
+
font-variant-numeric: tabular-nums;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
/* --------------------------------------------------------------------------
|
package/src/base.js
CHANGED
|
@@ -144,15 +144,13 @@ export default {
|
|
|
144
144
|
"line-height": "1.5",
|
|
145
145
|
},
|
|
146
146
|
|
|
147
|
-
kbd: {
|
|
147
|
+
":where(code, kbd, samp)": {
|
|
148
148
|
"font-family": "var(--font-family-mono)",
|
|
149
149
|
"font-size": "0.875em",
|
|
150
|
-
"font-weight": "600",
|
|
151
150
|
},
|
|
152
151
|
|
|
153
|
-
|
|
154
|
-
"font-
|
|
155
|
-
"font-size": "0.875em",
|
|
152
|
+
kbd: {
|
|
153
|
+
"font-weight": "600",
|
|
156
154
|
},
|
|
157
155
|
|
|
158
156
|
data: {
|
|
@@ -331,7 +329,6 @@ export default {
|
|
|
331
329
|
"margin-top": "var(--spacing-md)",
|
|
332
330
|
"margin-bottom": "var(--spacing-md)",
|
|
333
331
|
padding: "var(--spacing-md)",
|
|
334
|
-
border: "0",
|
|
335
332
|
},
|
|
336
333
|
|
|
337
334
|
legend: {
|
package/src/convert.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts base.css to base.js format with preserved comments
|
|
5
|
+
* https://claude.ai/chat/90dedd98-3e31-4831-a620-c35d6523b836
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
9
|
+
import { resolve } from "path";
|
|
10
|
+
|
|
11
|
+
// Configuration
|
|
12
|
+
const INPUT_FILE = "base.css";
|
|
13
|
+
const OUTPUT_FILE = "base.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse CSS content into structured data
|
|
17
|
+
*/
|
|
18
|
+
function parseCSS(css) {
|
|
19
|
+
const result = {};
|
|
20
|
+
const lines = css.split("\n");
|
|
21
|
+
let currentContext = result;
|
|
22
|
+
let contextStack = [result];
|
|
23
|
+
let currentSelector = null;
|
|
24
|
+
let inAtLayer = false;
|
|
25
|
+
let buffer = "";
|
|
26
|
+
let commentBuffer = [];
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const line = lines[i].trim();
|
|
30
|
+
|
|
31
|
+
// Skip empty lines
|
|
32
|
+
if (!line) {
|
|
33
|
+
if (commentBuffer.length > 0) {
|
|
34
|
+
commentBuffer.push("");
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Capture comments
|
|
40
|
+
if (line.startsWith("/*")) {
|
|
41
|
+
const commentLines = [line];
|
|
42
|
+
while (i < lines.length && !lines[i].includes("*/")) {
|
|
43
|
+
i++;
|
|
44
|
+
commentLines.push(lines[i].trim());
|
|
45
|
+
}
|
|
46
|
+
commentBuffer.push(...commentLines);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Handle @layer
|
|
51
|
+
if (line.startsWith("@layer")) {
|
|
52
|
+
const match = line.match(/@layer\s+(\w+)/);
|
|
53
|
+
if (match) {
|
|
54
|
+
inAtLayer = true;
|
|
55
|
+
currentContext["@layer base"] = {};
|
|
56
|
+
contextStack.push(currentContext["@layer base"]);
|
|
57
|
+
currentContext = currentContext["@layer base"];
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle opening brace (new rule)
|
|
63
|
+
if (line.includes("{") && !line.includes("}")) {
|
|
64
|
+
const selector = line.replace("{", "").trim();
|
|
65
|
+
|
|
66
|
+
// Store comments before selector
|
|
67
|
+
if (commentBuffer.length > 0) {
|
|
68
|
+
currentContext[`__comment_${Object.keys(currentContext).length}`] =
|
|
69
|
+
commentBuffer.join("\n");
|
|
70
|
+
commentBuffer = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
currentContext[selector] = {};
|
|
74
|
+
contextStack.push(currentContext[selector]);
|
|
75
|
+
currentContext = currentContext[selector];
|
|
76
|
+
currentSelector = selector;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Handle closing brace
|
|
81
|
+
if (line === "}") {
|
|
82
|
+
contextStack.pop();
|
|
83
|
+
currentContext = contextStack[contextStack.length - 1];
|
|
84
|
+
currentSelector = null;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle properties
|
|
89
|
+
if (line.includes(":") && currentSelector) {
|
|
90
|
+
let [prop, ...valueParts] = line.split(":");
|
|
91
|
+
let value = valueParts.join(":").trim();
|
|
92
|
+
|
|
93
|
+
// Remove semicolon and inline comments
|
|
94
|
+
const inlineComment = value.match(/\/\*.*?\*\//);
|
|
95
|
+
if (inlineComment) {
|
|
96
|
+
value = value.replace(inlineComment[0], "").trim();
|
|
97
|
+
}
|
|
98
|
+
value = value.replace(";", "").trim();
|
|
99
|
+
|
|
100
|
+
prop = prop.trim();
|
|
101
|
+
|
|
102
|
+
// Store inline comment separately if exists
|
|
103
|
+
if (inlineComment && inlineComment[0]) {
|
|
104
|
+
currentContext[`__inline_comment_${prop}`] = inlineComment[0];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
currentContext[prop] = value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Convert parsed CSS to JS object string
|
|
116
|
+
*/
|
|
117
|
+
function toJSObject(obj, indent = 0) {
|
|
118
|
+
const spaces = " ".repeat(indent);
|
|
119
|
+
const lines = [];
|
|
120
|
+
|
|
121
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
122
|
+
// Handle comments
|
|
123
|
+
if (key.startsWith("__comment_")) {
|
|
124
|
+
const comment = value.split("\n").map((line) => `${spaces}${line}`).join(
|
|
125
|
+
"\n",
|
|
126
|
+
);
|
|
127
|
+
lines.push(comment);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (key.startsWith("__inline_comment_")) {
|
|
132
|
+
continue; // Skip inline comments in first pass
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
136
|
+
// It's a nested object (selector)
|
|
137
|
+
lines.push(`${spaces}"${key}": {`);
|
|
138
|
+
lines.push(toJSObject(value, indent + 1));
|
|
139
|
+
lines.push(`${spaces}},`);
|
|
140
|
+
} else {
|
|
141
|
+
// It's a property
|
|
142
|
+
const formattedValue = value.includes('"') || value.includes("'")
|
|
143
|
+
? `"${value.replace(/"/g, '\\"')}"`
|
|
144
|
+
: `"${value}"`;
|
|
145
|
+
|
|
146
|
+
// Check for inline comment
|
|
147
|
+
const inlineCommentKey = `__inline_comment_${key}`;
|
|
148
|
+
const inlineComment = obj[inlineCommentKey];
|
|
149
|
+
const comment = inlineComment ? ` ${inlineComment}` : "";
|
|
150
|
+
|
|
151
|
+
lines.push(`${spaces}"${key}": ${formattedValue},${comment}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return lines.join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Main conversion function
|
|
160
|
+
*/
|
|
161
|
+
function convertCSStoJS(cssContent) {
|
|
162
|
+
const parsed = parseCSS(cssContent);
|
|
163
|
+
const jsContent = `export default {\n${
|
|
164
|
+
toJSObject(parsed["@layer base"] || parsed, 1)
|
|
165
|
+
}\n};\n`;
|
|
166
|
+
return jsContent;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Main execution
|
|
170
|
+
try {
|
|
171
|
+
console.log(`📖 Reading ${INPUT_FILE}...`);
|
|
172
|
+
const cssContent = readFileSync(resolve(INPUT_FILE), "utf-8");
|
|
173
|
+
|
|
174
|
+
console.log("⚙️ Converting CSS to JS...");
|
|
175
|
+
const jsContent = convertCSStoJS(cssContent);
|
|
176
|
+
|
|
177
|
+
console.log(`💾 Writing ${OUTPUT_FILE}...`);
|
|
178
|
+
writeFileSync(resolve(OUTPUT_FILE), jsContent, "utf-8");
|
|
179
|
+
|
|
180
|
+
console.log("✅ Conversion complete!");
|
|
181
|
+
console.log(`📄 Output: ${OUTPUT_FILE}`);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error("❌ Error:", error.message);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
package/src/extra.js
CHANGED
|
@@ -2,63 +2,79 @@
|
|
|
2
2
|
* Extra opinionated styles and coloring.
|
|
3
3
|
* Applies colors to the structural base elements.
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
export default {
|
|
6
7
|
// --- Basic Coloring (Applying theme variables) ---
|
|
7
|
-
|
|
8
8
|
"body": {
|
|
9
|
-
"background-color": "var(--clampography-background)",
|
|
10
|
-
"color": "var(--clampography-text)",
|
|
9
|
+
"background-color": "oklch(var(--clampography-background))",
|
|
10
|
+
"color": "oklch(var(--clampography-text))",
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
":where(h1, h2, h3, h4, h5, h6)": {
|
|
14
|
-
"color": "var(--clampography-heading)",
|
|
14
|
+
"color": "oklch(var(--clampography-heading))",
|
|
15
15
|
},
|
|
16
16
|
|
|
17
17
|
"a": {
|
|
18
|
-
"color": "var(--clampography-link)",
|
|
18
|
+
"color": "oklch(var(--clampography-link))",
|
|
19
19
|
},
|
|
20
20
|
|
|
21
21
|
// Lists
|
|
22
22
|
"ul > li::before": {
|
|
23
|
-
"background-color": "var(--clampography-primary)", // Bullet points
|
|
23
|
+
"background-color": "oklch(var(--clampography-primary))", // Bullet points
|
|
24
24
|
},
|
|
25
25
|
|
|
26
26
|
"ol > li::before": {
|
|
27
|
-
"color": "var(--clampography-secondary)", // Numbers
|
|
27
|
+
"color": "oklch(var(--clampography-secondary))", // Numbers
|
|
28
28
|
},
|
|
29
29
|
|
|
30
30
|
// Inline Code
|
|
31
31
|
":where(code, kbd, samp)": {
|
|
32
|
-
"background-color": "var(--clampography-surface)",
|
|
33
|
-
"color": "var(--clampography-heading)",
|
|
34
|
-
"border": "1px solid var(--clampography-border)",
|
|
32
|
+
"background-color": "oklch(var(--clampography-surface))",
|
|
33
|
+
"color": "oklch(var(--clampography-heading))",
|
|
34
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
35
35
|
"border-radius": "0.25rem",
|
|
36
|
+
"padding": "0.125rem var(--spacing-xs)",
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Keyboard input - vertical alignment
|
|
40
|
+
"kbd": {
|
|
41
|
+
transform: "translateY(-0.15em)",
|
|
36
42
|
},
|
|
37
43
|
|
|
38
44
|
// Preformatted Code Blocks
|
|
39
45
|
"pre": {
|
|
40
|
-
"background-color": "var(--clampography-surface)",
|
|
41
|
-
"border": "1px solid var(--clampography-border)",
|
|
46
|
+
"background-color": "oklch(var(--clampography-surface))",
|
|
47
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
42
48
|
"border-radius": "0.375rem",
|
|
43
49
|
"padding": "1rem",
|
|
44
50
|
},
|
|
45
51
|
|
|
46
52
|
// Tables
|
|
53
|
+
"table": {
|
|
54
|
+
"padding": "var(--spacing-sm)",
|
|
55
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
56
|
+
},
|
|
57
|
+
|
|
47
58
|
"th": {
|
|
48
|
-
"color": "var(--clampography-heading)",
|
|
59
|
+
"color": "oklch(var(--clampography-heading))",
|
|
49
60
|
},
|
|
50
61
|
|
|
51
62
|
"th, td": {
|
|
52
|
-
"border
|
|
63
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
53
64
|
},
|
|
54
65
|
|
|
55
66
|
"thead th": {
|
|
56
67
|
"border-bottom-width": "2px",
|
|
57
68
|
},
|
|
58
69
|
|
|
70
|
+
// Zebra striping for table rows
|
|
71
|
+
"tbody tr:nth-child(even)": {
|
|
72
|
+
"background-color": "oklch(var(--clampography-surface))",
|
|
73
|
+
},
|
|
74
|
+
|
|
59
75
|
// Captions & Muted text
|
|
60
76
|
"caption, figcaption, .muted": {
|
|
61
|
-
"color": "var(--clampography-muted)",
|
|
77
|
+
"color": "oklch(var(--clampography-muted))",
|
|
62
78
|
},
|
|
63
79
|
|
|
64
80
|
// Horizontal Rule (Thematic)
|
|
@@ -67,7 +83,7 @@ export default {
|
|
|
67
83
|
"border-width": "0",
|
|
68
84
|
"margin-top": "3rem",
|
|
69
85
|
"margin-bottom": "3rem",
|
|
70
|
-
"background-color": "var(--clampography-border)",
|
|
86
|
+
"background-color": "oklch(var(--clampography-border))",
|
|
71
87
|
},
|
|
72
88
|
|
|
73
89
|
// --- Opinionated Extras ---
|
|
@@ -75,12 +91,12 @@ export default {
|
|
|
75
91
|
// Styled Blockquote
|
|
76
92
|
"blockquote": {
|
|
77
93
|
"border-left-width": "4px",
|
|
78
|
-
"border-left-color": "var(--clampography-primary)",
|
|
79
|
-
"background-color": "var(--clampography-surface)",
|
|
94
|
+
"border-left-color": "oklch(var(--clampography-primary))",
|
|
95
|
+
"background-color": "oklch(var(--clampography-surface))",
|
|
80
96
|
"padding": "1rem",
|
|
81
97
|
"border-radius": "0.25rem",
|
|
82
98
|
"font-style": "italic",
|
|
83
|
-
"color": "var(--clampography-heading)",
|
|
99
|
+
"color": "oklch(var(--clampography-heading))",
|
|
84
100
|
},
|
|
85
101
|
|
|
86
102
|
// Styled Links (Enhanced)
|
|
@@ -95,44 +111,60 @@ export default {
|
|
|
95
111
|
},
|
|
96
112
|
|
|
97
113
|
"a:hover": {
|
|
98
|
-
"text-decoration-color": "var(--clampography-primary)",
|
|
114
|
+
"text-decoration-color": "oklch(var(--clampography-primary))",
|
|
99
115
|
},
|
|
100
116
|
|
|
101
117
|
// Mark
|
|
102
118
|
"mark": {
|
|
103
|
-
"background-color": "var(--clampography-primary)",
|
|
104
|
-
"color": "var(--clampography-background)",
|
|
119
|
+
"background-color": "oklch(var(--clampography-primary))",
|
|
120
|
+
"color": "oklch(var(--clampography-background))",
|
|
121
|
+
"padding": "0.125rem var(--spacing-xs)",
|
|
122
|
+
"border-radius": "0.25rem",
|
|
105
123
|
},
|
|
106
124
|
|
|
107
125
|
// Deleted Text
|
|
108
126
|
"del": {
|
|
109
|
-
"text-decoration-color": "var(--clampography-secondary)",
|
|
127
|
+
"text-decoration-color": "oklch(var(--clampography-secondary))",
|
|
110
128
|
"text-decoration-thickness": "2px",
|
|
111
129
|
},
|
|
112
130
|
|
|
131
|
+
// Buttons - All types
|
|
132
|
+
":where(button, [type='button'], [type='reset'], [type='submit'])": {
|
|
133
|
+
"padding": "var(--spacing-xs) var(--spacing-sm)",
|
|
134
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
135
|
+
"border-radius": "0.375rem", // ← Rounded corners
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// Inputs - All types
|
|
139
|
+
":where(input:not([type='checkbox'], [type='radio']), textarea, select)": {
|
|
140
|
+
"padding": "var(--spacing-xs) var(--spacing-sm)",
|
|
141
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
142
|
+
"border-radius": "0.375rem", // ← Rounded corners
|
|
143
|
+
},
|
|
144
|
+
|
|
113
145
|
// Fieldset
|
|
114
146
|
"fieldset": {
|
|
115
|
-
"border": "1px solid var(--clampography-border)",
|
|
147
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
116
148
|
"border-radius": "0.375rem",
|
|
117
149
|
},
|
|
118
150
|
|
|
119
151
|
"legend": {
|
|
120
|
-
"color": "var(--clampography-heading)",
|
|
152
|
+
"color": "oklch(var(--clampography-heading))",
|
|
121
153
|
},
|
|
122
154
|
|
|
123
155
|
// Details
|
|
124
156
|
"details": {
|
|
125
|
-
"border": "1px solid var(--clampography-border)",
|
|
157
|
+
"border": "1px solid oklch(var(--clampography-border))",
|
|
126
158
|
"border-radius": "0.375rem",
|
|
127
159
|
"padding": "0.5rem",
|
|
128
160
|
},
|
|
129
161
|
|
|
130
162
|
"summary": {
|
|
131
|
-
"color": "var(--clampography-heading)",
|
|
163
|
+
"color": "oklch(var(--clampography-heading))",
|
|
132
164
|
},
|
|
133
165
|
|
|
134
166
|
"details[open] > summary": {
|
|
135
|
-
"border-bottom": "1px solid var(--clampography-border)",
|
|
167
|
+
"border-bottom": "1px solid oklch(var(--clampography-border))",
|
|
136
168
|
"padding-bottom": "0.5rem",
|
|
137
169
|
},
|
|
138
170
|
};
|
package/src/index.js
CHANGED
|
@@ -16,94 +16,120 @@ const resolveBool = (value, defaultValue) => {
|
|
|
16
16
|
/**
|
|
17
17
|
* Main plugin function.
|
|
18
18
|
*/
|
|
19
|
-
export default plugin.withOptions(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (configThemes
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
export default plugin.withOptions(
|
|
20
|
+
(options = {}) => {
|
|
21
|
+
return ({ addBase }) => {
|
|
22
|
+
// 1. Load Base and Extra styles
|
|
23
|
+
// We use the helper to correctly parse "false" string from CSS
|
|
24
|
+
const includeBase = resolveBool(options.base, true); // Default: true
|
|
25
|
+
const includeExtra = resolveBool(options.extra, false); // Default: false
|
|
26
|
+
|
|
27
|
+
includeBase && addBase(baseStyles);
|
|
28
|
+
includeExtra && addBase(extraStyles);
|
|
29
|
+
|
|
30
|
+
// 2. Parse themes configuration
|
|
31
|
+
let configThemes = options.themes;
|
|
32
|
+
let themesToInclude = [];
|
|
33
|
+
let defaultThemeName = null;
|
|
34
|
+
let prefersDarkTheme = false;
|
|
35
|
+
let rootSelector = options.root ?? ":root";
|
|
36
|
+
|
|
37
|
+
// Normalize input to an array of strings
|
|
38
|
+
let rawThemeList = [];
|
|
39
|
+
|
|
40
|
+
if (typeof configThemes === "string") {
|
|
41
|
+
if (["all", "true", "yes"].includes(configThemes.trim())) {
|
|
42
|
+
// Special case: themes: all
|
|
43
|
+
rawThemeList = Object.keys(builtInThemes);
|
|
44
|
+
} else if (["false", "none", "no"].includes(configThemes.trim())) {
|
|
45
|
+
// Explicitly disabled themes
|
|
46
|
+
rawThemeList = [];
|
|
47
|
+
} else {
|
|
48
|
+
rawThemeList = configThemes.split(",");
|
|
49
|
+
}
|
|
50
|
+
} else if (Array.isArray(configThemes)) {
|
|
51
|
+
rawThemeList = configThemes;
|
|
46
52
|
} else {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
rawThemeList = configThemes;
|
|
51
|
-
} else {
|
|
52
|
-
// Default behavior: NO themes loaded automatically.
|
|
53
|
-
// User must specify themes to load them.
|
|
54
|
-
rawThemeList = [];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 3. Process the list and look for flags (--default, --prefersdark)
|
|
58
|
-
rawThemeList.forEach((rawItem) => {
|
|
59
|
-
let themeName = rawItem.trim();
|
|
60
|
-
|
|
61
|
-
// Ignore empty entries
|
|
62
|
-
if (!themeName) return;
|
|
63
|
-
|
|
64
|
-
// Check for --default flag
|
|
65
|
-
if (themeName.includes("--default")) {
|
|
66
|
-
themeName = themeName.replace("--default", "").trim();
|
|
67
|
-
defaultThemeName = themeName;
|
|
53
|
+
// Default behavior: NO themes loaded automatically.
|
|
54
|
+
// User must specify themes to load them.
|
|
55
|
+
rawThemeList = [];
|
|
68
56
|
}
|
|
69
57
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
themeName =
|
|
73
|
-
|
|
58
|
+
// 3. Process the list and look for flags (--default, --prefersdark)
|
|
59
|
+
rawThemeList.forEach((rawItem) => {
|
|
60
|
+
let themeName = rawItem.trim();
|
|
61
|
+
|
|
62
|
+
// Ignore empty entries
|
|
63
|
+
if (!themeName) return;
|
|
64
|
+
|
|
65
|
+
// Check for --default flag
|
|
66
|
+
if (themeName.includes("--default")) {
|
|
67
|
+
themeName = themeName.replace("--default", "").trim();
|
|
68
|
+
defaultThemeName = themeName;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for --prefersdark flag
|
|
72
|
+
if (themeName.toLowerCase().includes("--prefersdark")) {
|
|
73
|
+
themeName = themeName.replace(/--prefersdark/i, "").trim();
|
|
74
|
+
prefersDarkTheme = themeName;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if theme exists in the database
|
|
78
|
+
if (builtInThemes[themeName]) {
|
|
79
|
+
themesToInclude.push(themeName);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// If list is empty after filtering, stop here
|
|
84
|
+
if (
|
|
85
|
+
themesToInclude.length === 0 && !defaultThemeName && !prefersDarkTheme
|
|
86
|
+
) return;
|
|
87
|
+
|
|
88
|
+
// 4. Generate CSS
|
|
89
|
+
const themeStyles = {};
|
|
90
|
+
|
|
91
|
+
// A. Default theme (:root)
|
|
92
|
+
if (defaultThemeName && builtInThemes[defaultThemeName]) {
|
|
93
|
+
themeStyles[rootSelector] = builtInThemes[defaultThemeName];
|
|
74
94
|
}
|
|
75
95
|
|
|
76
|
-
//
|
|
77
|
-
if (builtInThemes[
|
|
78
|
-
|
|
96
|
+
// B. Theme for prefers-color-scheme: dark
|
|
97
|
+
if (prefersDarkTheme && builtInThemes[prefersDarkTheme]) {
|
|
98
|
+
themeStyles["@media (prefers-color-scheme: dark)"] = {
|
|
99
|
+
[rootSelector]: builtInThemes[prefersDarkTheme],
|
|
100
|
+
};
|
|
79
101
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
102
|
+
|
|
103
|
+
// C. Scoped styles [data-theme="..."]
|
|
104
|
+
themesToInclude.forEach((themeName) => {
|
|
105
|
+
themeStyles[`[data-theme="${themeName}"]`] = builtInThemes[themeName];
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
addBase(themeStyles);
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
// Theme extension - enables utilities like bg-surface, text-heading, etc.
|
|
112
|
+
(options = {}) => {
|
|
113
|
+
return {
|
|
114
|
+
theme: {
|
|
115
|
+
extend: {
|
|
116
|
+
colors: {
|
|
117
|
+
background: "oklch(var(--clampography-background) / <alpha-value>)",
|
|
118
|
+
border: "oklch(var(--clampography-border) / <alpha-value>)",
|
|
119
|
+
error: "oklch(var(--clampography-error) / <alpha-value>)",
|
|
120
|
+
heading: "oklch(var(--clampography-heading) / <alpha-value>)",
|
|
121
|
+
info: "oklch(var(--clampography-info) / <alpha-value>)",
|
|
122
|
+
link: "oklch(var(--clampography-link) / <alpha-value>)",
|
|
123
|
+
muted: "oklch(var(--clampography-muted) / <alpha-value>)",
|
|
124
|
+
primary: "oklch(var(--clampography-primary) / <alpha-value>)",
|
|
125
|
+
secondary: "oklch(var(--clampography-secondary) / <alpha-value>)",
|
|
126
|
+
success: "oklch(var(--clampography-success) / <alpha-value>)",
|
|
127
|
+
surface: "oklch(var(--clampography-surface) / <alpha-value>)",
|
|
128
|
+
text: "oklch(var(--clampography-text) / <alpha-value>)",
|
|
129
|
+
warning: "oklch(var(--clampography-warning) / <alpha-value>)",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
);
|
package/src/theme-plugin.js
CHANGED
|
@@ -27,14 +27,18 @@ export default plugin.withOptions((options = {}) => {
|
|
|
27
27
|
// Mapping of simplified keys to full CSS variable names
|
|
28
28
|
const keyMap = {
|
|
29
29
|
"background": "--clampography-background",
|
|
30
|
-
"surface": "--clampography-surface",
|
|
31
30
|
"border": "--clampography-border",
|
|
31
|
+
"error": "--clampography-error",
|
|
32
32
|
"heading": "--clampography-heading",
|
|
33
|
-
"
|
|
34
|
-
"muted": "--clampography-muted",
|
|
33
|
+
"info": "--clampography-info",
|
|
35
34
|
"link": "--clampography-link",
|
|
35
|
+
"muted": "--clampography-muted",
|
|
36
36
|
"primary": "--clampography-primary",
|
|
37
37
|
"secondary": "--clampography-secondary",
|
|
38
|
+
"success": "--clampography-success",
|
|
39
|
+
"surface": "--clampography-surface",
|
|
40
|
+
"text": "--clampography-text",
|
|
41
|
+
"warning": "--clampography-warning",
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
// First, populate with fallback colors
|
package/src/themes.js
CHANGED
|
@@ -1,51 +1,67 @@
|
|
|
1
1
|
export const themes = {
|
|
2
2
|
light: {
|
|
3
3
|
"color-scheme": "light",
|
|
4
|
-
"--clampography-background": "
|
|
5
|
-
"--clampography-
|
|
6
|
-
"--clampography-
|
|
7
|
-
"--clampography-heading": "
|
|
8
|
-
"--clampography-
|
|
9
|
-
"--clampography-
|
|
10
|
-
"--clampography-
|
|
11
|
-
"--clampography-primary": "
|
|
12
|
-
"--clampography-secondary": "
|
|
4
|
+
"--clampography-background": "100% 0 0",
|
|
5
|
+
"--clampography-border": "92% 0.003 264",
|
|
6
|
+
"--clampography-error": "63% 0.22 27",
|
|
7
|
+
"--clampography-heading": "15% 0.02 264",
|
|
8
|
+
"--clampography-info": "63% 0.258 262",
|
|
9
|
+
"--clampography-link": "43% 0.19 264",
|
|
10
|
+
"--clampography-muted": "52% 0.014 258",
|
|
11
|
+
"--clampography-primary": "63% 0.258 262",
|
|
12
|
+
"--clampography-secondary": "55% 0.28 300",
|
|
13
|
+
"--clampography-success": "65% 0.17 165",
|
|
14
|
+
"--clampography-surface": "96% 0.003 264",
|
|
15
|
+
"--clampography-text": "31% 0.02 257",
|
|
16
|
+
"--clampography-warning": "72% 0.17 65",
|
|
13
17
|
},
|
|
14
18
|
dark: {
|
|
15
19
|
"color-scheme": "dark",
|
|
16
|
-
"--clampography-background": "
|
|
17
|
-
"--clampography-
|
|
18
|
-
"--clampography-
|
|
19
|
-
"--clampography-heading": "
|
|
20
|
-
"--clampography-
|
|
21
|
-
"--clampography-
|
|
22
|
-
"--clampography-
|
|
23
|
-
"--clampography-primary": "
|
|
24
|
-
"--clampography-secondary": "
|
|
20
|
+
"--clampography-background": "10% 0 0",
|
|
21
|
+
"--clampography-border": "31% 0.03 254",
|
|
22
|
+
"--clampography-error": "63% 0.22 27",
|
|
23
|
+
"--clampography-heading": "98% 0.003 264",
|
|
24
|
+
"--clampography-info": "72% 0.17 254",
|
|
25
|
+
"--clampography-link": "72% 0.17 254",
|
|
26
|
+
"--clampography-muted": "68% 0.024 254",
|
|
27
|
+
"--clampography-primary": "63% 0.258 262",
|
|
28
|
+
"--clampography-secondary": "63% 0.25 300",
|
|
29
|
+
"--clampography-success": "65% 0.17 165",
|
|
30
|
+
"--clampography-surface": "12% 0 0",
|
|
31
|
+
"--clampography-text": "95% 0 0",
|
|
32
|
+
"--clampography-warning": "72% 0.17 65",
|
|
25
33
|
},
|
|
26
34
|
retro: {
|
|
27
35
|
"color-scheme": "light",
|
|
28
|
-
"--clampography-background": "
|
|
29
|
-
"--clampography-
|
|
30
|
-
"--clampography-
|
|
31
|
-
"--clampography-heading": "
|
|
32
|
-
"--clampography-
|
|
33
|
-
"--clampography-
|
|
34
|
-
"--clampography-
|
|
35
|
-
"--clampography-primary": "
|
|
36
|
-
"--clampography-secondary": "
|
|
36
|
+
"--clampography-background": "91% 0.03 85",
|
|
37
|
+
"--clampography-border": "78% 0.05 85",
|
|
38
|
+
"--clampography-error": "52% 0.15 35",
|
|
39
|
+
"--clampography-heading": "18% 0.02 35",
|
|
40
|
+
"--clampography-info": "60% 0.06 230",
|
|
41
|
+
"--clampography-link": "63% 0.13 40",
|
|
42
|
+
"--clampography-muted": "44% 0.03 45",
|
|
43
|
+
"--clampography-primary": "60% 0.19 35",
|
|
44
|
+
"--clampography-secondary": "80% 0.14 85",
|
|
45
|
+
"--clampography-success": "62% 0.10 130",
|
|
46
|
+
"--clampography-surface": "87% 0.04 85",
|
|
47
|
+
"--clampography-text": "28% 0.03 40",
|
|
48
|
+
"--clampography-warning": "80% 0.14 85",
|
|
37
49
|
},
|
|
38
50
|
cyberpunk: {
|
|
39
51
|
"color-scheme": "dark",
|
|
40
|
-
"--clampography-background": "
|
|
41
|
-
"--clampography-
|
|
42
|
-
"--clampography-
|
|
43
|
-
"--clampography-heading": "
|
|
44
|
-
"--clampography-
|
|
45
|
-
"--clampography-
|
|
46
|
-
"--clampography-
|
|
47
|
-
"--clampography-primary": "
|
|
48
|
-
"--clampography-secondary": "
|
|
52
|
+
"--clampography-background": "8% 0.04 264",
|
|
53
|
+
"--clampography-border": "27% 0.09 254",
|
|
54
|
+
"--clampography-error": "60% 0.29 340",
|
|
55
|
+
"--clampography-heading": "100% 0 0",
|
|
56
|
+
"--clampography-info": "88% 0.16 195",
|
|
57
|
+
"--clampography-link": "60% 0.29 340",
|
|
58
|
+
"--clampography-muted": "55% 0.07 200",
|
|
59
|
+
"--clampography-primary": "93% 0.22 105",
|
|
60
|
+
"--clampography-secondary": "87% 0.20 165",
|
|
61
|
+
"--clampography-success": "87% 0.20 165",
|
|
62
|
+
"--clampography-surface": "12% 0.05 264",
|
|
63
|
+
"--clampography-text": "88% 0.16 195",
|
|
64
|
+
"--clampography-warning": "93% 0.22 105",
|
|
49
65
|
},
|
|
50
66
|
};
|
|
51
67
|
|