@gtk-js/theme-fluent 0.0.2
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/CHANGELOG.md +15 -0
- package/build.ts +104 -0
- package/dist/dark_circular_default.css +8117 -0
- package/dist/dark_circular_round.css +8172 -0
- package/dist/dark_square_default.css +8119 -0
- package/dist/dark_square_round.css +8174 -0
- package/dist/index.ts +8 -0
- package/dist/light_circular_default.css +8113 -0
- package/dist/light_circular_round.css +8168 -0
- package/dist/light_square_default.css +8115 -0
- package/dist/light_square_round.css +8170 -0
- package/package.json +18 -0
- package/src/index.ts +73 -0
package/CHANGELOG.md
ADDED
package/build.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { compileGtkCSS } from "@gtk-js/gtk-css/compile";
|
|
2
|
+
import { mkdirSync, unlinkSync, writeFileSync } from "fs";
|
|
3
|
+
|
|
4
|
+
const upstreamDir = new URL("../../upstream/fluent-gtk-theme/src", import.meta.url).pathname;
|
|
5
|
+
const outDir = new URL("dist/", import.meta.url).pathname;
|
|
6
|
+
mkdirSync(outDir, { recursive: true });
|
|
7
|
+
|
|
8
|
+
const sassDir = `${upstreamDir}/_sass`;
|
|
9
|
+
|
|
10
|
+
const schemes = ["light", "dark"] as const;
|
|
11
|
+
const titlebuttons = ["circular", "square"] as const;
|
|
12
|
+
const windows = ["default", "round"] as const;
|
|
13
|
+
|
|
14
|
+
// Accent hex baked in by the SCSS theme() function for $theme: 'default'
|
|
15
|
+
const ACCENT_HEX: Record<"light" | "dark", { hex: string; r: number; g: number; b: number }> = {
|
|
16
|
+
light: { hex: "#1A73E8", r: 26, g: 115, b: 232 },
|
|
17
|
+
dark: { hex: "#3281EA", r: 50, g: 129, b: 234 },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Adjust .gtk-switch min-width/min-height to match native GTK layout manager.
|
|
22
|
+
*
|
|
23
|
+
* Native GTK computes: switch_width = 2 × slider_measured_width (content + margin).
|
|
24
|
+
* The upstream SCSS sets switch min-width to $small-size (22px), but the native
|
|
25
|
+
* layout manager overrides this to 2 × (12px slider + 5px margin × 2) = 44px.
|
|
26
|
+
* The switch min-height is slider_measured_height = 12px + 5px × 2 = 22px.
|
|
27
|
+
*/
|
|
28
|
+
function fixSwitchLayout(css: string): string {
|
|
29
|
+
// Match the first .gtk-switch { ... } block and fix min-width inside it.
|
|
30
|
+
// The compiled CSS has exactly one `.gtk-switch {` rule with min-width: 22px.
|
|
31
|
+
return css.replace(
|
|
32
|
+
/(\.gtk-switch\s*\{[^}]*?)min-width:\s*22px/,
|
|
33
|
+
"$1min-width: 44px;\n min-height: 22px",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Post-process compiled CSS to replace the baked-in accent hex and all
|
|
39
|
+
* rgba(R,G,B,A) derived forms with CSS custom property references.
|
|
40
|
+
* This allows the accent color to be overridden at runtime.
|
|
41
|
+
*/
|
|
42
|
+
function replaceAccentWithVar(css: string, scheme: "light" | "dark"): string {
|
|
43
|
+
const { hex, r, g, b } = ACCENT_HEX[scheme];
|
|
44
|
+
|
|
45
|
+
// Replace bare hex (case-insensitive)
|
|
46
|
+
css = css.replace(new RegExp(hex, "gi"), "var(--fluent-accent)");
|
|
47
|
+
|
|
48
|
+
// Replace rgba(R, G, B, A) derived forms → color-mix(in srgb, var(--fluent-accent) A%, transparent)
|
|
49
|
+
css = css.replace(
|
|
50
|
+
new RegExp(`rgba\\(${r},\\s*${g},\\s*${b},\\s*([\\d.]+)\\)`, "g"),
|
|
51
|
+
(_, a: string) =>
|
|
52
|
+
`color-mix(in srgb, var(--fluent-accent) ${Math.round(parseFloat(a) * 100)}%, transparent)`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return css;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const results: Record<string, string> = {};
|
|
59
|
+
|
|
60
|
+
for (const scheme of schemes) {
|
|
61
|
+
const scssEntry = `${upstreamDir}/gtk/4.0/gtk-${scheme === "light" ? "Light" : "Dark"}.scss`;
|
|
62
|
+
|
|
63
|
+
for (const titlebutton of titlebuttons) {
|
|
64
|
+
for (const win of windows) {
|
|
65
|
+
const tweaksTempContent = `
|
|
66
|
+
$panel_style: 'compact';
|
|
67
|
+
$opacity: 'default';
|
|
68
|
+
$window: '${win}';
|
|
69
|
+
$theme: 'default';
|
|
70
|
+
$blur: 'false';
|
|
71
|
+
$outline: 'true';
|
|
72
|
+
$titlebutton: '${titlebutton}';
|
|
73
|
+
`;
|
|
74
|
+
writeFileSync(`${sassDir}/_tweaks-temp.scss`, tweaksTempContent);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
let css = await compileGtkCSS(scssEntry, { scheme });
|
|
78
|
+
css = replaceAccentWithVar(css, scheme);
|
|
79
|
+
css = fixSwitchLayout(css);
|
|
80
|
+
|
|
81
|
+
const key = `${scheme}_${titlebutton}_${win}`;
|
|
82
|
+
results[key] = css;
|
|
83
|
+
process.stdout.write(` ${key}: ${css.length}b\n`);
|
|
84
|
+
} finally {
|
|
85
|
+
try {
|
|
86
|
+
unlinkSync(`${sassDir}/_tweaks-temp.scss`);
|
|
87
|
+
} catch {}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Write individual CSS files
|
|
94
|
+
for (const [key, css] of Object.entries(results)) {
|
|
95
|
+
writeFileSync(`${outDir}${key}.css`, css);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Write JS index that exports all variants as named string constants
|
|
99
|
+
const indexLines = Object.keys(results).map(
|
|
100
|
+
(key) => `export { default as ${key} } from "./${key}.css" with { type: "text" };`,
|
|
101
|
+
);
|
|
102
|
+
writeFileSync(`${outDir}index.ts`, indexLines.join("\n") + "\n");
|
|
103
|
+
|
|
104
|
+
console.log(`Built ${Object.keys(results).length} Fluent variants.`);
|