@felixgeelhaar/glossa-ui 0.1.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/LICENSE +21 -0
- package/dist/badge.d.ts +18 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +59 -0
- package/dist/badge.js.map +1 -0
- package/dist/button.d.ts +32 -0
- package/dist/button.d.ts.map +1 -0
- package/dist/button.js +120 -0
- package/dist/button.js.map +1 -0
- package/dist/card.d.ts +17 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +45 -0
- package/dist/card.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +69 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +129 -0
- package/dist/input.js.map +1 -0
- package/dist/select.d.ts +38 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +77 -0
- package/dist/select.js.map +1 -0
- package/dist/table.d.ts +22 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +74 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.d.ts +27 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +81 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.d.ts +38 -0
- package/dist/textarea.d.ts.map +1 -0
- package/dist/textarea.js +80 -0
- package/dist/textarea.js.map +1 -0
- package/dist/theme-toggle.d.ts +20 -0
- package/dist/theme-toggle.d.ts.map +1 -0
- package/dist/theme-toggle.js +64 -0
- package/dist/theme-toggle.js.map +1 -0
- package/dist/theme.d.ts +9 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +48 -0
- package/dist/theme.js.map +1 -0
- package/dist/toast.d.ts +28 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +82 -0
- package/dist/toast.js.map +1 -0
- package/dist/tokens.css +193 -0
- package/dist/toolbar.d.ts +11 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +70 -0
- package/dist/toolbar.js.map +1 -0
- package/package.json +58 -0
- package/src/tokens.css +193 -0
package/dist/toast.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// <gl-toast> — non-blocking confirmation / error notice. The
|
|
2
|
+
// helper `toast(msg, variant)` mounts one to <body>, auto-removes
|
|
3
|
+
// after the default 3s. ARIA live region announces to screen
|
|
4
|
+
// readers.
|
|
5
|
+
import { LitElement, css, html } from "lit";
|
|
6
|
+
export class GlToast extends LitElement {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.variant = "ok";
|
|
10
|
+
this.message = "";
|
|
11
|
+
}
|
|
12
|
+
static { this.styles = css `
|
|
13
|
+
:host {
|
|
14
|
+
position: fixed;
|
|
15
|
+
bottom: var(--gl-space-5);
|
|
16
|
+
right: var(--gl-space-5);
|
|
17
|
+
z-index: 9999;
|
|
18
|
+
}
|
|
19
|
+
.toast {
|
|
20
|
+
background: var(--gl-surface-raised);
|
|
21
|
+
color: var(--gl-text);
|
|
22
|
+
border: 1px solid var(--gl-border);
|
|
23
|
+
border-radius: var(--gl-radius-md);
|
|
24
|
+
padding: 10px 14px;
|
|
25
|
+
box-shadow: var(--gl-shadow-lg);
|
|
26
|
+
max-width: 360px;
|
|
27
|
+
font-size: var(--gl-text-md);
|
|
28
|
+
animation: slide-in var(--gl-duration-slow) var(--gl-ease);
|
|
29
|
+
}
|
|
30
|
+
.err {
|
|
31
|
+
border-color: var(--gl-danger);
|
|
32
|
+
color: var(--gl-danger);
|
|
33
|
+
}
|
|
34
|
+
.ok {
|
|
35
|
+
border-color: var(--gl-success);
|
|
36
|
+
color: var(--gl-success);
|
|
37
|
+
}
|
|
38
|
+
@keyframes slide-in {
|
|
39
|
+
from {
|
|
40
|
+
opacity: 0;
|
|
41
|
+
transform: translateY(8px);
|
|
42
|
+
}
|
|
43
|
+
to {
|
|
44
|
+
opacity: 1;
|
|
45
|
+
transform: translateY(0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`; }
|
|
49
|
+
static { this.properties = {
|
|
50
|
+
variant: { type: String },
|
|
51
|
+
message: { type: String },
|
|
52
|
+
}; }
|
|
53
|
+
render() {
|
|
54
|
+
return html `
|
|
55
|
+
<div class=${`toast ${this.variant}`} role="status" aria-live="polite">
|
|
56
|
+
${this.message}
|
|
57
|
+
</div>
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!customElements.get("gl-toast")) {
|
|
62
|
+
customElements.define("gl-toast", GlToast);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Imperative helper: pops a toast attached to <body>. Returns a
|
|
66
|
+
* function that removes it immediately if the caller wants to
|
|
67
|
+
* cancel.
|
|
68
|
+
*/
|
|
69
|
+
export function toast(message, variant = "ok", ttl = 3000) {
|
|
70
|
+
if (typeof document === "undefined")
|
|
71
|
+
return () => undefined;
|
|
72
|
+
const el = document.createElement("gl-toast");
|
|
73
|
+
el.message = message;
|
|
74
|
+
el.variant = variant;
|
|
75
|
+
document.body.appendChild(el);
|
|
76
|
+
const timer = window.setTimeout(() => el.remove(), ttl);
|
|
77
|
+
return () => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
el.remove();
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=toast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.js","sourceRoot":"","sources":["../src/toast.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,kEAAkE;AAClE,6DAA6D;AAC7D,WAAW;AAEX,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAI5C,MAAM,OAAO,OAAQ,SAAQ,UAAU;IAAvC;;QA4CS,YAAO,GAAiB,IAAI,CAAC;QAC7B,YAAO,GAAG,EAAE,CAAC;IAStB,CAAC;aArDiB,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoC3B,AApCqB,CAoCpB;aAEc,eAAU,GAAG;QAC3B,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACzB,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KAC1B,AAHyB,CAGxB;IAKiB,MAAM;QACvB,OAAO,IAAI,CAAA;mBACI,SAAS,IAAI,CAAC,OAAO,EAAE;UAChC,IAAI,CAAC,OAAO;;KAEjB,CAAC;IACJ,CAAC;;AAGH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;IACpC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,UAAwB,IAAI,EAAE,GAAG,GAAG,IAAI;IAC7E,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;IAC5D,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAY,CAAC;IACzD,EAAE,CAAC,OAAO,GAAG,OAAO,CAAC;IACrB,EAAE,CAAC,OAAO,GAAG,OAAO,CAAC;IACrB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,GAAG,EAAE;QACV,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,EAAE,CAAC,MAAM,EAAE,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/tokens.css
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/* Glossa design tokens. Defined as CSS custom properties on
|
|
2
|
+
* :root so any consumer can override per-app, and on
|
|
3
|
+
* [data-glossa-theme] so the toggle hot-swaps both light + dark.
|
|
4
|
+
*
|
|
5
|
+
* One accent (violet) + grayscale. 8px spacing grid. Inter for UI,
|
|
6
|
+
* ui-monospace for keys and values where script and length matter.
|
|
7
|
+
* Translators stare at the admin for hours; dark mode is not a
|
|
8
|
+
* vanity feature.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
:root,
|
|
12
|
+
[data-glossa-theme="light"] {
|
|
13
|
+
/* Surfaces */
|
|
14
|
+
--gl-bg: #fafafa;
|
|
15
|
+
--gl-surface: #ffffff;
|
|
16
|
+
--gl-surface-raised: #ffffff;
|
|
17
|
+
--gl-surface-sunken: #f4f4f5;
|
|
18
|
+
|
|
19
|
+
/* Text */
|
|
20
|
+
--gl-text: #18181b;
|
|
21
|
+
--gl-text-muted: #52525b;
|
|
22
|
+
--gl-text-subtle: #71717a;
|
|
23
|
+
--gl-text-inverse: #fafafa;
|
|
24
|
+
|
|
25
|
+
/* Borders + focus */
|
|
26
|
+
--gl-border: #e4e4e7;
|
|
27
|
+
--gl-border-strong: #a1a1aa;
|
|
28
|
+
--gl-focus-ring: #7c3aed40;
|
|
29
|
+
--gl-focus-ring-strong: #7c3aed;
|
|
30
|
+
|
|
31
|
+
/* Accent */
|
|
32
|
+
--gl-accent: #7c3aed;
|
|
33
|
+
--gl-accent-hover: #6d28d9;
|
|
34
|
+
--gl-accent-quiet: #f5f3ff;
|
|
35
|
+
--gl-accent-fg: #ffffff;
|
|
36
|
+
|
|
37
|
+
/* Status */
|
|
38
|
+
--gl-danger: #dc2626;
|
|
39
|
+
--gl-danger-bg: #fef2f2;
|
|
40
|
+
--gl-warning: #ea580c;
|
|
41
|
+
--gl-warning-bg: #fff7ed;
|
|
42
|
+
--gl-success: #16a34a;
|
|
43
|
+
--gl-success-bg: #f0fdf4;
|
|
44
|
+
|
|
45
|
+
/* Status pills for translation lifecycle. Distinct from
|
|
46
|
+
* status colors above so a "needs review" badge doesn't shout
|
|
47
|
+
* like a "danger" alert. */
|
|
48
|
+
--gl-status-pending: #71717a;
|
|
49
|
+
--gl-status-pending-bg: #f4f4f5;
|
|
50
|
+
--gl-status-review: #c2410c;
|
|
51
|
+
--gl-status-review-bg: #ffedd5;
|
|
52
|
+
--gl-status-approved: #15803d;
|
|
53
|
+
--gl-status-approved-bg:#dcfce7;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[data-glossa-theme="dark"] {
|
|
57
|
+
--gl-bg: #09090b;
|
|
58
|
+
--gl-surface: #18181b;
|
|
59
|
+
--gl-surface-raised: #27272a;
|
|
60
|
+
--gl-surface-sunken: #09090b;
|
|
61
|
+
|
|
62
|
+
--gl-text: #fafafa;
|
|
63
|
+
--gl-text-muted: #a1a1aa;
|
|
64
|
+
--gl-text-subtle: #71717a;
|
|
65
|
+
--gl-text-inverse: #18181b;
|
|
66
|
+
|
|
67
|
+
--gl-border: #27272a;
|
|
68
|
+
--gl-border-strong: #52525b;
|
|
69
|
+
--gl-focus-ring: #a78bfa55;
|
|
70
|
+
--gl-focus-ring-strong: #a78bfa;
|
|
71
|
+
|
|
72
|
+
--gl-accent: #a78bfa;
|
|
73
|
+
--gl-accent-hover: #c4b5fd;
|
|
74
|
+
--gl-accent-quiet: #2e1065;
|
|
75
|
+
--gl-accent-fg: #18181b;
|
|
76
|
+
|
|
77
|
+
--gl-danger: #f87171;
|
|
78
|
+
--gl-danger-bg: #450a0a;
|
|
79
|
+
--gl-warning: #fb923c;
|
|
80
|
+
--gl-warning-bg: #431407;
|
|
81
|
+
--gl-success: #4ade80;
|
|
82
|
+
--gl-success-bg: #052e16;
|
|
83
|
+
|
|
84
|
+
--gl-status-pending: #a1a1aa;
|
|
85
|
+
--gl-status-pending-bg: #27272a;
|
|
86
|
+
--gl-status-review: #fdba74;
|
|
87
|
+
--gl-status-review-bg: #431407;
|
|
88
|
+
--gl-status-approved: #86efac;
|
|
89
|
+
--gl-status-approved-bg:#052e16;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* System-preference fallback when no explicit attribute is set. */
|
|
93
|
+
@media (prefers-color-scheme: dark) {
|
|
94
|
+
:root:not([data-glossa-theme]) {
|
|
95
|
+
--gl-bg: #09090b;
|
|
96
|
+
--gl-surface: #18181b;
|
|
97
|
+
--gl-surface-raised: #27272a;
|
|
98
|
+
--gl-surface-sunken: #09090b;
|
|
99
|
+
--gl-text: #fafafa;
|
|
100
|
+
--gl-text-muted: #a1a1aa;
|
|
101
|
+
--gl-text-subtle: #71717a;
|
|
102
|
+
--gl-text-inverse: #18181b;
|
|
103
|
+
--gl-border: #27272a;
|
|
104
|
+
--gl-border-strong: #52525b;
|
|
105
|
+
--gl-focus-ring: #a78bfa55;
|
|
106
|
+
--gl-focus-ring-strong: #a78bfa;
|
|
107
|
+
--gl-accent: #a78bfa;
|
|
108
|
+
--gl-accent-hover: #c4b5fd;
|
|
109
|
+
--gl-accent-quiet: #2e1065;
|
|
110
|
+
--gl-accent-fg: #18181b;
|
|
111
|
+
--gl-danger: #f87171;
|
|
112
|
+
--gl-danger-bg: #450a0a;
|
|
113
|
+
--gl-warning: #fb923c;
|
|
114
|
+
--gl-warning-bg: #431407;
|
|
115
|
+
--gl-success: #4ade80;
|
|
116
|
+
--gl-success-bg: #052e16;
|
|
117
|
+
--gl-status-pending: #a1a1aa;
|
|
118
|
+
--gl-status-pending-bg: #27272a;
|
|
119
|
+
--gl-status-review: #fdba74;
|
|
120
|
+
--gl-status-review-bg: #431407;
|
|
121
|
+
--gl-status-approved: #86efac;
|
|
122
|
+
--gl-status-approved-bg:#052e16;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:root {
|
|
127
|
+
/* Spacing — 8px grid, tighter steps at the start for
|
|
128
|
+
* intra-component padding. */
|
|
129
|
+
--gl-space-0: 0;
|
|
130
|
+
--gl-space-1: 4px;
|
|
131
|
+
--gl-space-2: 8px;
|
|
132
|
+
--gl-space-3: 12px;
|
|
133
|
+
--gl-space-4: 16px;
|
|
134
|
+
--gl-space-5: 24px;
|
|
135
|
+
--gl-space-6: 32px;
|
|
136
|
+
--gl-space-7: 48px;
|
|
137
|
+
--gl-space-8: 64px;
|
|
138
|
+
|
|
139
|
+
/* Radii */
|
|
140
|
+
--gl-radius-sm: 4px;
|
|
141
|
+
--gl-radius-md: 6px;
|
|
142
|
+
--gl-radius-lg: 8px;
|
|
143
|
+
--gl-radius-pill: 999px;
|
|
144
|
+
|
|
145
|
+
/* Typography */
|
|
146
|
+
--gl-font-ui:
|
|
147
|
+
"Inter", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
148
|
+
"Helvetica Neue", sans-serif;
|
|
149
|
+
--gl-font-mono:
|
|
150
|
+
ui-monospace, SFMono-Regular, "JetBrains Mono", "Fira Code",
|
|
151
|
+
Menlo, Consolas, monospace;
|
|
152
|
+
|
|
153
|
+
--gl-text-xs: 11px;
|
|
154
|
+
--gl-text-sm: 12px;
|
|
155
|
+
--gl-text-md: 13px;
|
|
156
|
+
--gl-text-base: 14px;
|
|
157
|
+
--gl-text-lg: 16px;
|
|
158
|
+
--gl-text-xl: 18px;
|
|
159
|
+
--gl-text-2xl: 22px;
|
|
160
|
+
|
|
161
|
+
--gl-leading-tight: 1.25;
|
|
162
|
+
--gl-leading-snug: 1.4;
|
|
163
|
+
--gl-leading-base: 1.5;
|
|
164
|
+
|
|
165
|
+
/* Motion */
|
|
166
|
+
--gl-duration-fast: 80ms;
|
|
167
|
+
--gl-duration-base: 120ms;
|
|
168
|
+
--gl-duration-slow: 200ms;
|
|
169
|
+
--gl-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
170
|
+
|
|
171
|
+
/* Elevation — kept restrained. Most surfaces use borders, not
|
|
172
|
+
* shadows; modals/toasts get the only real shadow. */
|
|
173
|
+
--gl-shadow-md:
|
|
174
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.07),
|
|
175
|
+
0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
176
|
+
--gl-shadow-lg:
|
|
177
|
+
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
|
178
|
+
0 4px 6px -4px rgba(0, 0, 0, 0.05);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Page-level baseline. Apply to body once tokens are loaded so
|
|
182
|
+
* inputs / text everywhere pick up the font + colors without per-
|
|
183
|
+
* component declarations. */
|
|
184
|
+
.gl-root,
|
|
185
|
+
body.gl-root {
|
|
186
|
+
background: var(--gl-bg);
|
|
187
|
+
color: var(--gl-text);
|
|
188
|
+
font-family: var(--gl-font-ui);
|
|
189
|
+
font-size: var(--gl-text-base);
|
|
190
|
+
line-height: var(--gl-leading-base);
|
|
191
|
+
-webkit-font-smoothing: antialiased;
|
|
192
|
+
-moz-osx-font-smoothing: grayscale;
|
|
193
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
export declare class GlToolbar extends LitElement {
|
|
3
|
+
static styles: import("lit").CSSResult;
|
|
4
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
5
|
+
}
|
|
6
|
+
declare global {
|
|
7
|
+
interface HTMLElementTagNameMap {
|
|
8
|
+
"gl-toolbar": GlToolbar;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=toolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar.d.ts","sourceRoot":"","sources":["../src/toolbar.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,qBAAa,SAAU,SAAQ,UAAU;IACvC,OAAgB,MAAM,0BA8CpB;cAEiB,MAAM;CAa1B;AAMD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,SAAS,CAAC;KACzB;CACF"}
|
package/dist/toolbar.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// <gl-toolbar> — top app strip. Hosts the brand, project picker,
|
|
2
|
+
// theme toggle, and a sign-out button via slots so consumers
|
|
3
|
+
// compose without rewriting the chrome.
|
|
4
|
+
import { LitElement, css, html } from "lit";
|
|
5
|
+
export class GlToolbar extends LitElement {
|
|
6
|
+
static { this.styles = css `
|
|
7
|
+
:host {
|
|
8
|
+
display: block;
|
|
9
|
+
background: var(--gl-surface);
|
|
10
|
+
border-bottom: 1px solid var(--gl-border);
|
|
11
|
+
padding: var(--gl-space-3) var(--gl-space-5);
|
|
12
|
+
}
|
|
13
|
+
.row {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: var(--gl-space-4);
|
|
17
|
+
flex-wrap: wrap;
|
|
18
|
+
}
|
|
19
|
+
.brand {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: var(--gl-space-2);
|
|
23
|
+
font-size: var(--gl-text-lg);
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
color: var(--gl-text);
|
|
26
|
+
letter-spacing: -0.01em;
|
|
27
|
+
}
|
|
28
|
+
.brand-mark {
|
|
29
|
+
width: 22px;
|
|
30
|
+
height: 22px;
|
|
31
|
+
border-radius: 6px;
|
|
32
|
+
background: var(--gl-accent);
|
|
33
|
+
display: inline-block;
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
.brand-mark::after {
|
|
37
|
+
content: "g";
|
|
38
|
+
position: absolute;
|
|
39
|
+
inset: 0;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: center;
|
|
43
|
+
color: var(--gl-accent-fg);
|
|
44
|
+
font-family: var(--gl-font-mono);
|
|
45
|
+
font-weight: 700;
|
|
46
|
+
font-size: 14px;
|
|
47
|
+
line-height: 1;
|
|
48
|
+
}
|
|
49
|
+
.spacer {
|
|
50
|
+
flex: 1;
|
|
51
|
+
}
|
|
52
|
+
`; }
|
|
53
|
+
render() {
|
|
54
|
+
return html `
|
|
55
|
+
<div class="row">
|
|
56
|
+
<span class="brand">
|
|
57
|
+
<span class="brand-mark" aria-hidden="true"></span>
|
|
58
|
+
<slot name="title">Glossa</slot>
|
|
59
|
+
</span>
|
|
60
|
+
<slot name="center"></slot>
|
|
61
|
+
<span class="spacer"></span>
|
|
62
|
+
<slot name="actions"></slot>
|
|
63
|
+
</div>
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!customElements.get("gl-toolbar")) {
|
|
68
|
+
customElements.define("gl-toolbar", GlToolbar);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=toolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar.js","sourceRoot":"","sources":["../src/toolbar.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,6DAA6D;AAC7D,wCAAwC;AAExC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE5C,MAAM,OAAO,SAAU,SAAQ,UAAU;aACvB,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8C3B,CAAC;IAEiB,MAAM;QACvB,OAAO,IAAI,CAAA;;;;;;;;;;KAUV,CAAC;IACJ,CAAC;;AAGH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;IACtC,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AACjD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@felixgeelhaar/glossa-ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Glossa design system — utilitarian Lit primitives + design tokens. Used by the admin SPA and any consumer surface embedding glossa.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./tokens.css": "./src/tokens.css"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src/tokens.css"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"lit": "^3.2.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"jsdom": "^25.0.0",
|
|
25
|
+
"prettier": "^3.0.0",
|
|
26
|
+
"typescript": "^5.5.0",
|
|
27
|
+
"vitest": "^2.0.0"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "Felix Geelhaar",
|
|
31
|
+
"homepage": "https://github.com/felixgeelhaar/glossa/tree/main/packages/ui#readme",
|
|
32
|
+
"bugs": "https://github.com/felixgeelhaar/glossa/issues",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/felixgeelhaar/glossa.git",
|
|
36
|
+
"directory": "packages/ui"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"lit",
|
|
40
|
+
"web-components",
|
|
41
|
+
"design-system",
|
|
42
|
+
"ui",
|
|
43
|
+
"tokens",
|
|
44
|
+
"glossa"
|
|
45
|
+
],
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc -p tsconfig.json && cp src/tokens.css dist/tokens.css",
|
|
54
|
+
"test": "vitest run --passWithNoTests",
|
|
55
|
+
"lint": "tsc --noEmit -p tsconfig.json",
|
|
56
|
+
"format": "prettier --write src"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/tokens.css
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/* Glossa design tokens. Defined as CSS custom properties on
|
|
2
|
+
* :root so any consumer can override per-app, and on
|
|
3
|
+
* [data-glossa-theme] so the toggle hot-swaps both light + dark.
|
|
4
|
+
*
|
|
5
|
+
* One accent (violet) + grayscale. 8px spacing grid. Inter for UI,
|
|
6
|
+
* ui-monospace for keys and values where script and length matter.
|
|
7
|
+
* Translators stare at the admin for hours; dark mode is not a
|
|
8
|
+
* vanity feature.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
:root,
|
|
12
|
+
[data-glossa-theme="light"] {
|
|
13
|
+
/* Surfaces */
|
|
14
|
+
--gl-bg: #fafafa;
|
|
15
|
+
--gl-surface: #ffffff;
|
|
16
|
+
--gl-surface-raised: #ffffff;
|
|
17
|
+
--gl-surface-sunken: #f4f4f5;
|
|
18
|
+
|
|
19
|
+
/* Text */
|
|
20
|
+
--gl-text: #18181b;
|
|
21
|
+
--gl-text-muted: #52525b;
|
|
22
|
+
--gl-text-subtle: #71717a;
|
|
23
|
+
--gl-text-inverse: #fafafa;
|
|
24
|
+
|
|
25
|
+
/* Borders + focus */
|
|
26
|
+
--gl-border: #e4e4e7;
|
|
27
|
+
--gl-border-strong: #a1a1aa;
|
|
28
|
+
--gl-focus-ring: #7c3aed40;
|
|
29
|
+
--gl-focus-ring-strong: #7c3aed;
|
|
30
|
+
|
|
31
|
+
/* Accent */
|
|
32
|
+
--gl-accent: #7c3aed;
|
|
33
|
+
--gl-accent-hover: #6d28d9;
|
|
34
|
+
--gl-accent-quiet: #f5f3ff;
|
|
35
|
+
--gl-accent-fg: #ffffff;
|
|
36
|
+
|
|
37
|
+
/* Status */
|
|
38
|
+
--gl-danger: #dc2626;
|
|
39
|
+
--gl-danger-bg: #fef2f2;
|
|
40
|
+
--gl-warning: #ea580c;
|
|
41
|
+
--gl-warning-bg: #fff7ed;
|
|
42
|
+
--gl-success: #16a34a;
|
|
43
|
+
--gl-success-bg: #f0fdf4;
|
|
44
|
+
|
|
45
|
+
/* Status pills for translation lifecycle. Distinct from
|
|
46
|
+
* status colors above so a "needs review" badge doesn't shout
|
|
47
|
+
* like a "danger" alert. */
|
|
48
|
+
--gl-status-pending: #71717a;
|
|
49
|
+
--gl-status-pending-bg: #f4f4f5;
|
|
50
|
+
--gl-status-review: #c2410c;
|
|
51
|
+
--gl-status-review-bg: #ffedd5;
|
|
52
|
+
--gl-status-approved: #15803d;
|
|
53
|
+
--gl-status-approved-bg:#dcfce7;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[data-glossa-theme="dark"] {
|
|
57
|
+
--gl-bg: #09090b;
|
|
58
|
+
--gl-surface: #18181b;
|
|
59
|
+
--gl-surface-raised: #27272a;
|
|
60
|
+
--gl-surface-sunken: #09090b;
|
|
61
|
+
|
|
62
|
+
--gl-text: #fafafa;
|
|
63
|
+
--gl-text-muted: #a1a1aa;
|
|
64
|
+
--gl-text-subtle: #71717a;
|
|
65
|
+
--gl-text-inverse: #18181b;
|
|
66
|
+
|
|
67
|
+
--gl-border: #27272a;
|
|
68
|
+
--gl-border-strong: #52525b;
|
|
69
|
+
--gl-focus-ring: #a78bfa55;
|
|
70
|
+
--gl-focus-ring-strong: #a78bfa;
|
|
71
|
+
|
|
72
|
+
--gl-accent: #a78bfa;
|
|
73
|
+
--gl-accent-hover: #c4b5fd;
|
|
74
|
+
--gl-accent-quiet: #2e1065;
|
|
75
|
+
--gl-accent-fg: #18181b;
|
|
76
|
+
|
|
77
|
+
--gl-danger: #f87171;
|
|
78
|
+
--gl-danger-bg: #450a0a;
|
|
79
|
+
--gl-warning: #fb923c;
|
|
80
|
+
--gl-warning-bg: #431407;
|
|
81
|
+
--gl-success: #4ade80;
|
|
82
|
+
--gl-success-bg: #052e16;
|
|
83
|
+
|
|
84
|
+
--gl-status-pending: #a1a1aa;
|
|
85
|
+
--gl-status-pending-bg: #27272a;
|
|
86
|
+
--gl-status-review: #fdba74;
|
|
87
|
+
--gl-status-review-bg: #431407;
|
|
88
|
+
--gl-status-approved: #86efac;
|
|
89
|
+
--gl-status-approved-bg:#052e16;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* System-preference fallback when no explicit attribute is set. */
|
|
93
|
+
@media (prefers-color-scheme: dark) {
|
|
94
|
+
:root:not([data-glossa-theme]) {
|
|
95
|
+
--gl-bg: #09090b;
|
|
96
|
+
--gl-surface: #18181b;
|
|
97
|
+
--gl-surface-raised: #27272a;
|
|
98
|
+
--gl-surface-sunken: #09090b;
|
|
99
|
+
--gl-text: #fafafa;
|
|
100
|
+
--gl-text-muted: #a1a1aa;
|
|
101
|
+
--gl-text-subtle: #71717a;
|
|
102
|
+
--gl-text-inverse: #18181b;
|
|
103
|
+
--gl-border: #27272a;
|
|
104
|
+
--gl-border-strong: #52525b;
|
|
105
|
+
--gl-focus-ring: #a78bfa55;
|
|
106
|
+
--gl-focus-ring-strong: #a78bfa;
|
|
107
|
+
--gl-accent: #a78bfa;
|
|
108
|
+
--gl-accent-hover: #c4b5fd;
|
|
109
|
+
--gl-accent-quiet: #2e1065;
|
|
110
|
+
--gl-accent-fg: #18181b;
|
|
111
|
+
--gl-danger: #f87171;
|
|
112
|
+
--gl-danger-bg: #450a0a;
|
|
113
|
+
--gl-warning: #fb923c;
|
|
114
|
+
--gl-warning-bg: #431407;
|
|
115
|
+
--gl-success: #4ade80;
|
|
116
|
+
--gl-success-bg: #052e16;
|
|
117
|
+
--gl-status-pending: #a1a1aa;
|
|
118
|
+
--gl-status-pending-bg: #27272a;
|
|
119
|
+
--gl-status-review: #fdba74;
|
|
120
|
+
--gl-status-review-bg: #431407;
|
|
121
|
+
--gl-status-approved: #86efac;
|
|
122
|
+
--gl-status-approved-bg:#052e16;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:root {
|
|
127
|
+
/* Spacing — 8px grid, tighter steps at the start for
|
|
128
|
+
* intra-component padding. */
|
|
129
|
+
--gl-space-0: 0;
|
|
130
|
+
--gl-space-1: 4px;
|
|
131
|
+
--gl-space-2: 8px;
|
|
132
|
+
--gl-space-3: 12px;
|
|
133
|
+
--gl-space-4: 16px;
|
|
134
|
+
--gl-space-5: 24px;
|
|
135
|
+
--gl-space-6: 32px;
|
|
136
|
+
--gl-space-7: 48px;
|
|
137
|
+
--gl-space-8: 64px;
|
|
138
|
+
|
|
139
|
+
/* Radii */
|
|
140
|
+
--gl-radius-sm: 4px;
|
|
141
|
+
--gl-radius-md: 6px;
|
|
142
|
+
--gl-radius-lg: 8px;
|
|
143
|
+
--gl-radius-pill: 999px;
|
|
144
|
+
|
|
145
|
+
/* Typography */
|
|
146
|
+
--gl-font-ui:
|
|
147
|
+
"Inter", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
148
|
+
"Helvetica Neue", sans-serif;
|
|
149
|
+
--gl-font-mono:
|
|
150
|
+
ui-monospace, SFMono-Regular, "JetBrains Mono", "Fira Code",
|
|
151
|
+
Menlo, Consolas, monospace;
|
|
152
|
+
|
|
153
|
+
--gl-text-xs: 11px;
|
|
154
|
+
--gl-text-sm: 12px;
|
|
155
|
+
--gl-text-md: 13px;
|
|
156
|
+
--gl-text-base: 14px;
|
|
157
|
+
--gl-text-lg: 16px;
|
|
158
|
+
--gl-text-xl: 18px;
|
|
159
|
+
--gl-text-2xl: 22px;
|
|
160
|
+
|
|
161
|
+
--gl-leading-tight: 1.25;
|
|
162
|
+
--gl-leading-snug: 1.4;
|
|
163
|
+
--gl-leading-base: 1.5;
|
|
164
|
+
|
|
165
|
+
/* Motion */
|
|
166
|
+
--gl-duration-fast: 80ms;
|
|
167
|
+
--gl-duration-base: 120ms;
|
|
168
|
+
--gl-duration-slow: 200ms;
|
|
169
|
+
--gl-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
170
|
+
|
|
171
|
+
/* Elevation — kept restrained. Most surfaces use borders, not
|
|
172
|
+
* shadows; modals/toasts get the only real shadow. */
|
|
173
|
+
--gl-shadow-md:
|
|
174
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.07),
|
|
175
|
+
0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
176
|
+
--gl-shadow-lg:
|
|
177
|
+
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
|
178
|
+
0 4px 6px -4px rgba(0, 0, 0, 0.05);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Page-level baseline. Apply to body once tokens are loaded so
|
|
182
|
+
* inputs / text everywhere pick up the font + colors without per-
|
|
183
|
+
* component declarations. */
|
|
184
|
+
.gl-root,
|
|
185
|
+
body.gl-root {
|
|
186
|
+
background: var(--gl-bg);
|
|
187
|
+
color: var(--gl-text);
|
|
188
|
+
font-family: var(--gl-font-ui);
|
|
189
|
+
font-size: var(--gl-text-base);
|
|
190
|
+
line-height: var(--gl-leading-base);
|
|
191
|
+
-webkit-font-smoothing: antialiased;
|
|
192
|
+
-moz-osx-font-smoothing: grayscale;
|
|
193
|
+
}
|