@birdycom/omniaui 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +21 -21
- package/bin/lib/add.mjs +126 -126
- package/bin/lib/catalog.mjs +169 -169
- package/bin/lib/project.mjs +90 -90
- package/bin/omniaui.mjs +69 -69
- package/dist/code-block.css +25 -25
- package/dist/components-extra.css +916 -914
- package/dist/components.css +6565 -6469
- package/dist/components.min.css +1 -1
- package/dist/data-table.d.ts +9 -9
- package/dist/data-table.js +505 -505
- package/dist/docs-ui.css +267 -265
- package/dist/oc-theme.css +69 -69
- package/dist/parts/app-accordion-accent.css +60 -60
- package/dist/parts/app-alpha-tabs.css +68 -68
- package/dist/parts/app-busy-overlay.css +25 -25
- package/dist/parts/app-column-menu.css +85 -85
- package/dist/parts/app-confirm-dialog.css +70 -70
- package/dist/parts/app-cookie-consent.css +63 -63
- package/dist/parts/app-data-table.css +174 -174
- package/dist/parts/app-greeting.css +47 -47
- package/dist/parts/app-list-toolbar.css +81 -81
- package/dist/parts/app-page-header.css +54 -54
- package/dist/parts/app-severity-card.css +91 -91
- package/dist/parts/app-sidebar-dark.css +15 -15
- package/dist/parts/app-sortable-row.css +52 -52
- package/dist/parts/app-stat-card.css +68 -68
- package/dist/parts/app-table-actions.css +71 -71
- package/dist/parts/app-table-compact.css +54 -54
- package/dist/parts/app-top-progress.css +68 -68
- package/dist/parts/app-tree.css +104 -104
- package/dist/parts/app-upgrade-banner.css +90 -90
- package/dist/parts/app-version-banner.css +80 -80
- package/dist/parts/data-chart-line.css +167 -167
- package/dist/parts/forms-affix-input.css +75 -75
- package/dist/parts/forms-barcode-input.css +75 -75
- package/dist/parts/forms-chip-filter.css +91 -91
- package/dist/parts/forms-color-select.css +97 -89
- package/dist/parts/forms-decimal-input.css +51 -51
- package/dist/parts/forms-filter-counts.css +94 -94
- package/dist/parts/forms-language-select.css +89 -76
- package/dist/parts/forms-number-input.css +98 -95
- package/dist/parts/forms-password-requirements.css +55 -55
- package/dist/parts/forms-phone-input.css +85 -85
- package/dist/parts/forms-time-input.css +74 -74
- package/dist/parts/forms-toggle-field.css +69 -69
- package/dist/parts/media-art.css +21 -21
- package/dist/parts/media-attachment.css +160 -160
- package/dist/parts/media-browser-frame.css +73 -73
- package/dist/parts/media-card.css +83 -83
- package/dist/parts/media-chat-composer.css +90 -90
- package/dist/parts/media-doc-viewer.css +151 -151
- package/dist/parts/media-emoji-picker.css +88 -88
- package/dist/parts/media-entity-card.css +52 -52
- package/dist/parts/media-flip-card.css +78 -78
- package/dist/parts/media-image-zoom.css +68 -68
- package/dist/parts/media-lightbox.css +131 -131
- package/dist/parts/media-message-thread.css +136 -136
- package/dist/parts/media-message.css +160 -160
- package/dist/parts/media-row.css +78 -78
- package/dist/parts/media-stack-card.css +82 -82
- package/dist/parts/media-terminal-log.css +76 -76
- package/dist/parts/media-thumb.css +71 -71
- package/dist/parts/site-fact-list.css +25 -25
- package/dist/parts/site-link-arrow.css +34 -34
- package/dist/parts/site-marquee.css +34 -34
- package/dist/parts/site-next-teaser.css +75 -75
- package/dist/parts/site-price-card.css +91 -75
- package/dist/parts/site-product-mark.css +66 -66
- package/dist/parts/site-project-card.css +111 -111
- package/dist/parts/site-prose.css +124 -124
- package/dist/parts/site-stack-list.css +48 -48
- package/dist/parts/site-timeline.css +54 -54
- package/dist/showcase.css +410 -404
- package/package.json +69 -69
- package/snippets/accordion-accent.html +24 -24
- package/snippets/accordion.html +11 -11
- package/snippets/affix-input.html +30 -30
- package/snippets/alert-dialog.html +22 -22
- package/snippets/alert.html +5 -5
- package/snippets/alpha-tabs.html +37 -37
- package/snippets/aspect-ratio.html +15 -15
- package/snippets/attachment.html +43 -43
- package/snippets/avatar.html +6 -6
- package/snippets/back-link.html +5 -5
- package/snippets/badge.html +5 -5
- package/snippets/barcode-input.html +18 -18
- package/snippets/breadcrumb.html +6 -6
- package/snippets/browser-frame.html +18 -18
- package/snippets/busy-overlay.html +31 -31
- package/snippets/button-group.html +21 -21
- package/snippets/button.html +8 -8
- package/snippets/calendar.html +43 -43
- package/snippets/card.html +17 -17
- package/snippets/carousel.html +21 -21
- package/snippets/chart-line.html +46 -46
- package/snippets/chart.html +27 -27
- package/snippets/chat-composer.html +21 -21
- package/snippets/checkbox.html +5 -5
- package/snippets/checklist.html +23 -23
- package/snippets/chip-filter.html +14 -14
- package/snippets/code-window.html +20 -20
- package/snippets/collapsible.html +19 -19
- package/snippets/color-field.html +13 -13
- package/snippets/color-select.html +18 -18
- package/snippets/column-menu.html +38 -38
- package/snippets/combobox.html +19 -19
- package/snippets/command.html +24 -24
- package/snippets/confirm-dialog.html +32 -32
- package/snippets/context-menu.html +25 -25
- package/snippets/cookie-consent.html +70 -70
- package/snippets/copy-field.html +19 -19
- package/snippets/counter.html +2 -2
- package/snippets/data-table.html +151 -151
- package/snippets/date-picker.html +32 -32
- package/snippets/decimal-input.html +20 -20
- package/snippets/definition-list.html +20 -20
- package/snippets/demo-panel.html +18 -18
- package/snippets/doc-viewer.html +58 -58
- package/snippets/drawer.html +30 -30
- package/snippets/dropdown-menu.html +27 -27
- package/snippets/dropdown.html +9 -9
- package/snippets/dropzone.html +13 -13
- package/snippets/emoji-picker.html +51 -51
- package/snippets/empty-state.html +17 -17
- package/snippets/entity-card.html +26 -26
- package/snippets/expandable-table.html +26 -26
- package/snippets/fact-list.html +14 -14
- package/snippets/filter-counts.html +30 -30
- package/snippets/flip-card.html +22 -22
- package/snippets/form-field.html +6 -6
- package/snippets/greeting.html +22 -22
- package/snippets/heading.html +14 -14
- package/snippets/hover-card.html +18 -18
- package/snippets/image-zoom.html +30 -30
- package/snippets/input-group.html +10 -10
- package/snippets/input.html +5 -5
- package/snippets/item.html +26 -26
- package/snippets/kbd.html +13 -13
- package/snippets/label.html +9 -9
- package/snippets/language-select.html +26 -26
- package/snippets/launcher-card.html +14 -14
- package/snippets/lightbox.html +50 -50
- package/snippets/link-arrow.html +10 -10
- package/snippets/list-toolbar.html +33 -33
- package/snippets/marquee.html +15 -15
- package/snippets/media-card.html +28 -28
- package/snippets/media-row.html +21 -21
- package/snippets/media-thumb.html +12 -12
- package/snippets/menubar.html +30 -30
- package/snippets/message-thread.html +123 -123
- package/snippets/message.html +51 -51
- package/snippets/modal.html +15 -15
- package/snippets/native-select.html +15 -15
- package/snippets/navmenu.html +23 -23
- package/snippets/next-teaser.html +15 -15
- package/snippets/number-input.html +27 -27
- package/snippets/otp-input.html +9 -9
- package/snippets/page-header.html +24 -24
- package/snippets/pagination.html +6 -6
- package/snippets/password-input.html +24 -24
- package/snippets/password-requirements.html +30 -30
- package/snippets/phone-input.html +22 -22
- package/snippets/popover.html +15 -15
- package/snippets/price-card.html +34 -34
- package/snippets/product-mark.html +13 -13
- package/snippets/progress.html +4 -4
- package/snippets/project-card.html +23 -23
- package/snippets/prose.html +54 -54
- package/snippets/radio.html +17 -17
- package/snippets/recovery-codes.html +20 -20
- package/snippets/resizable.html +16 -16
- package/snippets/scroll-area.html +20 -20
- package/snippets/search.html +8 -8
- package/snippets/segmented.html +11 -11
- package/snippets/select.html +7 -7
- package/snippets/separator.html +15 -15
- package/snippets/severity-card.html +35 -35
- package/snippets/sheet.html +32 -32
- package/snippets/sidebar-docs.html +24 -24
- package/snippets/sidebar.html +55 -55
- package/snippets/site-footer.html +6 -6
- package/snippets/site-header.html +26 -26
- package/snippets/skeleton.html +4 -4
- package/snippets/slider.html +17 -17
- package/snippets/sortable-row.html +31 -31
- package/snippets/spinner.html +14 -14
- package/snippets/stack-card.html +17 -17
- package/snippets/stack-list.html +16 -16
- package/snippets/stat-card.html +24 -24
- package/snippets/stepper.html +13 -13
- package/snippets/switch.html +6 -6
- package/snippets/table-actions.html +39 -39
- package/snippets/table-compact.html +24 -24
- package/snippets/table.html +29 -29
- package/snippets/tabs.html +9 -9
- package/snippets/tag-input.html +60 -17
- package/snippets/terminal-log.html +23 -23
- package/snippets/textarea.html +3 -3
- package/snippets/theme-switch.html +6 -6
- package/snippets/time-input.html +26 -26
- package/snippets/timeline.html +28 -28
- package/snippets/toast-stack.html +10 -10
- package/snippets/toast.html +36 -36
- package/snippets/toc.html +13 -13
- package/snippets/toggle-field.html +20 -20
- package/snippets/toggle.html +22 -22
- package/snippets/tooltip.html +4 -4
- package/snippets/top-progress.html +12 -12
- package/snippets/tree.html +38 -38
- package/snippets/upgrade-banner.html +28 -28
- package/snippets/user.html +15 -15
- package/snippets/version-banner.html +15 -15
package/dist/parts/media-row.css
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-row.css | Map: list -> row grid (thumb | text | menu) -> title (stretched link) + meta
|
|
2
|
-
-> menu button -> numbered playlist (CSS counter) -> current item -> hover -> small screens
|
|
3
|
-
Media row: a compact horizontal item for "up next" lists and playlists. The thumb is a .oc-media-thumb. */
|
|
4
|
-
|
|
5
|
-
.oc-media-row-list { display: grid; gap: 0.25rem; margin: 0; padding: 0; list-style: none; inline-size: 100%; counter-reset: oc-media-row; }
|
|
6
|
-
|
|
7
|
-
.oc-media-row {
|
|
8
|
-
position: relative;
|
|
9
|
-
display: grid;
|
|
10
|
-
grid-template-columns: 10rem minmax(0, 1fr) auto;
|
|
11
|
-
gap: 0.75rem;
|
|
12
|
-
align-items: start;
|
|
13
|
-
padding: 0.375rem;
|
|
14
|
-
border-radius: var(--oc-radius);
|
|
15
|
-
color: var(--oc-foreground);
|
|
16
|
-
}
|
|
17
|
-
.oc-media-row:hover { background: var(--oc-surface); }
|
|
18
|
-
.oc-media-row > .oc-media-thumb { border-radius: calc(var(--oc-radius) - 2px); }
|
|
19
|
-
|
|
20
|
-
.oc-media-row__text { display: grid; gap: 0.2rem; min-inline-size: 0; }
|
|
21
|
-
.oc-media-row__title {
|
|
22
|
-
margin: 0;
|
|
23
|
-
font-size: 0.875rem;
|
|
24
|
-
font-weight: 600;
|
|
25
|
-
line-height: 1.35;
|
|
26
|
-
display: -webkit-box;
|
|
27
|
-
-webkit-box-orient: vertical;
|
|
28
|
-
-webkit-line-clamp: 2;
|
|
29
|
-
line-clamp: 2;
|
|
30
|
-
overflow: hidden;
|
|
31
|
-
}
|
|
32
|
-
.oc-media-row__title > a { color: inherit; text-decoration: none; }
|
|
33
|
-
.oc-media-row__title > a::after { content: ""; position: absolute; inset: 0; border-radius: var(--oc-radius); }
|
|
34
|
-
.oc-media-row__title > a:focus-visible { outline: none; }
|
|
35
|
-
.oc-media-row__title > a:focus-visible::after { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
36
|
-
.oc-media-row__meta { margin: 0; font-size: 0.75rem; color: var(--oc-muted-foreground); }
|
|
37
|
-
|
|
38
|
-
/* ⋮ button above the stretched link. */
|
|
39
|
-
.oc-media-row__menu {
|
|
40
|
-
position: relative;
|
|
41
|
-
z-index: 1;
|
|
42
|
-
display: grid;
|
|
43
|
-
place-items: center;
|
|
44
|
-
inline-size: 1.75rem;
|
|
45
|
-
aspect-ratio: 1;
|
|
46
|
-
padding: 0;
|
|
47
|
-
border: 0;
|
|
48
|
-
border-radius: 50%;
|
|
49
|
-
background: transparent;
|
|
50
|
-
color: var(--oc-muted-foreground);
|
|
51
|
-
cursor: pointer;
|
|
52
|
-
}
|
|
53
|
-
.oc-media-row__menu:hover { background: var(--oc-surface-strong); color: var(--oc-foreground); }
|
|
54
|
-
.oc-media-row__menu:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
55
|
-
|
|
56
|
-
/* Numbered playlist: an extra first column with a CSS counter (no number in the markup). */
|
|
57
|
-
.oc-media-row-list--numbered > .oc-media-row { counter-increment: oc-media-row; grid-template-columns: 1.5rem 8rem minmax(0, 1fr) auto; align-items: center; }
|
|
58
|
-
.oc-media-row-list--numbered > .oc-media-row::before {
|
|
59
|
-
content: counter(oc-media-row);
|
|
60
|
-
font-size: 0.8125rem;
|
|
61
|
-
font-variant-numeric: tabular-nums;
|
|
62
|
-
text-align: center;
|
|
63
|
-
color: var(--oc-muted-foreground);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Current item (aria-current="true"): tinted row and a play mark instead of the number. */
|
|
67
|
-
.oc-media-row[aria-current="true"] { background: color-mix(in oklch, var(--oc-primary) 12%, transparent); }
|
|
68
|
-
.oc-media-row-list--numbered > .oc-media-row[aria-current="true"]::before { content: "\25B6" / "Now playing"; color: var(--oc-primary); }
|
|
69
|
-
|
|
70
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
71
|
-
.oc-media-row:hover .oc-media-thumb > :is(img, video, .oc-media-art) { transform: scale(1.04); }
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* Narrow containers: smaller thumb. */
|
|
75
|
-
@media (max-width: 30rem) {
|
|
76
|
-
.oc-media-row { grid-template-columns: 7.5rem minmax(0, 1fr) auto; }
|
|
77
|
-
.oc-media-row-list--numbered > .oc-media-row { grid-template-columns: 1.25rem 6.5rem minmax(0, 1fr) auto; }
|
|
78
|
-
}
|
|
1
|
+
/* File: packages/ui/src/parts/media-row.css | Map: list -> row grid (thumb | text | menu) -> title (stretched link) + meta
|
|
2
|
+
-> menu button -> numbered playlist (CSS counter) -> current item -> hover -> small screens
|
|
3
|
+
Media row: a compact horizontal item for "up next" lists and playlists. The thumb is a .oc-media-thumb. */
|
|
4
|
+
|
|
5
|
+
.oc-media-row-list { display: grid; gap: 0.25rem; margin: 0; padding: 0; list-style: none; inline-size: 100%; counter-reset: oc-media-row; }
|
|
6
|
+
|
|
7
|
+
.oc-media-row {
|
|
8
|
+
position: relative;
|
|
9
|
+
display: grid;
|
|
10
|
+
grid-template-columns: 10rem minmax(0, 1fr) auto;
|
|
11
|
+
gap: 0.75rem;
|
|
12
|
+
align-items: start;
|
|
13
|
+
padding: 0.375rem;
|
|
14
|
+
border-radius: var(--oc-radius);
|
|
15
|
+
color: var(--oc-foreground);
|
|
16
|
+
}
|
|
17
|
+
.oc-media-row:hover { background: var(--oc-surface); }
|
|
18
|
+
.oc-media-row > .oc-media-thumb { border-radius: calc(var(--oc-radius) - 2px); }
|
|
19
|
+
|
|
20
|
+
.oc-media-row__text { display: grid; gap: 0.2rem; min-inline-size: 0; }
|
|
21
|
+
.oc-media-row__title {
|
|
22
|
+
margin: 0;
|
|
23
|
+
font-size: 0.875rem;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
line-height: 1.35;
|
|
26
|
+
display: -webkit-box;
|
|
27
|
+
-webkit-box-orient: vertical;
|
|
28
|
+
-webkit-line-clamp: 2;
|
|
29
|
+
line-clamp: 2;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
}
|
|
32
|
+
.oc-media-row__title > a { color: inherit; text-decoration: none; }
|
|
33
|
+
.oc-media-row__title > a::after { content: ""; position: absolute; inset: 0; border-radius: var(--oc-radius); }
|
|
34
|
+
.oc-media-row__title > a:focus-visible { outline: none; }
|
|
35
|
+
.oc-media-row__title > a:focus-visible::after { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
36
|
+
.oc-media-row__meta { margin: 0; font-size: 0.75rem; color: var(--oc-muted-foreground); }
|
|
37
|
+
|
|
38
|
+
/* ⋮ button above the stretched link. */
|
|
39
|
+
.oc-media-row__menu {
|
|
40
|
+
position: relative;
|
|
41
|
+
z-index: 1;
|
|
42
|
+
display: grid;
|
|
43
|
+
place-items: center;
|
|
44
|
+
inline-size: 1.75rem;
|
|
45
|
+
aspect-ratio: 1;
|
|
46
|
+
padding: 0;
|
|
47
|
+
border: 0;
|
|
48
|
+
border-radius: 50%;
|
|
49
|
+
background: transparent;
|
|
50
|
+
color: var(--oc-muted-foreground);
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
}
|
|
53
|
+
.oc-media-row__menu:hover { background: var(--oc-surface-strong); color: var(--oc-foreground); }
|
|
54
|
+
.oc-media-row__menu:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
55
|
+
|
|
56
|
+
/* Numbered playlist: an extra first column with a CSS counter (no number in the markup). */
|
|
57
|
+
.oc-media-row-list--numbered > .oc-media-row { counter-increment: oc-media-row; grid-template-columns: 1.5rem 8rem minmax(0, 1fr) auto; align-items: center; }
|
|
58
|
+
.oc-media-row-list--numbered > .oc-media-row::before {
|
|
59
|
+
content: counter(oc-media-row);
|
|
60
|
+
font-size: 0.8125rem;
|
|
61
|
+
font-variant-numeric: tabular-nums;
|
|
62
|
+
text-align: center;
|
|
63
|
+
color: var(--oc-muted-foreground);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Current item (aria-current="true"): tinted row and a play mark instead of the number. */
|
|
67
|
+
.oc-media-row[aria-current="true"] { background: color-mix(in oklch, var(--oc-primary) 12%, transparent); }
|
|
68
|
+
.oc-media-row-list--numbered > .oc-media-row[aria-current="true"]::before { content: "\25B6" / "Now playing"; color: var(--oc-primary); }
|
|
69
|
+
|
|
70
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
71
|
+
.oc-media-row:hover .oc-media-thumb > :is(img, video, .oc-media-art) { transform: scale(1.04); }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Narrow containers: smaller thumb. */
|
|
75
|
+
@media (max-width: 30rem) {
|
|
76
|
+
.oc-media-row { grid-template-columns: 7.5rem minmax(0, 1fr) auto; }
|
|
77
|
+
.oc-media-row-list--numbered > .oc-media-row { grid-template-columns: 1.25rem 6.5rem minmax(0, 1fr) auto; }
|
|
78
|
+
}
|
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-stack-card.css | Map: card -> deck (two layers behind via ::before / ::after)
|
|
2
|
-
-> count badge -> panel modifier -> body (title link + meta) -> hover spread -> motion
|
|
3
|
-
Stack card: a playlist / course cover that looks like a small pile of cards, with a "12 videos" badge. */
|
|
4
|
-
|
|
5
|
-
.oc-stack-card {
|
|
6
|
-
position: relative;
|
|
7
|
-
display: grid;
|
|
8
|
-
gap: 0.75rem;
|
|
9
|
-
align-content: start;
|
|
10
|
-
inline-size: 100%;
|
|
11
|
-
padding-block-start: 0.6rem; /* room for the layers peeking out above */
|
|
12
|
-
color: var(--oc-foreground);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/* The deck: the cover plus two layers drawn behind it. */
|
|
16
|
-
.oc-stack-card__deck { position: relative; isolation: isolate; }
|
|
17
|
-
.oc-stack-card__deck::before,
|
|
18
|
-
.oc-stack-card__deck::after {
|
|
19
|
-
content: "";
|
|
20
|
-
position: absolute;
|
|
21
|
-
inset-inline: 0.75rem;
|
|
22
|
-
inset-block: -0.3rem auto;
|
|
23
|
-
block-size: 100%;
|
|
24
|
-
z-index: -1;
|
|
25
|
-
border-radius: var(--oc-radius);
|
|
26
|
-
background: color-mix(in oklch, var(--oc-muted-foreground) 35%, var(--oc-card));
|
|
27
|
-
transition: translate var(--oc-transition-normal), rotate var(--oc-transition-normal);
|
|
28
|
-
}
|
|
29
|
-
.oc-stack-card__deck::after {
|
|
30
|
-
inset-inline: 1.5rem;
|
|
31
|
-
inset-block-start: -0.6rem;
|
|
32
|
-
z-index: -2;
|
|
33
|
-
background: color-mix(in oklch, var(--oc-muted-foreground) 18%, var(--oc-card));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* Count badge: bottom right on the cover ("12 videos"). */
|
|
37
|
-
.oc-stack-card__count {
|
|
38
|
-
position: absolute;
|
|
39
|
-
inset-block-end: 0.45rem;
|
|
40
|
-
inset-inline-end: 0.45rem;
|
|
41
|
-
display: inline-flex;
|
|
42
|
-
align-items: center;
|
|
43
|
-
gap: 0.3rem;
|
|
44
|
-
padding: 0.15rem 0.45rem;
|
|
45
|
-
border-radius: 0.3rem;
|
|
46
|
-
background: oklch(from var(--color-black-60) l c h / 0.78);
|
|
47
|
-
color: var(--color-white-50);
|
|
48
|
-
font-size: 0.75rem;
|
|
49
|
-
font-weight: 600;
|
|
50
|
-
font-variant-numeric: tabular-nums;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/* Panel: the count becomes a dark side panel over the right third of the cover. */
|
|
54
|
-
.oc-stack-card--panel .oc-stack-card__count {
|
|
55
|
-
inset-block: 0;
|
|
56
|
-
inset-inline-end: 0;
|
|
57
|
-
inline-size: 38%;
|
|
58
|
-
flex-direction: column;
|
|
59
|
-
justify-content: center;
|
|
60
|
-
border-radius: 0 var(--oc-radius) var(--oc-radius) 0;
|
|
61
|
-
background: oklch(from var(--color-black-60) l c h / 0.72);
|
|
62
|
-
backdrop-filter: blur(6px);
|
|
63
|
-
font-size: 0.875rem;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Body: title (link covers the card) + meta. */
|
|
67
|
-
.oc-stack-card__title { margin: 0; font-size: 0.95rem; font-weight: 600; line-height: 1.35; }
|
|
68
|
-
.oc-stack-card__title > a { color: inherit; text-decoration: none; }
|
|
69
|
-
.oc-stack-card__title > a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: var(--oc-radius); }
|
|
70
|
-
.oc-stack-card__title > a:focus-visible { outline: none; }
|
|
71
|
-
.oc-stack-card__title > a:focus-visible::after { outline: 2px solid var(--oc-ring); outline-offset: 4px; }
|
|
72
|
-
.oc-stack-card__meta { margin: 0.2rem 0 0; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
73
|
-
|
|
74
|
-
/* Hover: the layers fan out a little. */
|
|
75
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
76
|
-
.oc-stack-card:hover .oc-stack-card__deck::before { translate: 0 -0.2rem; rotate: -1.5deg; }
|
|
77
|
-
.oc-stack-card:hover .oc-stack-card__deck::after { translate: 0 -0.35rem; rotate: 2deg; }
|
|
78
|
-
}
|
|
79
|
-
@media (prefers-reduced-motion: reduce) {
|
|
80
|
-
.oc-stack-card__deck::before,
|
|
81
|
-
.oc-stack-card__deck::after { transition: none; }
|
|
82
|
-
}
|
|
1
|
+
/* File: packages/ui/src/parts/media-stack-card.css | Map: card -> deck (two layers behind via ::before / ::after)
|
|
2
|
+
-> count badge -> panel modifier -> body (title link + meta) -> hover spread -> motion
|
|
3
|
+
Stack card: a playlist / course cover that looks like a small pile of cards, with a "12 videos" badge. */
|
|
4
|
+
|
|
5
|
+
.oc-stack-card {
|
|
6
|
+
position: relative;
|
|
7
|
+
display: grid;
|
|
8
|
+
gap: 0.75rem;
|
|
9
|
+
align-content: start;
|
|
10
|
+
inline-size: 100%;
|
|
11
|
+
padding-block-start: 0.6rem; /* room for the layers peeking out above */
|
|
12
|
+
color: var(--oc-foreground);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* The deck: the cover plus two layers drawn behind it. */
|
|
16
|
+
.oc-stack-card__deck { position: relative; isolation: isolate; }
|
|
17
|
+
.oc-stack-card__deck::before,
|
|
18
|
+
.oc-stack-card__deck::after {
|
|
19
|
+
content: "";
|
|
20
|
+
position: absolute;
|
|
21
|
+
inset-inline: 0.75rem;
|
|
22
|
+
inset-block: -0.3rem auto;
|
|
23
|
+
block-size: 100%;
|
|
24
|
+
z-index: -1;
|
|
25
|
+
border-radius: var(--oc-radius);
|
|
26
|
+
background: color-mix(in oklch, var(--oc-muted-foreground) 35%, var(--oc-card));
|
|
27
|
+
transition: translate var(--oc-transition-normal), rotate var(--oc-transition-normal);
|
|
28
|
+
}
|
|
29
|
+
.oc-stack-card__deck::after {
|
|
30
|
+
inset-inline: 1.5rem;
|
|
31
|
+
inset-block-start: -0.6rem;
|
|
32
|
+
z-index: -2;
|
|
33
|
+
background: color-mix(in oklch, var(--oc-muted-foreground) 18%, var(--oc-card));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Count badge: bottom right on the cover ("12 videos"). */
|
|
37
|
+
.oc-stack-card__count {
|
|
38
|
+
position: absolute;
|
|
39
|
+
inset-block-end: 0.45rem;
|
|
40
|
+
inset-inline-end: 0.45rem;
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 0.3rem;
|
|
44
|
+
padding: 0.15rem 0.45rem;
|
|
45
|
+
border-radius: 0.3rem;
|
|
46
|
+
background: oklch(from var(--color-black-60) l c h / 0.78);
|
|
47
|
+
color: var(--color-white-50);
|
|
48
|
+
font-size: 0.75rem;
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
font-variant-numeric: tabular-nums;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Panel: the count becomes a dark side panel over the right third of the cover. */
|
|
54
|
+
.oc-stack-card--panel .oc-stack-card__count {
|
|
55
|
+
inset-block: 0;
|
|
56
|
+
inset-inline-end: 0;
|
|
57
|
+
inline-size: 38%;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
border-radius: 0 var(--oc-radius) var(--oc-radius) 0;
|
|
61
|
+
background: oklch(from var(--color-black-60) l c h / 0.72);
|
|
62
|
+
backdrop-filter: blur(6px);
|
|
63
|
+
font-size: 0.875rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Body: title (link covers the card) + meta. */
|
|
67
|
+
.oc-stack-card__title { margin: 0; font-size: 0.95rem; font-weight: 600; line-height: 1.35; }
|
|
68
|
+
.oc-stack-card__title > a { color: inherit; text-decoration: none; }
|
|
69
|
+
.oc-stack-card__title > a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: var(--oc-radius); }
|
|
70
|
+
.oc-stack-card__title > a:focus-visible { outline: none; }
|
|
71
|
+
.oc-stack-card__title > a:focus-visible::after { outline: 2px solid var(--oc-ring); outline-offset: 4px; }
|
|
72
|
+
.oc-stack-card__meta { margin: 0.2rem 0 0; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
73
|
+
|
|
74
|
+
/* Hover: the layers fan out a little. */
|
|
75
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
76
|
+
.oc-stack-card:hover .oc-stack-card__deck::before { translate: 0 -0.2rem; rotate: -1.5deg; }
|
|
77
|
+
.oc-stack-card:hover .oc-stack-card__deck::after { translate: 0 -0.35rem; rotate: 2deg; }
|
|
78
|
+
}
|
|
79
|
+
@media (prefers-reduced-motion: reduce) {
|
|
80
|
+
.oc-stack-card__deck::before,
|
|
81
|
+
.oc-stack-card__deck::after { transition: none; }
|
|
82
|
+
}
|
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-terminal-log.css | Map: frame (always dark) -> title bar (traffic lights, title, live dot)
|
|
2
|
-
-> body (scrolling log) -> line grid (time | level | message) -> level colors -> prompt + blinking cursor -> motion
|
|
3
|
-
Terminal log: a console window for build / scan output. color-scheme: dark makes every light-dark() token
|
|
4
|
-
inside resolve to its dark value, so the terminal stays dark in the light theme too. */
|
|
5
|
-
|
|
6
|
-
.oc-terminal-log {
|
|
7
|
-
color-scheme: dark;
|
|
8
|
-
inline-size: 100%;
|
|
9
|
-
overflow: hidden;
|
|
10
|
-
border: 1px solid var(--oc-border);
|
|
11
|
-
border-radius: calc(var(--oc-radius) + 4px);
|
|
12
|
-
background: var(--color-shallowblue-95);
|
|
13
|
-
color: var(--oc-foreground);
|
|
14
|
-
box-shadow: 0 24px 48px -24px oklch(from var(--color-black-60) l c h / 0.6);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/* ---- Title bar ---- */
|
|
18
|
-
.oc-terminal-log__bar { display: flex; align-items: center; gap: 0.45rem; padding: 0.65rem 0.9rem; border-block-end: 1px solid var(--oc-border); background: var(--color-shallowblue-90); }
|
|
19
|
-
.oc-terminal-log__bar > i { inline-size: 0.7rem; aspect-ratio: 1; border-radius: 50%; background: var(--color-red-50); }
|
|
20
|
-
.oc-terminal-log__bar > i:nth-of-type(2) { background: var(--color-orange-60); }
|
|
21
|
-
.oc-terminal-log__bar > i:nth-of-type(3) { background: var(--color-green-20); }
|
|
22
|
-
.oc-terminal-log__title { margin-inline: 0.5rem auto; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
23
|
-
.oc-terminal-log__status { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.75rem; color: var(--oc-muted-foreground); }
|
|
24
|
-
.oc-terminal-log__status::before { content: ""; inline-size: 0.5rem; aspect-ratio: 1; border-radius: 50%; background: var(--color-green-20); }
|
|
25
|
-
|
|
26
|
-
/* ---- Body: monospace, scrolls when it gets long ---- */
|
|
27
|
-
.oc-terminal-log__body {
|
|
28
|
-
display: grid;
|
|
29
|
-
gap: 0.15rem;
|
|
30
|
-
max-block-size: var(--oc-terminal-log-height, 18rem);
|
|
31
|
-
margin: 0;
|
|
32
|
-
padding: 0.9rem 1rem;
|
|
33
|
-
overflow: auto;
|
|
34
|
-
font-family: ui-monospace, "Cascadia Code", "Fira Code", Menlo, Consolas, monospace;
|
|
35
|
-
font-size: 0.8125rem;
|
|
36
|
-
line-height: 1.6;
|
|
37
|
-
scrollbar-width: thin;
|
|
38
|
-
}
|
|
39
|
-
.oc-terminal-log__body:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
40
|
-
|
|
41
|
-
/* One line: time | level | message. Long messages wrap under the message column. */
|
|
42
|
-
.oc-terminal-log__line { display: grid; grid-template-columns: auto 3.5rem minmax(0, 1fr); gap: 0.75rem; margin: 0; }
|
|
43
|
-
.oc-terminal-log__line:not(:has(.oc-terminal-log__time)) { grid-template-columns: 3.5rem minmax(0, 1fr); }
|
|
44
|
-
.oc-terminal-log__time { color: var(--color-stormblue-40); font-variant-numeric: tabular-nums; }
|
|
45
|
-
.oc-terminal-log__level { font-weight: 700; text-transform: uppercase; }
|
|
46
|
-
.oc-terminal-log__msg { overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
47
|
-
|
|
48
|
-
/* Level colors (palette tokens, readable on the dark background). */
|
|
49
|
-
.oc-terminal-log__line--info .oc-terminal-log__level { color: var(--color-skycyan-50); }
|
|
50
|
-
.oc-terminal-log__line--success .oc-terminal-log__level { color: var(--color-green-20); }
|
|
51
|
-
.oc-terminal-log__line--warn .oc-terminal-log__level { color: var(--color-orange-50); }
|
|
52
|
-
.oc-terminal-log__line--error .oc-terminal-log__level,
|
|
53
|
-
.oc-terminal-log__line--error .oc-terminal-log__msg { color: var(--color-red-40); }
|
|
54
|
-
.oc-terminal-log__line--debug { opacity: 0.6; }
|
|
55
|
-
.oc-terminal-log__line--debug .oc-terminal-log__level { color: var(--color-purple-30); }
|
|
56
|
-
|
|
57
|
-
/* Prompt line: "$ " + text + a block cursor. */
|
|
58
|
-
.oc-terminal-log__prompt { margin: 0.25rem 0 0; color: var(--oc-foreground); }
|
|
59
|
-
.oc-terminal-log__prompt::before { content: "$ "; color: var(--color-green-20); }
|
|
60
|
-
.oc-terminal-log__prompt::after {
|
|
61
|
-
content: "";
|
|
62
|
-
display: inline-block;
|
|
63
|
-
inline-size: 0.55em;
|
|
64
|
-
block-size: 1.1em;
|
|
65
|
-
margin-inline-start: 0.15em;
|
|
66
|
-
vertical-align: text-bottom;
|
|
67
|
-
background: currentColor;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/* Blinking cursor and pulsing live dot only when motion is welcome; otherwise they stay still. */
|
|
71
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
72
|
-
.oc-terminal-log__prompt::after { animation: oc-terminal-log-blink 1.1s steps(1) infinite; }
|
|
73
|
-
.oc-terminal-log__status::before { animation: oc-terminal-log-pulse 1.6s ease-in-out infinite; }
|
|
74
|
-
}
|
|
75
|
-
@keyframes oc-terminal-log-blink { 50% { opacity: 0; } }
|
|
76
|
-
@keyframes oc-terminal-log-pulse { 50% { opacity: 0.35; } }
|
|
1
|
+
/* File: packages/ui/src/parts/media-terminal-log.css | Map: frame (always dark) -> title bar (traffic lights, title, live dot)
|
|
2
|
+
-> body (scrolling log) -> line grid (time | level | message) -> level colors -> prompt + blinking cursor -> motion
|
|
3
|
+
Terminal log: a console window for build / scan output. color-scheme: dark makes every light-dark() token
|
|
4
|
+
inside resolve to its dark value, so the terminal stays dark in the light theme too. */
|
|
5
|
+
|
|
6
|
+
.oc-terminal-log {
|
|
7
|
+
color-scheme: dark;
|
|
8
|
+
inline-size: 100%;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
border: 1px solid var(--oc-border);
|
|
11
|
+
border-radius: calc(var(--oc-radius) + 4px);
|
|
12
|
+
background: var(--color-shallowblue-95);
|
|
13
|
+
color: var(--oc-foreground);
|
|
14
|
+
box-shadow: 0 24px 48px -24px oklch(from var(--color-black-60) l c h / 0.6);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* ---- Title bar ---- */
|
|
18
|
+
.oc-terminal-log__bar { display: flex; align-items: center; gap: 0.45rem; padding: 0.65rem 0.9rem; border-block-end: 1px solid var(--oc-border); background: var(--color-shallowblue-90); }
|
|
19
|
+
.oc-terminal-log__bar > i { inline-size: 0.7rem; aspect-ratio: 1; border-radius: 50%; background: var(--color-red-50); }
|
|
20
|
+
.oc-terminal-log__bar > i:nth-of-type(2) { background: var(--color-orange-60); }
|
|
21
|
+
.oc-terminal-log__bar > i:nth-of-type(3) { background: var(--color-green-20); }
|
|
22
|
+
.oc-terminal-log__title { margin-inline: 0.5rem auto; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
23
|
+
.oc-terminal-log__status { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.75rem; color: var(--oc-muted-foreground); }
|
|
24
|
+
.oc-terminal-log__status::before { content: ""; inline-size: 0.5rem; aspect-ratio: 1; border-radius: 50%; background: var(--color-green-20); }
|
|
25
|
+
|
|
26
|
+
/* ---- Body: monospace, scrolls when it gets long ---- */
|
|
27
|
+
.oc-terminal-log__body {
|
|
28
|
+
display: grid;
|
|
29
|
+
gap: 0.15rem;
|
|
30
|
+
max-block-size: var(--oc-terminal-log-height, 18rem);
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0.9rem 1rem;
|
|
33
|
+
overflow: auto;
|
|
34
|
+
font-family: ui-monospace, "Cascadia Code", "Fira Code", Menlo, Consolas, monospace;
|
|
35
|
+
font-size: 0.8125rem;
|
|
36
|
+
line-height: 1.6;
|
|
37
|
+
scrollbar-width: thin;
|
|
38
|
+
}
|
|
39
|
+
.oc-terminal-log__body:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
40
|
+
|
|
41
|
+
/* One line: time | level | message. Long messages wrap under the message column. */
|
|
42
|
+
.oc-terminal-log__line { display: grid; grid-template-columns: auto 3.5rem minmax(0, 1fr); gap: 0.75rem; margin: 0; }
|
|
43
|
+
.oc-terminal-log__line:not(:has(.oc-terminal-log__time)) { grid-template-columns: 3.5rem minmax(0, 1fr); }
|
|
44
|
+
.oc-terminal-log__time { color: var(--color-stormblue-40); font-variant-numeric: tabular-nums; }
|
|
45
|
+
.oc-terminal-log__level { font-weight: 700; text-transform: uppercase; }
|
|
46
|
+
.oc-terminal-log__msg { overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
47
|
+
|
|
48
|
+
/* Level colors (palette tokens, readable on the dark background). */
|
|
49
|
+
.oc-terminal-log__line--info .oc-terminal-log__level { color: var(--color-skycyan-50); }
|
|
50
|
+
.oc-terminal-log__line--success .oc-terminal-log__level { color: var(--color-green-20); }
|
|
51
|
+
.oc-terminal-log__line--warn .oc-terminal-log__level { color: var(--color-orange-50); }
|
|
52
|
+
.oc-terminal-log__line--error .oc-terminal-log__level,
|
|
53
|
+
.oc-terminal-log__line--error .oc-terminal-log__msg { color: var(--color-red-40); }
|
|
54
|
+
.oc-terminal-log__line--debug { opacity: 0.6; }
|
|
55
|
+
.oc-terminal-log__line--debug .oc-terminal-log__level { color: var(--color-purple-30); }
|
|
56
|
+
|
|
57
|
+
/* Prompt line: "$ " + text + a block cursor. */
|
|
58
|
+
.oc-terminal-log__prompt { margin: 0.25rem 0 0; color: var(--oc-foreground); }
|
|
59
|
+
.oc-terminal-log__prompt::before { content: "$ "; color: var(--color-green-20); }
|
|
60
|
+
.oc-terminal-log__prompt::after {
|
|
61
|
+
content: "";
|
|
62
|
+
display: inline-block;
|
|
63
|
+
inline-size: 0.55em;
|
|
64
|
+
block-size: 1.1em;
|
|
65
|
+
margin-inline-start: 0.15em;
|
|
66
|
+
vertical-align: text-bottom;
|
|
67
|
+
background: currentColor;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Blinking cursor and pulsing live dot only when motion is welcome; otherwise they stay still. */
|
|
71
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
72
|
+
.oc-terminal-log__prompt::after { animation: oc-terminal-log-blink 1.1s steps(1) infinite; }
|
|
73
|
+
.oc-terminal-log__status::before { animation: oc-terminal-log-pulse 1.6s ease-in-out infinite; }
|
|
74
|
+
}
|
|
75
|
+
@keyframes oc-terminal-log-blink { 50% { opacity: 0; } }
|
|
76
|
+
@keyframes oc-terminal-log-pulse { 50% { opacity: 0.35; } }
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-thumb.css | Map: thumb box (16:9) -> media fill + hover -> badge (top)
|
|
2
|
-
-> duration (bottom right) -> watch progress (native <progress>) -> ratio modifiers -> watched state -> motion
|
|
3
|
-
Media thumb: a video preview tile. Works as <a> or <div>; put an <img> (or .oc-media-art) inside. */
|
|
4
|
-
|
|
5
|
-
.oc-media-thumb {
|
|
6
|
-
position: relative;
|
|
7
|
-
display: block;
|
|
8
|
-
aspect-ratio: 16 / 9;
|
|
9
|
-
overflow: hidden;
|
|
10
|
-
border-radius: var(--oc-radius);
|
|
11
|
-
background: var(--oc-muted);
|
|
12
|
-
color: var(--color-white-50);
|
|
13
|
-
isolation: isolate;
|
|
14
|
-
}
|
|
15
|
-
.oc-media-thumb:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
16
|
-
|
|
17
|
-
/* The picture fills the box. */
|
|
18
|
-
.oc-media-thumb > :is(img, video, .oc-media-art) {
|
|
19
|
-
position: absolute;
|
|
20
|
-
inset: 0;
|
|
21
|
-
inline-size: 100%;
|
|
22
|
-
block-size: 100%;
|
|
23
|
-
object-fit: cover;
|
|
24
|
-
z-index: -1;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/* Small dark labels on top of the picture. */
|
|
28
|
-
.oc-media-thumb__badge,
|
|
29
|
-
.oc-media-thumb__duration {
|
|
30
|
-
position: absolute;
|
|
31
|
-
padding: 0.1rem 0.4rem;
|
|
32
|
-
border-radius: 0.3rem;
|
|
33
|
-
background: oklch(from var(--color-black-60) l c h / 0.78);
|
|
34
|
-
font-size: 0.75rem;
|
|
35
|
-
font-weight: 600;
|
|
36
|
-
line-height: 1.4;
|
|
37
|
-
font-variant-numeric: tabular-nums;
|
|
38
|
-
}
|
|
39
|
-
.oc-media-thumb__badge { inset-block-start: 0.4rem; inset-inline-start: 0.4rem; }
|
|
40
|
-
.oc-media-thumb__badge--live { background: var(--color-red-60); }
|
|
41
|
-
.oc-media-thumb__duration { inset-block-end: 0.45rem; inset-inline-end: 0.45rem; }
|
|
42
|
-
/* With a progress bar the duration moves up a little. */
|
|
43
|
-
.oc-media-thumb:has(.oc-media-thumb__progress) .oc-media-thumb__duration { inset-block-end: 0.7rem; }
|
|
44
|
-
|
|
45
|
-
/* Watch progress: a native <progress value max>, drawn as a thin bar on the bottom edge. */
|
|
46
|
-
.oc-media-thumb__progress {
|
|
47
|
-
position: absolute;
|
|
48
|
-
inset: auto 0 0;
|
|
49
|
-
inline-size: 100%;
|
|
50
|
-
block-size: 0.25rem;
|
|
51
|
-
border: 0;
|
|
52
|
-
appearance: none;
|
|
53
|
-
background: oklch(from var(--color-white-50) l c h / 0.35);
|
|
54
|
-
color: var(--color-red-60);
|
|
55
|
-
}
|
|
56
|
-
.oc-media-thumb__progress::-webkit-progress-bar { background: transparent; }
|
|
57
|
-
.oc-media-thumb__progress::-webkit-progress-value { background: var(--color-red-60); }
|
|
58
|
-
.oc-media-thumb__progress::-moz-progress-bar { background: var(--color-red-60); }
|
|
59
|
-
|
|
60
|
-
/* Ratios. */
|
|
61
|
-
.oc-media-thumb--square { aspect-ratio: 1 / 1; }
|
|
62
|
-
.oc-media-thumb--portrait { aspect-ratio: 9 / 16; }
|
|
63
|
-
|
|
64
|
-
/* Already watched: the picture fades a bit. */
|
|
65
|
-
.oc-media-thumb.is-watched > :is(img, video, .oc-media-art) { opacity: 0.6; }
|
|
66
|
-
|
|
67
|
-
/* Gentle zoom on hover, only when motion is welcome. */
|
|
68
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
69
|
-
.oc-media-thumb > :is(img, video, .oc-media-art) { transition: transform var(--oc-transition-normal); }
|
|
70
|
-
.oc-media-thumb:hover > :is(img, video, .oc-media-art) { transform: scale(1.04); }
|
|
71
|
-
}
|
|
1
|
+
/* File: packages/ui/src/parts/media-thumb.css | Map: thumb box (16:9) -> media fill + hover -> badge (top)
|
|
2
|
+
-> duration (bottom right) -> watch progress (native <progress>) -> ratio modifiers -> watched state -> motion
|
|
3
|
+
Media thumb: a video preview tile. Works as <a> or <div>; put an <img> (or .oc-media-art) inside. */
|
|
4
|
+
|
|
5
|
+
.oc-media-thumb {
|
|
6
|
+
position: relative;
|
|
7
|
+
display: block;
|
|
8
|
+
aspect-ratio: 16 / 9;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
border-radius: var(--oc-radius);
|
|
11
|
+
background: var(--oc-muted);
|
|
12
|
+
color: var(--color-white-50);
|
|
13
|
+
isolation: isolate;
|
|
14
|
+
}
|
|
15
|
+
.oc-media-thumb:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
16
|
+
|
|
17
|
+
/* The picture fills the box. */
|
|
18
|
+
.oc-media-thumb > :is(img, video, .oc-media-art) {
|
|
19
|
+
position: absolute;
|
|
20
|
+
inset: 0;
|
|
21
|
+
inline-size: 100%;
|
|
22
|
+
block-size: 100%;
|
|
23
|
+
object-fit: cover;
|
|
24
|
+
z-index: -1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Small dark labels on top of the picture. */
|
|
28
|
+
.oc-media-thumb__badge,
|
|
29
|
+
.oc-media-thumb__duration {
|
|
30
|
+
position: absolute;
|
|
31
|
+
padding: 0.1rem 0.4rem;
|
|
32
|
+
border-radius: 0.3rem;
|
|
33
|
+
background: oklch(from var(--color-black-60) l c h / 0.78);
|
|
34
|
+
font-size: 0.75rem;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
line-height: 1.4;
|
|
37
|
+
font-variant-numeric: tabular-nums;
|
|
38
|
+
}
|
|
39
|
+
.oc-media-thumb__badge { inset-block-start: 0.4rem; inset-inline-start: 0.4rem; }
|
|
40
|
+
.oc-media-thumb__badge--live { background: var(--color-red-60); }
|
|
41
|
+
.oc-media-thumb__duration { inset-block-end: 0.45rem; inset-inline-end: 0.45rem; }
|
|
42
|
+
/* With a progress bar the duration moves up a little. */
|
|
43
|
+
.oc-media-thumb:has(.oc-media-thumb__progress) .oc-media-thumb__duration { inset-block-end: 0.7rem; }
|
|
44
|
+
|
|
45
|
+
/* Watch progress: a native <progress value max>, drawn as a thin bar on the bottom edge. */
|
|
46
|
+
.oc-media-thumb__progress {
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset: auto 0 0;
|
|
49
|
+
inline-size: 100%;
|
|
50
|
+
block-size: 0.25rem;
|
|
51
|
+
border: 0;
|
|
52
|
+
appearance: none;
|
|
53
|
+
background: oklch(from var(--color-white-50) l c h / 0.35);
|
|
54
|
+
color: var(--color-red-60);
|
|
55
|
+
}
|
|
56
|
+
.oc-media-thumb__progress::-webkit-progress-bar { background: transparent; }
|
|
57
|
+
.oc-media-thumb__progress::-webkit-progress-value { background: var(--color-red-60); }
|
|
58
|
+
.oc-media-thumb__progress::-moz-progress-bar { background: var(--color-red-60); }
|
|
59
|
+
|
|
60
|
+
/* Ratios. */
|
|
61
|
+
.oc-media-thumb--square { aspect-ratio: 1 / 1; }
|
|
62
|
+
.oc-media-thumb--portrait { aspect-ratio: 9 / 16; }
|
|
63
|
+
|
|
64
|
+
/* Already watched: the picture fades a bit. */
|
|
65
|
+
.oc-media-thumb.is-watched > :is(img, video, .oc-media-art) { opacity: 0.6; }
|
|
66
|
+
|
|
67
|
+
/* Gentle zoom on hover, only when motion is welcome. */
|
|
68
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
69
|
+
.oc-media-thumb > :is(img, video, .oc-media-art) { transition: transform var(--oc-transition-normal); }
|
|
70
|
+
.oc-media-thumb:hover > :is(img, video, .oc-media-art) { transform: scale(1.04); }
|
|
71
|
+
}
|