@anton-gustafsson/snapshot-core 0.0.4 → 0.0.6
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/dist/snapshot-nav-list.d.ts +10 -5
- package/dist/snapshot-nav-list.js +100 -12
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ export interface NavItem {
|
|
|
8
8
|
route?: string;
|
|
9
9
|
description?: string;
|
|
10
10
|
}
|
|
11
|
-
export type SnapshotNavListVariant = 'list' | 'icon-only';
|
|
11
|
+
export type SnapshotNavListVariant = 'list' | 'icon-only' | 'card';
|
|
12
12
|
/**
|
|
13
13
|
* Visual identity: a contact sheet. Every tile is a "frame" — numbered like a strip
|
|
14
14
|
* of negatives — because that's literally what a snapshot thumbnail is. All colors
|
|
@@ -19,10 +19,12 @@ export declare class SnapshotNavList extends LitElement {
|
|
|
19
19
|
static styles: import("lit").CSSResult;
|
|
20
20
|
items: NavItem[];
|
|
21
21
|
variant: SnapshotNavListVariant;
|
|
22
|
-
/** icon-only tile overlay: tint behind the title so it stays legible over any image. */
|
|
22
|
+
/** icon-only tile overlay: tint behind the title so it stays legible over any image. Transparent by default — opt into a scrim explicitly. */
|
|
23
23
|
overlayTint: 'dark' | 'light' | 'none';
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/** caption background tint strength, 0-1 */
|
|
25
|
+
textOverlayOpacity: number;
|
|
26
|
+
/** image scrim tint strength, 0-1 — 0 keeps the image clear (blur only) */
|
|
27
|
+
imageOverlayOpacity: number;
|
|
26
28
|
/** backdrop blur behind the title, in px */
|
|
27
29
|
overlayBlur: number;
|
|
28
30
|
/** icon-only only: 'bottom' is the caption strip (default), 'center' centers a larger title. */
|
|
@@ -42,7 +44,10 @@ export declare class SnapshotNavList extends LitElement {
|
|
|
42
44
|
willUpdate(changed: Map<string, unknown>): void;
|
|
43
45
|
updated(changed: Map<string, unknown>): void;
|
|
44
46
|
private loadThumb;
|
|
45
|
-
|
|
47
|
+
/** image scrim: blur + its own (usually 0) tint strength — independent of the caption's. */
|
|
48
|
+
private get imageOverlayStyle();
|
|
49
|
+
/** caption background: tint (to pop the text) + the same blur. */
|
|
50
|
+
private get metaStyle();
|
|
46
51
|
private select;
|
|
47
52
|
private edit;
|
|
48
53
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -23,10 +23,12 @@ export class SnapshotNavList extends LitElement {
|
|
|
23
23
|
super(...arguments);
|
|
24
24
|
this.items = [];
|
|
25
25
|
this.variant = 'icon-only';
|
|
26
|
-
/** icon-only tile overlay: tint behind the title so it stays legible over any image. */
|
|
27
|
-
this.overlayTint = '
|
|
28
|
-
/**
|
|
29
|
-
this.
|
|
26
|
+
/** icon-only tile overlay: tint behind the title so it stays legible over any image. Transparent by default — opt into a scrim explicitly. */
|
|
27
|
+
this.overlayTint = 'none';
|
|
28
|
+
/** caption background tint strength, 0-1 */
|
|
29
|
+
this.textOverlayOpacity = 0.35;
|
|
30
|
+
/** image scrim tint strength, 0-1 — 0 keeps the image clear (blur only) */
|
|
31
|
+
this.imageOverlayOpacity = 0;
|
|
30
32
|
/** backdrop blur behind the title, in px */
|
|
31
33
|
this.overlayBlur = 0;
|
|
32
34
|
/** icon-only only: 'bottom' is the caption strip (default), 'center' centers a larger title. */
|
|
@@ -171,7 +173,7 @@ export class SnapshotNavList extends LitElement {
|
|
|
171
173
|
}
|
|
172
174
|
}
|
|
173
175
|
|
|
174
|
-
/* tint
|
|
176
|
+
/* independent from .meta's tint — image-overlay-opacity defaults to 0 so the image stays clear (blur only) */
|
|
175
177
|
.image-overlay {
|
|
176
178
|
position: absolute;
|
|
177
179
|
inset: 0;
|
|
@@ -269,10 +271,15 @@ export class SnapshotNavList extends LitElement {
|
|
|
269
271
|
:host([variant='icon-only']) .meta {
|
|
270
272
|
position: absolute;
|
|
271
273
|
inset: auto 0 0 0;
|
|
274
|
+
margin: var(--snapshot-nav-list-overlay-margin, 0);
|
|
275
|
+
border-radius: var(--snapshot-nav-list-overlay-radius, 0);
|
|
272
276
|
align-items: flex-start;
|
|
273
277
|
gap: 0.15rem;
|
|
274
278
|
padding: 0.4rem 0.5rem;
|
|
275
279
|
color: var(--overlay-text, #fff);
|
|
280
|
+
background: var(--overlay-bg, transparent);
|
|
281
|
+
backdrop-filter: blur(var(--overlay-blur, 0px));
|
|
282
|
+
-webkit-backdrop-filter: blur(var(--overlay-blur, 0px));
|
|
276
283
|
}
|
|
277
284
|
:host([variant='icon-only']) .label {
|
|
278
285
|
white-space: normal;
|
|
@@ -293,6 +300,72 @@ export class SnapshotNavList extends LitElement {
|
|
|
293
300
|
font-weight: 600;
|
|
294
301
|
text-align: center;
|
|
295
302
|
}
|
|
303
|
+
|
|
304
|
+
/* card: a contained (never cropped) preview above real body text below it —
|
|
305
|
+
text never sits on top of the image, so unlike icon-only it needs no
|
|
306
|
+
overlay tint to stay legible. Modeled on a typical "preview card"
|
|
307
|
+
pattern: framed shot, title + description underneath, shadow on hover. */
|
|
308
|
+
:host([variant='card']) ul {
|
|
309
|
+
display: grid;
|
|
310
|
+
grid-template-columns: repeat(auto-fill, minmax(var(--snapshot-nav-list-card-min-width, 220px), 1fr));
|
|
311
|
+
gap: var(--snapshot-nav-list-card-gap, 1.25rem);
|
|
312
|
+
}
|
|
313
|
+
:host([variant='card']) li {
|
|
314
|
+
flex-direction: column;
|
|
315
|
+
align-items: stretch;
|
|
316
|
+
gap: 0;
|
|
317
|
+
padding: var(--snapshot-nav-list-card-padding, 0.5rem);
|
|
318
|
+
background: var(--snapshot-nav-list-card-bg, transparent);
|
|
319
|
+
border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
|
320
|
+
box-shadow: none;
|
|
321
|
+
transition:
|
|
322
|
+
box-shadow var(--snapshot-nav-list-card-transition-dur, 0.15s) ease,
|
|
323
|
+
border-color var(--snapshot-nav-list-card-transition-dur, 0.15s) ease;
|
|
324
|
+
}
|
|
325
|
+
:host([variant='card']) li:hover,
|
|
326
|
+
:host([variant='card']) li:focus-visible {
|
|
327
|
+
background: var(--snapshot-nav-list-card-bg, transparent);
|
|
328
|
+
box-shadow: var(--snapshot-nav-list-card-shadow, 0 2px 8px color-mix(in srgb, currentColor 18%, transparent));
|
|
329
|
+
border-color: color-mix(in srgb, currentColor 22%, transparent);
|
|
330
|
+
}
|
|
331
|
+
:host([variant='card']) li:focus-visible {
|
|
332
|
+
outline: none;
|
|
333
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-accent) 55%, transparent);
|
|
334
|
+
}
|
|
335
|
+
:host([variant='card']) li:focus-visible .thumb-wrap {
|
|
336
|
+
outline: none;
|
|
337
|
+
}
|
|
338
|
+
:host([variant='card']) .thumb-wrap {
|
|
339
|
+
width: 100%;
|
|
340
|
+
height: auto;
|
|
341
|
+
aspect-ratio: 2 / 1;
|
|
342
|
+
border-radius: var(--snapshot-nav-list-radius-sm, 7px);
|
|
343
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent);
|
|
344
|
+
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
345
|
+
display: grid;
|
|
346
|
+
place-items: center;
|
|
347
|
+
}
|
|
348
|
+
:host([variant='card']) .thumb-wrap::before,
|
|
349
|
+
:host([variant='card']) .thumb-wrap::after {
|
|
350
|
+
display: none;
|
|
351
|
+
}
|
|
352
|
+
:host([variant='card']) img.thumb {
|
|
353
|
+
/* contain, not cover — the whole dashboard stays readable, nothing cropped */
|
|
354
|
+
object-fit: contain;
|
|
355
|
+
}
|
|
356
|
+
:host([variant='card']) .meta {
|
|
357
|
+
padding: 0.75rem 0.5rem 0.5rem;
|
|
358
|
+
gap: 0.25rem;
|
|
359
|
+
}
|
|
360
|
+
:host([variant='card']) .label {
|
|
361
|
+
white-space: normal;
|
|
362
|
+
font-size: 1rem;
|
|
363
|
+
font-weight: 600;
|
|
364
|
+
}
|
|
365
|
+
:host([variant='card']) .description {
|
|
366
|
+
white-space: normal;
|
|
367
|
+
font-size: 0.8125rem;
|
|
368
|
+
}
|
|
296
369
|
`; }
|
|
297
370
|
subscribeToService() {
|
|
298
371
|
this.unsubscribe?.();
|
|
@@ -366,13 +439,24 @@ export class SnapshotNavList extends LitElement {
|
|
|
366
439
|
this.requestUpdate();
|
|
367
440
|
}
|
|
368
441
|
}
|
|
369
|
-
|
|
442
|
+
/** image scrim: blur + its own (usually 0) tint strength — independent of the caption's. */
|
|
443
|
+
get imageOverlayStyle() {
|
|
444
|
+
const blur = `${this.overlayBlur}px`;
|
|
445
|
+
if (this.overlayTint === 'none' || this.imageOverlayOpacity === 0) {
|
|
446
|
+
return { '--overlay-blur': blur };
|
|
447
|
+
}
|
|
448
|
+
const tintColor = this.overlayTint === 'light' ? '#fff' : '#000';
|
|
449
|
+
const bg = `color-mix(in srgb, ${tintColor} ${Math.round(this.imageOverlayOpacity * 100)}%, transparent)`;
|
|
450
|
+
return { '--overlay-bg': bg, '--overlay-blur': blur };
|
|
451
|
+
}
|
|
452
|
+
/** caption background: tint (to pop the text) + the same blur. */
|
|
453
|
+
get metaStyle() {
|
|
370
454
|
const blur = `${this.overlayBlur}px`;
|
|
371
455
|
if (this.overlayTint === 'none') {
|
|
372
456
|
return { '--overlay-bg': 'transparent', '--overlay-text': 'inherit', '--overlay-blur': blur };
|
|
373
457
|
}
|
|
374
458
|
const tintColor = this.overlayTint === 'light' ? '#fff' : '#000';
|
|
375
|
-
const bg = `color-mix(in srgb, ${tintColor} ${Math.round(this.
|
|
459
|
+
const bg = `color-mix(in srgb, ${tintColor} ${Math.round(this.textOverlayOpacity * 100)}%, transparent)`;
|
|
376
460
|
const text = this.overlayTint === 'light' ? '#111' : '#fff';
|
|
377
461
|
return { '--overlay-bg': bg, '--overlay-text': text, '--overlay-blur': blur };
|
|
378
462
|
}
|
|
@@ -392,7 +476,8 @@ export class SnapshotNavList extends LitElement {
|
|
|
392
476
|
}));
|
|
393
477
|
}
|
|
394
478
|
render() {
|
|
395
|
-
const
|
|
479
|
+
const imageOverlayStyle = this.imageOverlayStyle;
|
|
480
|
+
const metaStyle = this.metaStyle;
|
|
396
481
|
return html `
|
|
397
482
|
<ul role="listbox">
|
|
398
483
|
${this.items.map((item) => html `
|
|
@@ -415,7 +500,7 @@ export class SnapshotNavList extends LitElement {
|
|
|
415
500
|
>${item.icon ? (isMarkupIcon(item.icon) ? unsafeHTML(item.icon) : item.icon) : ''}</span
|
|
416
501
|
>
|
|
417
502
|
</div>`}
|
|
418
|
-
<div class="image-overlay" part="overlay" style=${styleMap(
|
|
503
|
+
<div class="image-overlay" part="overlay" style=${styleMap(imageOverlayStyle)}></div>
|
|
419
504
|
${this.editable
|
|
420
505
|
? html `<button
|
|
421
506
|
type="button"
|
|
@@ -428,7 +513,7 @@ export class SnapshotNavList extends LitElement {
|
|
|
428
513
|
</button>`
|
|
429
514
|
: ''}
|
|
430
515
|
</div>
|
|
431
|
-
<div class="meta" part="meta">
|
|
516
|
+
<div class="meta" part="meta" style=${styleMap(metaStyle)}>
|
|
432
517
|
<span class="label" part="label">${item.label}</span>
|
|
433
518
|
${item.description ? html `<span class="description" part="description">${item.description}</span>` : ''}
|
|
434
519
|
</div>
|
|
@@ -448,8 +533,11 @@ __decorate([
|
|
|
448
533
|
property({ attribute: 'overlay-tint' })
|
|
449
534
|
], SnapshotNavList.prototype, "overlayTint", void 0);
|
|
450
535
|
__decorate([
|
|
451
|
-
property({ type: Number, attribute: 'overlay-opacity' })
|
|
452
|
-
], SnapshotNavList.prototype, "
|
|
536
|
+
property({ type: Number, attribute: 'text-overlay-opacity' })
|
|
537
|
+
], SnapshotNavList.prototype, "textOverlayOpacity", void 0);
|
|
538
|
+
__decorate([
|
|
539
|
+
property({ type: Number, attribute: 'image-overlay-opacity' })
|
|
540
|
+
], SnapshotNavList.prototype, "imageOverlayOpacity", void 0);
|
|
453
541
|
__decorate([
|
|
454
542
|
property({ type: Number, attribute: 'overlay-blur' })
|
|
455
543
|
], SnapshotNavList.prototype, "overlayBlur", void 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anton-gustafsson/snapshot-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "A pluggable snapshot service that turns any DOM element into a stored, shareable image, plus an optional <snapshot-nav-list> web component to display them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|