@glasshome/ui 0.5.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -25
- package/dist/index.d.ts +10 -3
- package/dist/index.js +9 -9
- package/dist/lib/alert-tones.d.ts +18 -0
- package/dist/lib/badge-tone.d.ts +2 -0
- package/dist/lib/button-variants.d.ts +65 -20
- package/dist/lib/card-classes.d.ts +19 -0
- package/dist/lib/glass-tone.d.ts +2 -0
- package/dist/lib/input-classes.d.ts +2 -0
- package/dist/lib/logo-lockup.d.ts +38 -0
- package/dist/lib/overlay-classes.d.ts +2 -0
- package/dist/lib/section-tokens.d.ts +4 -0
- package/dist/lib/tier-badge.d.ts +13 -0
- package/dist/solid/alert-dialog.d.ts +1 -3
- package/dist/solid/alert.d.ts +2 -11
- package/dist/solid/badge.d.ts +11 -22
- package/dist/solid/bottom-sheet/bottom-sheet.d.ts +1 -1
- package/dist/solid/bottom-sheet/constants.d.ts +0 -1
- package/dist/solid/bottom-sheet/drag-controller.d.ts +1 -1
- package/dist/solid/bottom-sheet/index.d.ts +1 -2
- package/dist/solid/breadcrumb.d.ts +1 -1
- package/dist/solid/button-group.d.ts +29 -11
- package/dist/solid/button.d.ts +1 -1
- package/dist/solid/card.d.ts +10 -2
- package/dist/solid/carousel.d.ts +1 -1
- package/dist/solid/charts.d.ts +45 -0
- package/dist/solid/count-pill.d.ts +10 -0
- package/dist/solid/data-table.d.ts +66 -0
- package/dist/solid/dock.d.ts +3 -0
- package/dist/solid/empty.d.ts +27 -9
- package/dist/solid/entity-data.d.ts +52 -0
- package/dist/solid/field.d.ts +31 -10
- package/dist/solid/form.d.ts +1 -1
- package/dist/solid/index.d.ts +74 -64
- package/dist/solid/index.js +11095 -10919
- package/dist/solid/input-group.d.ts +67 -19
- package/dist/solid/item.d.ts +77 -21
- package/dist/solid/logo.d.ts +23 -0
- package/dist/solid/number-field.d.ts +3 -0
- package/dist/solid/overlay.d.ts +3 -0
- package/dist/solid/page-header.d.ts +18 -0
- package/dist/solid/popover.d.ts +7 -1
- package/dist/solid/scope-indicator.d.ts +8 -0
- package/dist/solid/section-card.d.ts +54 -0
- package/dist/solid/select.d.ts +1 -18
- package/dist/solid/settings-row.d.ts +34 -0
- package/dist/solid/sliding-indicator.d.ts +32 -0
- package/dist/solid/sonner.d.ts +35 -4
- package/dist/solid/spinner.d.ts +2 -1
- package/dist/solid/switch.d.ts +1 -1
- package/dist/solid/toggle-group.d.ts +1 -1
- package/dist/solid/toggle.d.ts +44 -10
- package/dist/solid/widget-card.d.ts +29 -0
- package/dist/solid/widget-identity.d.ts +47 -0
- package/dist/solid/widget-trust-badge.d.ts +16 -0
- package/dist/tokens/index.d.ts +3 -3
- package/dist/tokens/index.js +11 -11
- package/dist/tokens/presets.d.ts +1 -1
- package/dist/utils-gbdcvo14.js +1910 -0
- package/package.json +38 -17
- package/scripts/check-tokens.ts +60 -0
- package/scripts/check-ui-drift.mjs +116 -0
- package/src/astro/Alert.astro +63 -0
- package/src/astro/Badge.astro +16 -0
- package/src/astro/Button.astro +43 -0
- package/src/astro/Card.astro +39 -0
- package/src/astro/Logo.astro +69 -0
- package/src/astro/TierBadge.astro +33 -0
- package/src/styles/globals.css +157 -0
- package/src/styles/theme.css +68 -12
- package/dist/solid/calendar.d.ts +0 -17
- package/dist/solid/command.d.ts +0 -24
- package/dist/solid/drawer.d.ts +0 -22
- package/dist/solid/glass-effect.d.ts +0 -6
- package/dist/solid/menubar.d.ts +0 -25
- package/dist/solid/navigation-menu.d.ts +0 -20
- package/dist/solid/sidebar.d.ts +0 -74
- package/dist/utils-BRD6YbhO.js +0 -1803
package/package.json
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glasshome/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "SolidJS component library for GlassHome, built on Kobalte",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
6
|
"homepage": "https://github.com/glasshome/ui#readme",
|
|
9
7
|
"bugs": {
|
|
10
8
|
"url": "https://github.com/glasshome/ui/issues"
|
|
@@ -13,9 +11,11 @@
|
|
|
13
11
|
"access": "public"
|
|
14
12
|
},
|
|
15
13
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
14
|
+
"node": ">=20"
|
|
17
15
|
},
|
|
18
|
-
"sideEffects":
|
|
16
|
+
"sideEffects": [
|
|
17
|
+
"**/*.css"
|
|
18
|
+
],
|
|
19
19
|
"keywords": [
|
|
20
20
|
"solidjs",
|
|
21
21
|
"components",
|
|
@@ -42,23 +42,34 @@
|
|
|
42
42
|
"types": "./dist/tokens/index.d.ts",
|
|
43
43
|
"import": "./dist/tokens/index.js"
|
|
44
44
|
},
|
|
45
|
+
"./astro/*": "./src/astro/*",
|
|
45
46
|
"./styles": "./src/styles/globals.css",
|
|
46
47
|
"./package.json": "./package.json",
|
|
47
|
-
"./styles/theme": "./src/styles/theme.css"
|
|
48
|
+
"./styles/theme": "./src/styles/theme.css",
|
|
49
|
+
"./scripts/*": "./scripts/*"
|
|
48
50
|
},
|
|
49
51
|
"files": [
|
|
50
52
|
"dist",
|
|
51
|
-
"src/
|
|
53
|
+
"src/astro",
|
|
54
|
+
"src/styles",
|
|
55
|
+
"scripts"
|
|
52
56
|
],
|
|
53
57
|
"scripts": {
|
|
54
58
|
"build": "vite build && tsc",
|
|
55
59
|
"check:tokens": "bun scripts/check-tokens.ts",
|
|
60
|
+
"check:types": "tsc --noEmit -p tsconfig.test.json",
|
|
61
|
+
"check:publish": "publint && attw --pack . --profile esm-only --exclude-entrypoints ./styles ./styles/theme",
|
|
56
62
|
"dev": "vite build --watch",
|
|
57
|
-
"lint": "biome check ."
|
|
63
|
+
"lint": "biome check .",
|
|
64
|
+
"test": "vitest run",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"dev:gallery": "vite --config vite.dev.config.ts"
|
|
58
67
|
},
|
|
59
68
|
"peerDependencies": {
|
|
60
|
-
"
|
|
61
|
-
"solid-js": "^1.9.9"
|
|
69
|
+
"astro": ">=4",
|
|
70
|
+
"solid-js": "^1.9.9",
|
|
71
|
+
"tailwindcss": "^4.1.13",
|
|
72
|
+
"tw-animate-css": "^1.4.0"
|
|
62
73
|
},
|
|
63
74
|
"dependencies": {
|
|
64
75
|
"@iconify-icon/solid": "^3.0.3",
|
|
@@ -66,24 +77,34 @@
|
|
|
66
77
|
"clsx": "^2.1.1",
|
|
67
78
|
"cva": "^1.0.0-beta.4",
|
|
68
79
|
"embla-carousel": "^8.5.1",
|
|
69
|
-
"lucide-solid": "^1.21.0",
|
|
70
80
|
"solid-sonner": "^0.3.1",
|
|
71
|
-
"tailwind-merge": "^3.4.0"
|
|
72
|
-
"tailwindcss": "^4.1.13",
|
|
73
|
-
"tw-animate-css": "^1.4.0"
|
|
81
|
+
"tailwind-merge": "^3.4.0"
|
|
74
82
|
},
|
|
75
83
|
"devDependencies": {
|
|
84
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
85
|
+
"@biomejs/biome": "2.4.15",
|
|
86
|
+
"@solidjs/testing-library": "^0.8.10",
|
|
87
|
+
"@tailwindcss/vite": "^4.1.13",
|
|
76
88
|
"@types/json-schema": "^7.0.15",
|
|
77
89
|
"@types/node": "^25.2.2",
|
|
90
|
+
"happy-dom": "^20.11.0",
|
|
91
|
+
"publint": "^0.3.21",
|
|
92
|
+
"tailwindcss": "^4.1.13",
|
|
93
|
+
"tw-animate-css": "^1.4.0",
|
|
78
94
|
"typescript": "^5",
|
|
79
95
|
"vite": "^8.1.0",
|
|
80
96
|
"vite-plugin-solid": "^2.11.12",
|
|
81
|
-
"
|
|
97
|
+
"vitest": "^4.1.10"
|
|
82
98
|
},
|
|
83
99
|
"repository": {
|
|
84
100
|
"type": "git",
|
|
85
|
-
"url": "https://github.com/glasshome/ui.git"
|
|
101
|
+
"url": "git+https://github.com/glasshome/ui.git"
|
|
86
102
|
},
|
|
87
103
|
"author": "GlassHome Labs",
|
|
88
|
-
"license": "MIT"
|
|
104
|
+
"license": "MIT",
|
|
105
|
+
"peerDependenciesMeta": {
|
|
106
|
+
"astro": {
|
|
107
|
+
"optional": true
|
|
108
|
+
}
|
|
109
|
+
}
|
|
89
110
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Fails when styles/theme.css and tokens/presets.ts (midnight-glass) drift.
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { DEFAULT_THEME_ID, getPreset, type ThemeColors } from "../src/tokens";
|
|
5
|
+
|
|
6
|
+
const css = readFileSync(
|
|
7
|
+
path.resolve(path.dirname(new URL(import.meta.url).pathname), "../src/styles/theme.css"),
|
|
8
|
+
"utf8",
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const KEYS: Record<string, keyof ThemeColors> = {
|
|
12
|
+
"--primary": "primary",
|
|
13
|
+
"--accent": "accent",
|
|
14
|
+
"--secondary": "secondary",
|
|
15
|
+
"--border": "border",
|
|
16
|
+
"--card": "card",
|
|
17
|
+
"--background": "background",
|
|
18
|
+
"--muted": "muted",
|
|
19
|
+
"--muted-foreground": "mutedForeground",
|
|
20
|
+
"--input": "input",
|
|
21
|
+
"--ring": "ring",
|
|
22
|
+
"--destructive": "destructive",
|
|
23
|
+
"--popover": "popover",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function cssVars(block: string): Record<string, string> {
|
|
27
|
+
const match = css.match(new RegExp(`${block}\\s*\\{([^}]*)\\}`));
|
|
28
|
+
if (!match) throw new Error(`block not found in theme.css: ${block}`);
|
|
29
|
+
const vars: Record<string, string> = {};
|
|
30
|
+
for (const line of match[1].split("\n")) {
|
|
31
|
+
const m = line.match(/^\s*(--[\w-]+):\s*(.+?);\s*$/);
|
|
32
|
+
if (m) vars[m[1]] = m[2];
|
|
33
|
+
}
|
|
34
|
+
return vars;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const preset = getPreset(DEFAULT_THEME_ID);
|
|
38
|
+
if (!preset) throw new Error(`preset missing: ${DEFAULT_THEME_ID}`);
|
|
39
|
+
|
|
40
|
+
let drift = 0;
|
|
41
|
+
for (const [mode, block] of [
|
|
42
|
+
["light", ":root"],
|
|
43
|
+
["dark", ".dark"],
|
|
44
|
+
] as const) {
|
|
45
|
+
const vars = cssVars(block);
|
|
46
|
+
for (const [cssKey, tokenKey] of Object.entries(KEYS)) {
|
|
47
|
+
const cssValue = vars[cssKey];
|
|
48
|
+
const tokenValue = preset.colors[mode][tokenKey];
|
|
49
|
+
if (cssValue !== tokenValue) {
|
|
50
|
+
console.error(`${mode} ${cssKey}: css="${cssValue}" tokens="${tokenValue}"`);
|
|
51
|
+
drift++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (drift > 0) {
|
|
57
|
+
console.error(`${drift} token(s) drifted between theme.css and tokens/presets.ts`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
console.log("theme.css and tokens/presets.ts in sync");
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Deny-by-default UI drift guard, shared by hub and dash. Glass, panels,
|
|
2
|
+
// pills, and callouts must come from @glasshome/ui (see SPEC.md); this scans
|
|
3
|
+
// app markup for the raw idioms those primitives replace.
|
|
4
|
+
//
|
|
5
|
+
// Escape hatch: `ui-drift-ok <reason>` in a comment on the line or the line
|
|
6
|
+
// above. SKIP_UI_DRIFT_CHECK=1 skips entirely.
|
|
7
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
const RULES = [
|
|
11
|
+
[
|
|
12
|
+
"hand-rolled blur",
|
|
13
|
+
/(?:backdrop-blur(?:-\w+|-\[[^\]]+\])?|backdrop-filter)/,
|
|
14
|
+
"blur belongs to the material: use <Card>/CARD_BLUR, OVERLAY_SURFACE, SCRIM_CLASS, or TRACK_SURFACE",
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
"hand-rolled surface fill",
|
|
18
|
+
/\b(?<!hover:)(?<!focus:)(?<!active:)(?<!group-hover:)bg-(?:card|background|popover)\/\d+/,
|
|
19
|
+
"translucent surface fills come from <Card>, <Overlay>, or a --glass-base knob",
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"bespoke pill",
|
|
23
|
+
/rounded-full[^"'`]*\bborder\b[^"'`]*bg-(?:card|background)\b/,
|
|
24
|
+
'use <Badge tone> or <Button size="none">',
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
"raw palette color",
|
|
28
|
+
/\b(?:bg|text|border)-(?:amber|green|yellow|red|blue|orange|emerald|rose|sky)-\d{3}\b/,
|
|
29
|
+
"use theme vars: var(--success)/var(--warning)/var(--destructive) via <Badge>/<Alert>",
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
"tinted callout",
|
|
33
|
+
/border-(?:primary|destructive|warning|success)\/\d+[^"'`]*bg-(?:primary|destructive|warning|success)\/\d+/,
|
|
34
|
+
"use <Alert tone> (Solid or astro) or ALERT_TONES",
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
"shadcn field chrome",
|
|
38
|
+
/border-input\s[^"'`]*bg-(?:background|transparent)\b/,
|
|
39
|
+
"use INPUT_CLASS / INPUT_SURFACE / FIELD_CHROME from @glasshome/ui",
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"solid badge",
|
|
43
|
+
/border-transparent\s+bg-primary\s+text-primary-foreground/,
|
|
44
|
+
"use <Badge tone> — there are no solid badge variants",
|
|
45
|
+
],
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
function walk(dir) {
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const name of readdirSync(dir)) {
|
|
51
|
+
const p = join(dir, name);
|
|
52
|
+
const s = statSync(p);
|
|
53
|
+
if (s.isDirectory()) out.push(...walk(p));
|
|
54
|
+
else if (/\.(astro|tsx)$/.test(p)) out.push(p);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function checkUiDrift({ root = "src", allowFiles = [], allowPrefixes = [] } = {}) {
|
|
60
|
+
if (process.env.SKIP_UI_DRIFT_CHECK === "1") return 0;
|
|
61
|
+
|
|
62
|
+
const offenders = [];
|
|
63
|
+
for (const file of walk(root)) {
|
|
64
|
+
if (allowFiles.includes(file)) continue;
|
|
65
|
+
if (allowPrefixes.some((p) => file.startsWith(p))) continue;
|
|
66
|
+
const text = readFileSync(file, "utf8");
|
|
67
|
+
const lines = text.split("\n");
|
|
68
|
+
const flagged = new Set();
|
|
69
|
+
lines.forEach((line, i) => {
|
|
70
|
+
if (line.includes("ui-drift-ok") || (i > 0 && lines[i - 1].includes("ui-drift-ok"))) return;
|
|
71
|
+
for (const [type, re, fix] of RULES) {
|
|
72
|
+
if (re.test(line)) {
|
|
73
|
+
offenders.push({ file, line: i + 1, type, fix });
|
|
74
|
+
flagged.add(type);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
// Class lists split across lines evade line rules: rerun on a
|
|
79
|
+
// whitespace-collapsed copy and report file-level hits not already seen.
|
|
80
|
+
if (!text.includes("ui-drift-ok")) {
|
|
81
|
+
const collapsed = text.replace(/\s+/g, " ");
|
|
82
|
+
for (const [type, re, fix] of RULES) {
|
|
83
|
+
if (!flagged.has(type) && re.test(collapsed)) {
|
|
84
|
+
offenders.push({ file, line: 0, type: `${type} (multi-line)`, fix });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (offenders.length === 0) {
|
|
91
|
+
console.log("ui:check — no hand-rolled primitives found ✓");
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const byType = {};
|
|
96
|
+
for (const o of offenders) {
|
|
97
|
+
byType[o.type] ??= [];
|
|
98
|
+
byType[o.type].push(o);
|
|
99
|
+
}
|
|
100
|
+
console.error(
|
|
101
|
+
`ui:check — ${offenders.length} hand-rolled primitive(s) duplicating @glasshome/ui:\n`,
|
|
102
|
+
);
|
|
103
|
+
for (const [type, list] of Object.entries(byType)) {
|
|
104
|
+
console.error(` ${type} (${list.length}) — ${list[0].fix}`);
|
|
105
|
+
for (const o of list) console.error(` ${o.file}${o.line ? `:${o.line}` : ""}`);
|
|
106
|
+
console.error("");
|
|
107
|
+
}
|
|
108
|
+
console.error(
|
|
109
|
+
"Migrate to the package primitive, or add `ui-drift-ok <reason>` in a line comment if bespoke is intended.",
|
|
110
|
+
);
|
|
111
|
+
return 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
115
|
+
process.exit(checkUiDrift());
|
|
116
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Static tone alert/callout for Astro / SSR pages — the same `ALERT_TONES` table
|
|
4
|
+
* and surface recipe the Solid <Alert> and hub's docs Callout use, rendered as
|
|
5
|
+
* plain HTML with zero JS and the lucide glyph inlined as SVG (no icon runtime).
|
|
6
|
+
* Drop this into `.astro` markup instead of hand-writing a
|
|
7
|
+
* `rounded-lg border border-primary/40 bg-primary/10` note box.
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
ALERT_CLASS,
|
|
11
|
+
ALERT_CONTENT_CLASS,
|
|
12
|
+
ALERT_DESCRIPTION_CLASS,
|
|
13
|
+
ALERT_ICON_BG_CLASS,
|
|
14
|
+
ALERT_ICON_PATHS,
|
|
15
|
+
ALERT_TITLE_CLASS,
|
|
16
|
+
ALERT_TONES,
|
|
17
|
+
type AlertTone,
|
|
18
|
+
alertIconBgStyle,
|
|
19
|
+
cn,
|
|
20
|
+
glassToneText,
|
|
21
|
+
} from "@glasshome/ui";
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
tone?: AlertTone;
|
|
25
|
+
/** Bold heading line. Optional. */
|
|
26
|
+
title?: string;
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { tone = "info", title, class: className, ...rest } = Astro.props;
|
|
31
|
+
const t = ALERT_TONES[tone];
|
|
32
|
+
|
|
33
|
+
const surfaceStyle = `--glass-tone:${t.color};color:var(--foreground)`;
|
|
34
|
+
|
|
35
|
+
const iconBgStyle = Object.entries(alertIconBgStyle(t.color))
|
|
36
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
37
|
+
.join(";");
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<div
|
|
41
|
+
data-slot="alert"
|
|
42
|
+
role={tone === "destructive" ? "alert" : "status"}
|
|
43
|
+
class={cn(ALERT_CLASS, "glass glass-tint", className)}
|
|
44
|
+
style={surfaceStyle}
|
|
45
|
+
{...rest}
|
|
46
|
+
>
|
|
47
|
+
<span class={ALERT_ICON_BG_CLASS} style={iconBgStyle} aria-hidden="true">
|
|
48
|
+
<svg
|
|
49
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
50
|
+
viewBox="0 0 24 24"
|
|
51
|
+
fill="none"
|
|
52
|
+
stroke="currentColor"
|
|
53
|
+
stroke-width="2"
|
|
54
|
+
stroke-linecap="round"
|
|
55
|
+
stroke-linejoin="round"
|
|
56
|
+
set:html={ALERT_ICON_PATHS[tone]}
|
|
57
|
+
/>
|
|
58
|
+
</span>
|
|
59
|
+
<div class={ALERT_CONTENT_CLASS}>
|
|
60
|
+
{title && <p data-slot="alert-title" class={ALERT_TITLE_CLASS} style={`color:${glassToneText(t.color)}`}>{title}</p>}
|
|
61
|
+
<div data-slot="alert-description" class={ALERT_DESCRIPTION_CLASS}><slot /></div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { BADGE_DEFAULT_TONE, BADGE_TONE_CLASS } from "../lib/badge-tone";
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
tone?: string;
|
|
7
|
+
as?: keyof HTMLElementTagNameMap;
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { tone = BADGE_DEFAULT_TONE, as: Tag = "span", class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<Tag data-slot="badge" class={cn(BADGE_TONE_CLASS, "glass glass-tint", className)} style={`--glass-tone:${tone}`} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</Tag>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Static button/CTA for Astro / SSR pages — the same `buttonVariants` recipe the
|
|
4
|
+
* Solid <Button> uses, rendered as a plain <a>/<button> with zero JS. Drop this
|
|
5
|
+
* into `.astro` markup instead of hand-writing a `rounded-full bg-primary px-6`
|
|
6
|
+
* pill.
|
|
7
|
+
*
|
|
8
|
+
* Renders an <a> when `href` is set, else a <button>. `size` defaults to `none`
|
|
9
|
+
* (sizeless: color + shape only) so marketing CTAs supply their own height and
|
|
10
|
+
* padding via `class`, matching how the hub pill tokens are used.
|
|
11
|
+
*/
|
|
12
|
+
import { buttonVariants, cn } from "@glasshome/ui";
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
|
16
|
+
size?: "default" | "sm" | "lg" | "icon" | "none";
|
|
17
|
+
href?: string;
|
|
18
|
+
type?: "button" | "submit" | "reset";
|
|
19
|
+
class?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
variant = "default",
|
|
24
|
+
size = "none",
|
|
25
|
+
href,
|
|
26
|
+
type = "button",
|
|
27
|
+
class: className,
|
|
28
|
+
...rest
|
|
29
|
+
} = Astro.props;
|
|
30
|
+
const cls = cn(buttonVariants({ variant, size }), className);
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
href ? (
|
|
35
|
+
<a data-slot="button" href={href} class={cls} {...rest}>
|
|
36
|
+
<slot />
|
|
37
|
+
</a>
|
|
38
|
+
) : (
|
|
39
|
+
<button data-slot="button" type={type} class={cls} {...rest}>
|
|
40
|
+
<slot />
|
|
41
|
+
</button>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
CARD_INTERACTIVE,
|
|
4
|
+
CARD_PADDING,
|
|
5
|
+
CARD_SURFACE,
|
|
6
|
+
CARD_SURFACE_OPAQUE,
|
|
7
|
+
type CardPadding,
|
|
8
|
+
} from "../lib/card-classes";
|
|
9
|
+
import { cn } from "../lib/utils";
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
as?: keyof HTMLElementTagNameMap;
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
opaque?: boolean;
|
|
15
|
+
padding?: CardPadding;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
as: Tag = "div",
|
|
21
|
+
interactive = false,
|
|
22
|
+
opaque = false,
|
|
23
|
+
padding = "none",
|
|
24
|
+
class: className,
|
|
25
|
+
...rest
|
|
26
|
+
} = Astro.props;
|
|
27
|
+
|
|
28
|
+
const classes = cn(
|
|
29
|
+
opaque ? CARD_SURFACE_OPAQUE : CARD_SURFACE,
|
|
30
|
+
"rounded-[var(--radius)]",
|
|
31
|
+
CARD_PADDING[padding],
|
|
32
|
+
interactive && CARD_INTERACTIVE,
|
|
33
|
+
className,
|
|
34
|
+
);
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
<Tag data-slot="card" class={classes} {...rest}>
|
|
38
|
+
<slot />
|
|
39
|
+
</Tag>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* The GlassHome lockup for Astro / SSR pages — the same spec the Solid <Logo>
|
|
4
|
+
* renders, as plain HTML with zero JS. Use this instead of hand-building a
|
|
5
|
+
* mark + "GlassHome" + sub-line stack; that is how the lockup ended up in six
|
|
6
|
+
* shapes across the repos.
|
|
7
|
+
*
|
|
8
|
+
* `href` renders the whole lockup as a link. The `sub` slot replaces the
|
|
9
|
+
* sub-brand line for surfaces that animate over it (e.g. hub's launch
|
|
10
|
+
* countdown cross-fade); it inherits nothing, so pass LOGO_SUB_CLASS yourself.
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
cn,
|
|
14
|
+
LOGO_DEFAULT_SIZE,
|
|
15
|
+
LOGO_DEFAULT_SRC,
|
|
16
|
+
LOGO_DEFAULT_SUB,
|
|
17
|
+
LOGO_MARK_CLASS,
|
|
18
|
+
LOGO_MARK_PX,
|
|
19
|
+
LOGO_NAME_CLASS,
|
|
20
|
+
LOGO_ROOT_CLASS,
|
|
21
|
+
LOGO_SIZES,
|
|
22
|
+
LOGO_STACK_CLASS,
|
|
23
|
+
LOGO_SUB_CLASS,
|
|
24
|
+
type LogoSize,
|
|
25
|
+
} from "@glasshome/ui";
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
/** Sub-brand line. Defaults to "Dash". */
|
|
29
|
+
sub?: string;
|
|
30
|
+
size?: LogoSize;
|
|
31
|
+
/** Renders the lockup as a link when set. */
|
|
32
|
+
href?: string;
|
|
33
|
+
/** Override the mark asset. Both apps serve the default path. */
|
|
34
|
+
src?: string;
|
|
35
|
+
class?: string;
|
|
36
|
+
/** Extra classes for the mark, e.g. a hover transform. */
|
|
37
|
+
markClass?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
sub = LOGO_DEFAULT_SUB,
|
|
42
|
+
size = LOGO_DEFAULT_SIZE,
|
|
43
|
+
href,
|
|
44
|
+
src = LOGO_DEFAULT_SRC,
|
|
45
|
+
class: className,
|
|
46
|
+
markClass,
|
|
47
|
+
...rest
|
|
48
|
+
} = Astro.props;
|
|
49
|
+
|
|
50
|
+
const s = LOGO_SIZES[size];
|
|
51
|
+
const px = LOGO_MARK_PX[size];
|
|
52
|
+
const Tag = href ? "a" : "div";
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
<Tag data-slot="logo" class={cn(LOGO_ROOT_CLASS, s.gap, className)} href={href} {...rest}>
|
|
56
|
+
<img
|
|
57
|
+
src={src}
|
|
58
|
+
alt=""
|
|
59
|
+
width={px}
|
|
60
|
+
height={px}
|
|
61
|
+
class={cn(LOGO_MARK_CLASS, s.mark, markClass)}
|
|
62
|
+
/>
|
|
63
|
+
<span class={LOGO_STACK_CLASS}>
|
|
64
|
+
<span data-slot="logo-name" class={cn(s.name, LOGO_NAME_CLASS)}>GlassHome</span>
|
|
65
|
+
<slot name="sub">
|
|
66
|
+
<span data-slot="logo-sub" class={cn(s.sub, LOGO_SUB_CLASS)}>{sub}</span>
|
|
67
|
+
</slot>
|
|
68
|
+
</span>
|
|
69
|
+
</Tag>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Static metallic tier chip for Astro / SSR pages (PRO / EARLY BIRD / CREATOR /
|
|
4
|
+
* FOUNDER) — the same tier tokens the Solid <TierBadge> uses, rendered as plain
|
|
5
|
+
* HTML with zero JS. One family; only the hi/lo/text triplet changes per tier.
|
|
6
|
+
*/
|
|
7
|
+
import { TIER_BADGE_CLASS, tierBadgeStyle } from "../lib/tier-badge";
|
|
8
|
+
import { cn } from "../lib/utils";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Gradient high stop (the near end of the diagonal sweep, and by default
|
|
12
|
+
* the far end too). */
|
|
13
|
+
hi: string;
|
|
14
|
+
/** Gradient low stop (the dip). */
|
|
15
|
+
lo: string;
|
|
16
|
+
/** Dark label color. */
|
|
17
|
+
text: string;
|
|
18
|
+
/** Far end of the sweep. Default: `hi` (symmetric brushed look). */
|
|
19
|
+
end?: string;
|
|
20
|
+
/** Where `lo` sits, in percent. Default: 50. */
|
|
21
|
+
stop?: number;
|
|
22
|
+
class?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { hi, lo, text, end, stop, class: className, ...rest } = Astro.props;
|
|
26
|
+
const style = Object.entries(tierBadgeStyle(hi, lo, text, { end, stop }))
|
|
27
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
28
|
+
.join(";");
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<span data-slot="tier-badge" class={cn(TIER_BADGE_CLASS, className)} style={style} {...rest}>
|
|
32
|
+
<slot />
|
|
33
|
+
</span>
|