@danieldeusing/design 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/README.md +168 -0
- package/dist/danieldeusing-design.css +554 -0
- package/dist/danieldeusing-design.min.css +2 -0
- package/package.json +65 -0
- package/runtime/dropdown.js +44 -0
- package/runtime/index.js +16 -0
- package/runtime/terminal.js +120 -0
- package/runtime/theme.js +107 -0
- package/runtime/zoom.js +25 -0
- package/src/base.css +68 -0
- package/src/components.css +288 -0
- package/src/fonts.css +40 -0
- package/src/index.css +19 -0
- package/src/reset.css +74 -0
- package/src/tailwind.css +48 -0
- package/src/tokens.css +116 -0
- package/tokens/tokens.json +100 -0
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
/*! danieldeusing-design v0.1.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
|
|
2
|
+
/* ===== reset.css ===== */
|
|
3
|
+
/*
|
|
4
|
+
* danieldeusing-design — minimal reset.
|
|
5
|
+
*
|
|
6
|
+
* Only loaded on the build-free path (index.css / the dist bundle / CDN), where
|
|
7
|
+
* there is no Tailwind Preflight to normalize the document. Tailwind v4 apps must
|
|
8
|
+
* NOT import this — they already get an equivalent reset from Preflight, and
|
|
9
|
+
* importing it twice would be redundant. Deliberately tiny: it normalizes the box
|
|
10
|
+
* model and strips default margins so the terminal layout is predictable, and
|
|
11
|
+
* stops short of a full normalize.css.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
*,
|
|
15
|
+
*::before,
|
|
16
|
+
*::after {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
* {
|
|
21
|
+
margin: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
html {
|
|
25
|
+
-webkit-text-size-adjust: 100%;
|
|
26
|
+
text-size-adjust: 100%;
|
|
27
|
+
tab-size: 4;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
min-height: 100vh;
|
|
32
|
+
min-height: 100dvh;
|
|
33
|
+
line-height: 1.5;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
img,
|
|
37
|
+
picture,
|
|
38
|
+
video,
|
|
39
|
+
canvas,
|
|
40
|
+
svg {
|
|
41
|
+
display: block;
|
|
42
|
+
max-width: 100%;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
input,
|
|
46
|
+
button,
|
|
47
|
+
textarea,
|
|
48
|
+
select {
|
|
49
|
+
font: inherit;
|
|
50
|
+
color: inherit;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
p,
|
|
54
|
+
h1,
|
|
55
|
+
h2,
|
|
56
|
+
h3,
|
|
57
|
+
h4,
|
|
58
|
+
h5,
|
|
59
|
+
h6 {
|
|
60
|
+
overflow-wrap: break-word;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ul,
|
|
64
|
+
ol {
|
|
65
|
+
list-style: none;
|
|
66
|
+
padding: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
a {
|
|
70
|
+
color: inherit;
|
|
71
|
+
text-decoration: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
table {
|
|
75
|
+
border-collapse: collapse;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* ===== tokens.css ===== */
|
|
79
|
+
/*
|
|
80
|
+
* danieldeusing-design — design tokens.
|
|
81
|
+
*
|
|
82
|
+
* The single source of truth for the "terminal" theme: CRT phosphor on
|
|
83
|
+
* JetBrains Mono, $-prompts, ASCII rules, scanline overlay. Four variants
|
|
84
|
+
* selected via html[data-theme]: warm (default), green, mono, paper.
|
|
85
|
+
* :root holds the warm defaults so the theme works with no attribute set.
|
|
86
|
+
*
|
|
87
|
+
* These are plain CSS custom properties — they work in any framework, any
|
|
88
|
+
* browser, with or without a build step. Load this file first; base.css and
|
|
89
|
+
* components.css resolve against the variables declared here.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
:root {
|
|
93
|
+
--background: #f5efe2;
|
|
94
|
+
--foreground: #43352a;
|
|
95
|
+
--card: #efe7d4;
|
|
96
|
+
--card-foreground: #43352a;
|
|
97
|
+
--popover: #efe7d4;
|
|
98
|
+
--popover-foreground: #43352a;
|
|
99
|
+
--primary: #8a4516;
|
|
100
|
+
--primary-foreground: #f8f3e8;
|
|
101
|
+
--secondary: #ece3cf;
|
|
102
|
+
--secondary-foreground: #43352a;
|
|
103
|
+
--muted: #ece3cf;
|
|
104
|
+
--muted-foreground: #71614e;
|
|
105
|
+
--accent: #8a4516;
|
|
106
|
+
--accent-foreground: #f8f3e8;
|
|
107
|
+
--destructive: #a02c2c;
|
|
108
|
+
--border: #d9cdb6;
|
|
109
|
+
--input: #d9cdb6;
|
|
110
|
+
--ring: #8a4516;
|
|
111
|
+
|
|
112
|
+
--glow: rgba(160, 82, 45, 0.1);
|
|
113
|
+
--glow-soft: rgba(160, 82, 45, 0.05);
|
|
114
|
+
--scanline-opacity: 0.15;
|
|
115
|
+
|
|
116
|
+
--radius: 0rem;
|
|
117
|
+
|
|
118
|
+
--font-mono: "JetBrains Mono Variable", "JetBrains Mono", "Menlo", monospace;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* CRT phosphor green */
|
|
122
|
+
html[data-theme="green"] {
|
|
123
|
+
--background: #020604;
|
|
124
|
+
--foreground: #4fdd7d;
|
|
125
|
+
--card: #04110a;
|
|
126
|
+
--card-foreground: #4fdd7d;
|
|
127
|
+
--popover: #04110a;
|
|
128
|
+
--popover-foreground: #4fdd7d;
|
|
129
|
+
--primary: #33ff66;
|
|
130
|
+
--primary-foreground: #02160a;
|
|
131
|
+
--secondary: #071509;
|
|
132
|
+
--secondary-foreground: #4fdd7d;
|
|
133
|
+
--muted: #071509;
|
|
134
|
+
--muted-foreground: #3da45e;
|
|
135
|
+
--accent: #33ff66;
|
|
136
|
+
--accent-foreground: #02160a;
|
|
137
|
+
--destructive: #ff5c5c;
|
|
138
|
+
--border: #1c4a2c;
|
|
139
|
+
--input: #1c4a2c;
|
|
140
|
+
--ring: #33ff66;
|
|
141
|
+
--glow: rgba(51, 255, 102, 0.35);
|
|
142
|
+
--glow-soft: rgba(51, 255, 102, 0.12);
|
|
143
|
+
--scanline-opacity: 0.5;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* white-phosphor terminal */
|
|
147
|
+
html[data-theme="mono"] {
|
|
148
|
+
--background: #050505;
|
|
149
|
+
--foreground: #d4d4d4;
|
|
150
|
+
--card: #0d0d0d;
|
|
151
|
+
--card-foreground: #d4d4d4;
|
|
152
|
+
--popover: #0d0d0d;
|
|
153
|
+
--popover-foreground: #d4d4d4;
|
|
154
|
+
--primary: #ffffff;
|
|
155
|
+
--primary-foreground: #050505;
|
|
156
|
+
--secondary: #111111;
|
|
157
|
+
--secondary-foreground: #d4d4d4;
|
|
158
|
+
--muted: #111111;
|
|
159
|
+
--muted-foreground: #8a8a8a;
|
|
160
|
+
--accent: #ffffff;
|
|
161
|
+
--accent-foreground: #050505;
|
|
162
|
+
--destructive: #ff5c5c;
|
|
163
|
+
--border: #333333;
|
|
164
|
+
--input: #333333;
|
|
165
|
+
--ring: #ffffff;
|
|
166
|
+
--glow: rgba(255, 255, 255, 0.25);
|
|
167
|
+
--glow-soft: rgba(255, 255, 255, 0.08);
|
|
168
|
+
--scanline-opacity: 0.45;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* black-on-white terminal (e-ink / printout) */
|
|
172
|
+
html[data-theme="paper"] {
|
|
173
|
+
--background: #fafafa;
|
|
174
|
+
--foreground: #1f1f1f;
|
|
175
|
+
--card: #f1f1f1;
|
|
176
|
+
--card-foreground: #1f1f1f;
|
|
177
|
+
--popover: #f1f1f1;
|
|
178
|
+
--popover-foreground: #1f1f1f;
|
|
179
|
+
--primary: #000000;
|
|
180
|
+
--primary-foreground: #fafafa;
|
|
181
|
+
--secondary: #efefef;
|
|
182
|
+
--secondary-foreground: #1f1f1f;
|
|
183
|
+
--muted: #efefef;
|
|
184
|
+
--muted-foreground: #595959;
|
|
185
|
+
--accent: #000000;
|
|
186
|
+
--accent-foreground: #fafafa;
|
|
187
|
+
--destructive: #b3261e;
|
|
188
|
+
--border: #d4d4d4;
|
|
189
|
+
--input: #d4d4d4;
|
|
190
|
+
--ring: #000000;
|
|
191
|
+
--glow: rgba(0, 0, 0, 0.06);
|
|
192
|
+
--glow-soft: rgba(0, 0, 0, 0.04);
|
|
193
|
+
--scanline-opacity: 0.12;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* ===== base.css ===== */
|
|
197
|
+
/*
|
|
198
|
+
* danieldeusing-design — base layer.
|
|
199
|
+
*
|
|
200
|
+
* The document-level look of the terminal theme: monospace body, CRT scanline
|
|
201
|
+
* overlay, phosphor selection, themed default border colour. Resolves against
|
|
202
|
+
* tokens.css (load that first). Plain CSS — no Tailwind required.
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
html {
|
|
206
|
+
scroll-behavior: smooth;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Default any element's border to the themed colour, so a bare `border-width`
|
|
210
|
+
(or a Tailwind `border` utility) paints in the theme border rather than the
|
|
211
|
+
element's currentColor. Mirrors the canonical `* { @apply border-border }`. */
|
|
212
|
+
*,
|
|
213
|
+
*::before,
|
|
214
|
+
*::after {
|
|
215
|
+
border-color: var(--border);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* Visible, on-theme focus ring for keyboard navigation. */
|
|
219
|
+
:focus-visible {
|
|
220
|
+
outline: 2px solid var(--ring);
|
|
221
|
+
outline-offset: 2px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
body {
|
|
225
|
+
background: var(--background);
|
|
226
|
+
color: var(--foreground);
|
|
227
|
+
font-family: var(--font-mono);
|
|
228
|
+
font-size: 0.75rem;
|
|
229
|
+
line-height: 1.5;
|
|
230
|
+
overflow-x: hidden;
|
|
231
|
+
-webkit-font-smoothing: antialiased;
|
|
232
|
+
-moz-osx-font-smoothing: grayscale;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Tailwind v4's reset drops the default button cursor — restore it for all
|
|
236
|
+
interactive controls (buttons, summaries, role=button). */
|
|
237
|
+
button:not(:disabled),
|
|
238
|
+
summary,
|
|
239
|
+
[role="button"] {
|
|
240
|
+
cursor: pointer;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* CRT scanlines: a fixed, non-interactive overlay above the page. Intensity is
|
|
244
|
+
per-theme via --scanline-opacity. */
|
|
245
|
+
body::after {
|
|
246
|
+
content: "";
|
|
247
|
+
position: fixed;
|
|
248
|
+
inset: 0;
|
|
249
|
+
z-index: 40;
|
|
250
|
+
pointer-events: none;
|
|
251
|
+
background: repeating-linear-gradient(
|
|
252
|
+
0deg,
|
|
253
|
+
rgba(0, 0, 0, 0.25) 0px,
|
|
254
|
+
rgba(0, 0, 0, 0.25) 1px,
|
|
255
|
+
transparent 1px,
|
|
256
|
+
transparent 3px
|
|
257
|
+
);
|
|
258
|
+
opacity: var(--scanline-opacity);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
::selection {
|
|
262
|
+
background: var(--primary);
|
|
263
|
+
color: var(--primary-foreground);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* ===== components.css ===== */
|
|
267
|
+
/*
|
|
268
|
+
* danieldeusing-design — component layer.
|
|
269
|
+
*
|
|
270
|
+
* Reusable, framework-agnostic primitives in plain CSS (no Tailwind @apply), so
|
|
271
|
+
* they render identically in an Astro/React/Angular app, a Tauri webview, or a
|
|
272
|
+
* single static HTML file. Every value resolves against tokens.css.
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
276
|
+
Phosphor glow — for bright, "lit" elements (brand mark, active items).
|
|
277
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
278
|
+
.glow {
|
|
279
|
+
color: var(--primary);
|
|
280
|
+
text-shadow: 0 0 8px var(--glow);
|
|
281
|
+
}
|
|
282
|
+
.glow-lg {
|
|
283
|
+
color: var(--primary);
|
|
284
|
+
text-shadow: 0 0 12px var(--glow);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
288
|
+
Shell affordances — `$ command` section headers and `# comment` lines.
|
|
289
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
290
|
+
.prompt {
|
|
291
|
+
font-size: 0.75rem;
|
|
292
|
+
font-weight: 700;
|
|
293
|
+
color: var(--muted-foreground);
|
|
294
|
+
}
|
|
295
|
+
.prompt::before {
|
|
296
|
+
content: "$ ";
|
|
297
|
+
color: var(--primary);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.comment::before {
|
|
301
|
+
content: "# ";
|
|
302
|
+
color: var(--border);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* Blinking block cursor — pair with a brand mark or end-of-line. */
|
|
306
|
+
.cursor-block {
|
|
307
|
+
display: inline-block;
|
|
308
|
+
width: 0.55em;
|
|
309
|
+
height: 1em;
|
|
310
|
+
margin-left: 8px;
|
|
311
|
+
background: var(--primary);
|
|
312
|
+
vertical-align: baseline;
|
|
313
|
+
transform: translateY(0.12em);
|
|
314
|
+
animation: ddd-blink 1.1s step-end infinite;
|
|
315
|
+
}
|
|
316
|
+
@keyframes ddd-blink {
|
|
317
|
+
50% {
|
|
318
|
+
opacity: 0;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
323
|
+
Primary CTA — `> label` with a phosphor glow that lifts on hover.
|
|
324
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
325
|
+
.btn-terminal {
|
|
326
|
+
display: inline-block;
|
|
327
|
+
background: var(--primary);
|
|
328
|
+
color: var(--primary-foreground);
|
|
329
|
+
font-weight: 700;
|
|
330
|
+
padding: 12px 24px;
|
|
331
|
+
box-shadow: 0 0 16px var(--glow);
|
|
332
|
+
transition:
|
|
333
|
+
box-shadow 0.15s ease,
|
|
334
|
+
transform 0.15s ease;
|
|
335
|
+
}
|
|
336
|
+
.btn-terminal::before {
|
|
337
|
+
content: "> ";
|
|
338
|
+
}
|
|
339
|
+
.btn-terminal:hover {
|
|
340
|
+
box-shadow: 0 0 28px var(--glow);
|
|
341
|
+
transform: translateY(-2px);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Quiet, underlined link that warms to the primary colour on hover. */
|
|
345
|
+
.link-quiet {
|
|
346
|
+
color: var(--muted-foreground);
|
|
347
|
+
text-decoration: underline;
|
|
348
|
+
text-underline-offset: 4px;
|
|
349
|
+
transition: color 0.15s ease;
|
|
350
|
+
}
|
|
351
|
+
.link-quiet:hover {
|
|
352
|
+
color: var(--primary);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* ASCII horizontal rule — a clipped, full-width row of box-drawing dashes that
|
|
356
|
+
reads like a terminal separator. Use on an <hr> or <div>; the dashes are a
|
|
357
|
+
decorative ::before clipped to the element width. */
|
|
358
|
+
.ascii-rule {
|
|
359
|
+
margin: 1rem 0;
|
|
360
|
+
border: 0;
|
|
361
|
+
color: var(--border);
|
|
362
|
+
line-height: 1;
|
|
363
|
+
white-space: nowrap;
|
|
364
|
+
overflow: hidden;
|
|
365
|
+
user-select: none;
|
|
366
|
+
}
|
|
367
|
+
.ascii-rule::before {
|
|
368
|
+
content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────";
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
372
|
+
Card — bordered surface that warms its border and glows softly on hover.
|
|
373
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
374
|
+
.card-terminal {
|
|
375
|
+
background: var(--card);
|
|
376
|
+
border: 1px solid var(--border);
|
|
377
|
+
transition:
|
|
378
|
+
border-color 0.15s ease,
|
|
379
|
+
box-shadow 0.15s ease;
|
|
380
|
+
}
|
|
381
|
+
.card-terminal:hover {
|
|
382
|
+
border-color: var(--primary);
|
|
383
|
+
box-shadow: 0 0 20px var(--glow-soft);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
387
|
+
Dropdown — a <details class="dropdown"> with a <summary> trigger and a
|
|
388
|
+
floating panel. Pairs with runtime/dropdown.js (close-others, click-away,
|
|
389
|
+
Escape). The panel opens UPWARD by default (for status-bar / footer menus);
|
|
390
|
+
add .dropdown-panel--down to open below the trigger.
|
|
391
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
392
|
+
.dropdown {
|
|
393
|
+
position: relative;
|
|
394
|
+
}
|
|
395
|
+
.dropdown > summary {
|
|
396
|
+
display: inline-flex;
|
|
397
|
+
align-items: center;
|
|
398
|
+
gap: 6px;
|
|
399
|
+
cursor: pointer;
|
|
400
|
+
user-select: none;
|
|
401
|
+
list-style: none;
|
|
402
|
+
color: var(--muted-foreground);
|
|
403
|
+
transition: color 0.15s ease;
|
|
404
|
+
}
|
|
405
|
+
.dropdown > summary::-webkit-details-marker {
|
|
406
|
+
display: none;
|
|
407
|
+
}
|
|
408
|
+
.dropdown > summary:hover,
|
|
409
|
+
.dropdown[open] > summary {
|
|
410
|
+
color: var(--primary);
|
|
411
|
+
}
|
|
412
|
+
.dropdown-panel {
|
|
413
|
+
position: absolute;
|
|
414
|
+
right: 0;
|
|
415
|
+
bottom: calc(100% + 12px);
|
|
416
|
+
z-index: 50;
|
|
417
|
+
min-width: 128px;
|
|
418
|
+
margin: 0;
|
|
419
|
+
padding: 4px 0;
|
|
420
|
+
list-style: none;
|
|
421
|
+
background: var(--card);
|
|
422
|
+
border: 1px solid var(--border);
|
|
423
|
+
border-radius: 0;
|
|
424
|
+
box-shadow: 0 0 20px var(--glow-soft);
|
|
425
|
+
}
|
|
426
|
+
/* open below the trigger instead of above */
|
|
427
|
+
.dropdown-panel--down {
|
|
428
|
+
top: calc(100% + 8px);
|
|
429
|
+
bottom: auto;
|
|
430
|
+
left: 0;
|
|
431
|
+
right: auto;
|
|
432
|
+
}
|
|
433
|
+
.dropdown-item {
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
gap: 8px;
|
|
437
|
+
width: 100%;
|
|
438
|
+
padding: 5px 14px;
|
|
439
|
+
text-align: left;
|
|
440
|
+
font: inherit;
|
|
441
|
+
line-height: 1.5;
|
|
442
|
+
background: none;
|
|
443
|
+
border: 0;
|
|
444
|
+
color: var(--muted-foreground);
|
|
445
|
+
cursor: pointer;
|
|
446
|
+
white-space: nowrap;
|
|
447
|
+
transition: color 0.15s ease;
|
|
448
|
+
}
|
|
449
|
+
.dropdown-item:hover {
|
|
450
|
+
color: var(--primary);
|
|
451
|
+
background: var(--muted);
|
|
452
|
+
}
|
|
453
|
+
.dropdown-item[aria-current="true"],
|
|
454
|
+
html:not([data-theme]) .dropdown-item[data-theme-value="warm"],
|
|
455
|
+
html[data-theme="green"] .dropdown-item[data-theme-value="green"],
|
|
456
|
+
html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],
|
|
457
|
+
html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],
|
|
458
|
+
html[data-theme="warm"] .dropdown-item[data-theme-value="warm"] {
|
|
459
|
+
color: var(--primary);
|
|
460
|
+
text-shadow: 0 0 8px var(--glow);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
464
|
+
ELI5 — an "explain like I'm 5" callout box (first-time-term explainers).
|
|
465
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
466
|
+
.eli5 {
|
|
467
|
+
margin: 1.25em 0;
|
|
468
|
+
padding: 0.7em 1em;
|
|
469
|
+
color: var(--foreground);
|
|
470
|
+
background: color-mix(in srgb, var(--primary) 7%, var(--card));
|
|
471
|
+
border: 1px solid var(--border);
|
|
472
|
+
border-left: 3px solid var(--primary);
|
|
473
|
+
border-radius: var(--radius);
|
|
474
|
+
font-size: 0.92em;
|
|
475
|
+
line-height: 1.6;
|
|
476
|
+
}
|
|
477
|
+
.eli5::before {
|
|
478
|
+
content: "ELI5";
|
|
479
|
+
display: inline-flex;
|
|
480
|
+
align-items: center;
|
|
481
|
+
justify-content: center;
|
|
482
|
+
margin-right: 0.6em;
|
|
483
|
+
vertical-align: 0.08em;
|
|
484
|
+
font-family: var(--font-mono);
|
|
485
|
+
font-size: 0.72em;
|
|
486
|
+
font-weight: 700;
|
|
487
|
+
line-height: 1;
|
|
488
|
+
letter-spacing: 0.04em;
|
|
489
|
+
padding: 0.34em 0.6em;
|
|
490
|
+
border-radius: 5px;
|
|
491
|
+
background: #b42318;
|
|
492
|
+
color: #fff;
|
|
493
|
+
}
|
|
494
|
+
.eli5-term {
|
|
495
|
+
font-weight: 700;
|
|
496
|
+
color: var(--primary);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
500
|
+
Animation kill-switch — add html.anim-off (e.g. from a footer "animations
|
|
501
|
+
off" toggle) to stop ALL motion regardless of the OS reduced-motion setting.
|
|
502
|
+
runtime/terminal.js also bails when this class is present, so content stays
|
|
503
|
+
visible. Complements the prefers-reduced-motion handling below.
|
|
504
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
505
|
+
html.anim-off *,
|
|
506
|
+
html.anim-off *::before,
|
|
507
|
+
html.anim-off *::after {
|
|
508
|
+
animation: none !important;
|
|
509
|
+
transition: none !important;
|
|
510
|
+
}
|
|
511
|
+
html.anim-off .cursor-block {
|
|
512
|
+
opacity: 1;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
516
|
+
Terminal session animation — `$ command` prompts type out, then their
|
|
517
|
+
section's content reveals like command output. Pairs with
|
|
518
|
+
runtime/terminal.js, which adds html.term-anim pre-paint. With JS disabled
|
|
519
|
+
or prefers-reduced-motion, the gate is never added and nothing is hidden, so
|
|
520
|
+
all content is visible by default (progressive enhancement).
|
|
521
|
+
|
|
522
|
+
Markup: a section gets [data-term]; its prompt uses .prompt; each chunk of
|
|
523
|
+
output gets [data-term-out].
|
|
524
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
525
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
526
|
+
/* pending prompt: fully invisible (incl. the `$ ` prefix), line box reserved */
|
|
527
|
+
html.term-anim [data-term] .prompt:not(.term-live),
|
|
528
|
+
html.term-anim [data-term] .prompt:not(.term-live)::before {
|
|
529
|
+
color: transparent;
|
|
530
|
+
}
|
|
531
|
+
/* pending output: keep layout (no CLS), no interaction until revealed */
|
|
532
|
+
html.term-anim [data-term] [data-term-out]:not(.term-show) {
|
|
533
|
+
visibility: hidden;
|
|
534
|
+
}
|
|
535
|
+
/* phosphor warm-up flicker as output appears */
|
|
536
|
+
html.term-anim [data-term] [data-term-out].term-show {
|
|
537
|
+
animation: ddd-term-output 0.2s steps(3, end) both;
|
|
538
|
+
}
|
|
539
|
+
@keyframes ddd-term-output {
|
|
540
|
+
from {
|
|
541
|
+
opacity: 0;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
/* caret at the typing edge (created by runtime/terminal.js) */
|
|
545
|
+
.term-caret {
|
|
546
|
+
display: inline-block;
|
|
547
|
+
width: 0.55em;
|
|
548
|
+
height: 1em;
|
|
549
|
+
margin-left: 2px;
|
|
550
|
+
background: var(--primary);
|
|
551
|
+
vertical-align: baseline;
|
|
552
|
+
transform: translateY(0.12em);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! danieldeusing-design v0.1.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
|
|
2
|
+
*,*::before,*::after{box-sizing: border-box}*{margin: 0}html{-webkit-text-size-adjust: 100%;text-size-adjust: 100%;tab-size: 4}body{min-height: 100vh;min-height: 100dvh;line-height: 1.5}img,picture,video,canvas,svg{display: block;max-width: 100%}input,button,textarea,select{font: inherit;color: inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap: break-word}ul,ol{list-style: none;padding: 0}a{color: inherit;text-decoration: none}table{border-collapse: collapse}:root{--background: #f5efe2;--foreground: #43352a;--card: #efe7d4;--card-foreground: #43352a;--popover: #efe7d4;--popover-foreground: #43352a;--primary: #8a4516;--primary-foreground: #f8f3e8;--secondary: #ece3cf;--secondary-foreground: #43352a;--muted: #ece3cf;--muted-foreground: #71614e;--accent: #8a4516;--accent-foreground: #f8f3e8;--destructive: #a02c2c;--border: #d9cdb6;--input: #d9cdb6;--ring: #8a4516;--glow: rgba(160,82,45,0.1);--glow-soft: rgba(160,82,45,0.05);--scanline-opacity: 0.15;--radius: 0rem;--font-mono: "JetBrains Mono Variable","JetBrains Mono","Menlo",monospace}html[data-theme="green"]{--background: #020604;--foreground: #4fdd7d;--card: #04110a;--card-foreground: #4fdd7d;--popover: #04110a;--popover-foreground: #4fdd7d;--primary: #33ff66;--primary-foreground: #02160a;--secondary: #071509;--secondary-foreground: #4fdd7d;--muted: #071509;--muted-foreground: #3da45e;--accent: #33ff66;--accent-foreground: #02160a;--destructive: #ff5c5c;--border: #1c4a2c;--input: #1c4a2c;--ring: #33ff66;--glow: rgba(51,255,102,0.35);--glow-soft: rgba(51,255,102,0.12);--scanline-opacity: 0.5}html[data-theme="mono"]{--background: #050505;--foreground: #d4d4d4;--card: #0d0d0d;--card-foreground: #d4d4d4;--popover: #0d0d0d;--popover-foreground: #d4d4d4;--primary: #ffffff;--primary-foreground: #050505;--secondary: #111111;--secondary-foreground: #d4d4d4;--muted: #111111;--muted-foreground: #8a8a8a;--accent: #ffffff;--accent-foreground: #050505;--destructive: #ff5c5c;--border: #333333;--input: #333333;--ring: #ffffff;--glow: rgba(255,255,255,0.25);--glow-soft: rgba(255,255,255,0.08);--scanline-opacity: 0.45}html[data-theme="paper"]{--background: #fafafa;--foreground: #1f1f1f;--card: #f1f1f1;--card-foreground: #1f1f1f;--popover: #f1f1f1;--popover-foreground: #1f1f1f;--primary: #000000;--primary-foreground: #fafafa;--secondary: #efefef;--secondary-foreground: #1f1f1f;--muted: #efefef;--muted-foreground: #595959;--accent: #000000;--accent-foreground: #fafafa;--destructive: #b3261e;--border: #d4d4d4;--input: #d4d4d4;--ring: #000000;--glow: rgba(0,0,0,0.06);--glow-soft: rgba(0,0,0,0.04);--scanline-opacity: 0.12}html{scroll-behavior: smooth}*,*::before,*::after{border-color: var(--border)}:focus-visible{outline: 2px solid var(--ring);outline-offset: 2px}body{background: var(--background);color: var(--foreground);font-family: var(--font-mono);font-size: 0.75rem;line-height: 1.5;overflow-x: hidden;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale}button:not(:disabled),summary,[role="button"]{cursor: pointer}body::after{content: "";position: fixed;inset: 0;z-index: 40;pointer-events: none;background: repeating-linear-gradient( 0deg,rgba(0,0,0,0.25) 0px,rgba(0,0,0,0.25) 1px,transparent 1px,transparent 3px );opacity: var(--scanline-opacity)}::selection{background: var(--primary);color: var(--primary-foreground)}.glow{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.glow-lg{color: var(--primary);text-shadow: 0 0 12px var(--glow)}.prompt{font-size: 0.75rem;font-weight: 700;color: var(--muted-foreground)}.prompt::before{content: "$ ";color: var(--primary)}.comment::before{content: "# ";color: var(--border)}.cursor-block{display: inline-block;width: 0.55em;height: 1em;margin-left: 8px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em);animation: ddd-blink 1.1s step-end infinite}@keyframes ddd-blink{50%{opacity: 0}}.btn-terminal{display: inline-block;background: var(--primary);color: var(--primary-foreground);font-weight: 700;padding: 12px 24px;box-shadow: 0 0 16px var(--glow);transition: box-shadow 0.15s ease,transform 0.15s ease}.btn-terminal::before{content: "> "}.btn-terminal:hover{box-shadow: 0 0 28px var(--glow);transform: translateY(-2px)}.link-quiet{color: var(--muted-foreground);text-decoration: underline;text-underline-offset: 4px;transition: color 0.15s ease}.link-quiet:hover{color: var(--primary)}.ascii-rule{margin: 1rem 0;border: 0;color: var(--border);line-height: 1;white-space: nowrap;overflow: hidden;user-select: none}.ascii-rule::before{content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"}.card-terminal{background: var(--card);border: 1px solid var(--border);transition: border-color 0.15s ease,box-shadow 0.15s ease}.card-terminal:hover{border-color: var(--primary);box-shadow: 0 0 20px var(--glow-soft)}.dropdown{position: relative}.dropdown>summary{display: inline-flex;align-items: center;gap: 6px;cursor: pointer;user-select: none;list-style: none;color: var(--muted-foreground);transition: color 0.15s ease}.dropdown>summary::-webkit-details-marker{display: none}.dropdown>summary:hover,.dropdown[open]>summary{color: var(--primary)}.dropdown-panel{position: absolute;right: 0;bottom: calc(100% + 12px);z-index: 50;min-width: 128px;margin: 0;padding: 4px 0;list-style: none;background: var(--card);border: 1px solid var(--border);border-radius: 0;box-shadow: 0 0 20px var(--glow-soft)}.dropdown-panel--down{top: calc(100% + 8px);bottom: auto;left: 0;right: auto}.dropdown-item{display: flex;align-items: center;gap: 8px;width: 100%;padding: 5px 14px;text-align: left;font: inherit;line-height: 1.5;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;white-space: nowrap;transition: color 0.15s ease}.dropdown-item:hover{color: var(--primary);background: var(--muted)}.dropdown-item[aria-current="true"],html:not([data-theme]) .dropdown-item[data-theme-value="warm"],html[data-theme="green"] .dropdown-item[data-theme-value="green"],html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],html[data-theme="warm"] .dropdown-item[data-theme-value="warm"]{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.eli5{margin: 1.25em 0;padding: 0.7em 1em;color: var(--foreground);background: color-mix(in srgb,var(--primary) 7%,var(--card));border: 1px solid var(--border);border-left: 3px solid var(--primary);border-radius: var(--radius);font-size: 0.92em;line-height: 1.6}.eli5::before{content: "ELI5";display: inline-flex;align-items: center;justify-content: center;margin-right: 0.6em;vertical-align: 0.08em;font-family: var(--font-mono);font-size: 0.72em;font-weight: 700;line-height: 1;letter-spacing: 0.04em;padding: 0.34em 0.6em;border-radius: 5px;background: #b42318;color: #fff}.eli5-term{font-weight: 700;color: var(--primary)}html.anim-off *,html.anim-off *::before,html.anim-off *::after{animation: none !important;transition: none !important}html.anim-off .cursor-block{opacity: 1}@media (prefers-reduced-motion: no-preference){html.term-anim [data-term] .prompt:not(.term-live),html.term-anim [data-term] .prompt:not(.term-live)::before{color: transparent}html.term-anim [data-term] [data-term-out]:not(.term-show){visibility: hidden}html.term-anim [data-term] [data-term-out].term-show{animation: ddd-term-output 0.2s steps(3,end) both}@keyframes ddd-term-output{from{opacity: 0}}.term-caret{display: inline-block;width: 0.55em;height: 1em;margin-left: 2px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em)}}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@danieldeusing/design",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The danieldeusing terminal design system — framework-agnostic CSS tokens, components, and a vanilla-JS runtime for the CRT/JetBrains-Mono look used across danieldeusing.de, seedr, and briefs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Daniel Deusing",
|
|
8
|
+
"homepage": "https://github.com/danieldeusing/danieldeusing-design#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/danieldeusing/danieldeusing-design.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/danieldeusing/danieldeusing-design/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"design-system",
|
|
18
|
+
"design-tokens",
|
|
19
|
+
"css",
|
|
20
|
+
"tailwindcss",
|
|
21
|
+
"tailwind-v4",
|
|
22
|
+
"terminal",
|
|
23
|
+
"crt",
|
|
24
|
+
"theme",
|
|
25
|
+
"danieldeusing"
|
|
26
|
+
],
|
|
27
|
+
"main": "./src/index.css",
|
|
28
|
+
"style": "./src/index.css",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./src/index.css",
|
|
31
|
+
"./tailwind.css": "./src/tailwind.css",
|
|
32
|
+
"./index.css": "./src/index.css",
|
|
33
|
+
"./reset.css": "./src/reset.css",
|
|
34
|
+
"./fonts.css": "./src/fonts.css",
|
|
35
|
+
"./tokens.css": "./src/tokens.css",
|
|
36
|
+
"./base.css": "./src/base.css",
|
|
37
|
+
"./components.css": "./src/components.css",
|
|
38
|
+
"./tokens.json": "./tokens/tokens.json",
|
|
39
|
+
"./runtime": "./runtime/index.js",
|
|
40
|
+
"./runtime/*": "./runtime/*.js",
|
|
41
|
+
"./dist/*": "./dist/*",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"src",
|
|
46
|
+
"runtime",
|
|
47
|
+
"dist",
|
|
48
|
+
"tokens",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE"
|
|
51
|
+
],
|
|
52
|
+
"sideEffects": [
|
|
53
|
+
"*.css"
|
|
54
|
+
],
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "node scripts/build.mjs",
|
|
57
|
+
"prepublishOnly": "node scripts/build.mjs"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* danieldeusing-design — dropdown controller.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour for <details class="dropdown"> menus styled by components.css:
|
|
5
|
+
* opening one closes the others, a click outside closes all, and Escape closes
|
|
6
|
+
* all. Native <details> already handles open/close and keyboard focus, so this
|
|
7
|
+
* is purely the "only one open, dismiss on outside interaction" layer.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {ParentNode} [root=document] Where to look for `details.dropdown`.
|
|
12
|
+
* @returns {(except?: HTMLDetailsElement) => void} A closeAll() you can call
|
|
13
|
+
* manually (e.g. after a menu item triggers navigation).
|
|
14
|
+
*/
|
|
15
|
+
export function initDropdowns(root = document) {
|
|
16
|
+
const dropdowns = /** @type {HTMLDetailsElement[]} */ (
|
|
17
|
+
Array.from(root.querySelectorAll("details.dropdown"))
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const closeAll = (except) => {
|
|
21
|
+
dropdowns.forEach((dropdown) => {
|
|
22
|
+
if (dropdown !== except) dropdown.removeAttribute("open");
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
dropdowns.forEach((dropdown) => {
|
|
27
|
+
dropdown.addEventListener("toggle", () => {
|
|
28
|
+
if (dropdown.open) closeAll(dropdown);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
document.addEventListener("click", (event) => {
|
|
33
|
+
const target = event.target;
|
|
34
|
+
if (!(target instanceof Node) || !dropdowns.some((dropdown) => dropdown.contains(target))) {
|
|
35
|
+
closeAll();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
document.addEventListener("keydown", (event) => {
|
|
40
|
+
if (event.key === "Escape") closeAll();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return closeAll;
|
|
44
|
+
}
|
package/runtime/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* danieldeusing-design — runtime barrel.
|
|
3
|
+
*
|
|
4
|
+
* Optional, dependency-free vanilla-JS enhancements for the terminal theme.
|
|
5
|
+
* Tree-shakeable: import only what you need, e.g.
|
|
6
|
+
*
|
|
7
|
+
* import { applyStoredTheme, initThemeSwitcher } from "@danieldeusing/design/runtime";
|
|
8
|
+
*
|
|
9
|
+
* The CSS works on its own; this layer adds theme switching, the resolution
|
|
10
|
+
* zoom, dropdown behaviour, and the terminal typing animation.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export * from "./theme.js";
|
|
14
|
+
export * from "./zoom.js";
|
|
15
|
+
export * from "./dropdown.js";
|
|
16
|
+
export * from "./terminal.js";
|