@birdycom/omniaui 0.0.0-stage → 0.11.1
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 +21 -3
- package/bin/lib/add.mjs +126 -0
- package/bin/lib/catalog.mjs +169 -0
- package/bin/lib/project.mjs +90 -0
- package/bin/omniaui.mjs +70 -0
- package/dist/code-block.css +163 -0
- package/dist/components-extra.css +916 -0
- package/dist/components.css +10171 -0
- package/dist/components.min.css +1 -0
- package/dist/data-table.d.ts +9 -0
- package/dist/data-table.js +505 -0
- package/dist/docs-ui.css +267 -0
- package/dist/oc-theme.css +69 -0
- package/dist/parts/.gitkeep +0 -0
- package/dist/parts/app-accordion-accent.css +60 -0
- package/dist/parts/app-alpha-tabs.css +68 -0
- package/dist/parts/app-busy-overlay.css +25 -0
- package/dist/parts/app-column-menu.css +85 -0
- package/dist/parts/app-confirm-dialog.css +70 -0
- package/dist/parts/app-cookie-consent.css +63 -0
- package/dist/parts/app-data-table.css +174 -0
- package/dist/parts/app-greeting.css +47 -0
- package/dist/parts/app-list-toolbar.css +81 -0
- package/dist/parts/app-page-header.css +54 -0
- package/dist/parts/app-severity-card.css +91 -0
- package/dist/parts/app-sidebar-dark.css +15 -0
- package/dist/parts/app-sortable-row.css +52 -0
- package/dist/parts/app-stat-card.css +68 -0
- package/dist/parts/app-table-actions.css +71 -0
- package/dist/parts/app-table-compact.css +54 -0
- package/dist/parts/app-top-progress.css +68 -0
- package/dist/parts/app-tree.css +104 -0
- package/dist/parts/app-upgrade-banner.css +90 -0
- package/dist/parts/app-version-banner.css +80 -0
- package/dist/parts/data-chart-line.css +167 -0
- package/dist/parts/forms-affix-input.css +75 -0
- package/dist/parts/forms-barcode-input.css +75 -0
- package/dist/parts/forms-chip-filter.css +91 -0
- package/dist/parts/forms-color-select.css +97 -0
- package/dist/parts/forms-decimal-input.css +51 -0
- package/dist/parts/forms-filter-counts.css +94 -0
- package/dist/parts/forms-language-select.css +89 -0
- package/dist/parts/forms-number-input.css +98 -0
- package/dist/parts/forms-password-requirements.css +55 -0
- package/dist/parts/forms-phone-input.css +85 -0
- package/dist/parts/forms-time-input.css +74 -0
- package/dist/parts/forms-toggle-field.css +69 -0
- package/dist/parts/media-art.css +21 -0
- package/dist/parts/media-attachment.css +160 -0
- package/dist/parts/media-browser-frame.css +73 -0
- package/dist/parts/media-card.css +83 -0
- package/dist/parts/media-chat-composer.css +90 -0
- package/dist/parts/media-doc-viewer.css +151 -0
- package/dist/parts/media-emoji-picker.css +88 -0
- package/dist/parts/media-entity-card.css +52 -0
- package/dist/parts/media-flip-card.css +78 -0
- package/dist/parts/media-image-zoom.css +68 -0
- package/dist/parts/media-lightbox.css +131 -0
- package/dist/parts/media-message-thread.css +136 -0
- package/dist/parts/media-message.css +160 -0
- package/dist/parts/media-row.css +78 -0
- package/dist/parts/media-stack-card.css +82 -0
- package/dist/parts/media-terminal-log.css +76 -0
- package/dist/parts/media-thumb.css +71 -0
- package/dist/parts/site-fact-list.css +25 -0
- package/dist/parts/site-link-arrow.css +34 -0
- package/dist/parts/site-marquee.css +34 -0
- package/dist/parts/site-next-teaser.css +75 -0
- package/dist/parts/site-price-card.css +91 -0
- package/dist/parts/site-product-mark.css +66 -0
- package/dist/parts/site-project-card.css +111 -0
- package/dist/parts/site-prose.css +124 -0
- package/dist/parts/site-stack-list.css +48 -0
- package/dist/parts/site-timeline.css +54 -0
- package/dist/showcase.css +404 -0
- package/manifest.json +1108 -0
- package/package.json +69 -6
- package/snippets/accordion-accent.html +24 -0
- package/snippets/accordion.html +11 -0
- package/snippets/affix-input.html +30 -0
- package/snippets/alert-dialog.html +22 -0
- package/snippets/alert.html +5 -0
- package/snippets/alpha-tabs.html +37 -0
- package/snippets/aspect-ratio.html +15 -0
- package/snippets/attachment.html +43 -0
- package/snippets/avatar.html +6 -0
- package/snippets/back-link.html +5 -0
- package/snippets/badge.html +5 -0
- package/snippets/barcode-input.html +18 -0
- package/snippets/breadcrumb.html +6 -0
- package/snippets/browser-frame.html +18 -0
- package/snippets/busy-overlay.html +31 -0
- package/snippets/button-group.html +21 -0
- package/snippets/button.html +8 -0
- package/snippets/calendar.html +43 -0
- package/snippets/card.html +17 -0
- package/snippets/carousel.html +21 -0
- package/snippets/chart-line.html +46 -0
- package/snippets/chart.html +27 -0
- package/snippets/chat-composer.html +21 -0
- package/snippets/checkbox.html +5 -0
- package/snippets/checklist.html +23 -0
- package/snippets/chip-filter.html +14 -0
- package/snippets/code-window.html +20 -0
- package/snippets/collapsible.html +19 -0
- package/snippets/color-field.html +13 -0
- package/snippets/color-select.html +18 -0
- package/snippets/column-menu.html +38 -0
- package/snippets/combobox.html +19 -0
- package/snippets/command.html +24 -0
- package/snippets/confirm-dialog.html +32 -0
- package/snippets/context-menu.html +25 -0
- package/snippets/cookie-consent.html +70 -0
- package/snippets/copy-field.html +19 -0
- package/snippets/counter.html +2 -0
- package/snippets/data-table.html +151 -0
- package/snippets/date-picker.html +32 -0
- package/snippets/decimal-input.html +20 -0
- package/snippets/definition-list.html +20 -0
- package/snippets/demo-panel.html +18 -0
- package/snippets/doc-viewer.html +58 -0
- package/snippets/drawer.html +30 -0
- package/snippets/dropdown-menu.html +27 -0
- package/snippets/dropdown.html +9 -0
- package/snippets/dropzone.html +13 -0
- package/snippets/emoji-picker.html +51 -0
- package/snippets/empty-state.html +17 -0
- package/snippets/entity-card.html +26 -0
- package/snippets/expandable-table.html +26 -0
- package/snippets/fact-list.html +14 -0
- package/snippets/filter-counts.html +30 -0
- package/snippets/flip-card.html +22 -0
- package/snippets/form-field.html +6 -0
- package/snippets/greeting.html +22 -0
- package/snippets/heading.html +14 -0
- package/snippets/hover-card.html +18 -0
- package/snippets/image-zoom.html +30 -0
- package/snippets/input-group.html +10 -0
- package/snippets/input.html +5 -0
- package/snippets/item.html +26 -0
- package/snippets/kbd.html +13 -0
- package/snippets/label.html +9 -0
- package/snippets/language-select.html +26 -0
- package/snippets/launcher-card.html +14 -0
- package/snippets/lightbox.html +50 -0
- package/snippets/link-arrow.html +10 -0
- package/snippets/list-toolbar.html +33 -0
- package/snippets/marquee.html +15 -0
- package/snippets/media-card.html +28 -0
- package/snippets/media-row.html +21 -0
- package/snippets/media-thumb.html +12 -0
- package/snippets/menubar.html +30 -0
- package/snippets/message-thread.html +123 -0
- package/snippets/message.html +51 -0
- package/snippets/modal.html +15 -0
- package/snippets/native-select.html +15 -0
- package/snippets/navmenu.html +23 -0
- package/snippets/next-teaser.html +15 -0
- package/snippets/number-input.html +27 -0
- package/snippets/otp-input.html +9 -0
- package/snippets/page-header.html +24 -0
- package/snippets/pagination.html +6 -0
- package/snippets/password-input.html +24 -0
- package/snippets/password-requirements.html +30 -0
- package/snippets/phone-input.html +22 -0
- package/snippets/popover.html +15 -0
- package/snippets/price-card.html +34 -0
- package/snippets/product-mark.html +13 -0
- package/snippets/progress.html +4 -0
- package/snippets/project-card.html +23 -0
- package/snippets/prose.html +54 -0
- package/snippets/radio.html +17 -0
- package/snippets/recovery-codes.html +20 -0
- package/snippets/resizable.html +16 -0
- package/snippets/scroll-area.html +20 -0
- package/snippets/search.html +8 -0
- package/snippets/segmented.html +11 -0
- package/snippets/select.html +7 -0
- package/snippets/separator.html +15 -0
- package/snippets/severity-card.html +35 -0
- package/snippets/sheet.html +32 -0
- package/snippets/sidebar-docs.html +24 -0
- package/snippets/sidebar.html +55 -0
- package/snippets/site-footer.html +6 -0
- package/snippets/site-header.html +26 -0
- package/snippets/skeleton.html +4 -0
- package/snippets/slider.html +17 -0
- package/snippets/sortable-row.html +31 -0
- package/snippets/spinner.html +14 -0
- package/snippets/stack-card.html +17 -0
- package/snippets/stack-list.html +16 -0
- package/snippets/stat-card.html +24 -0
- package/snippets/stepper.html +13 -0
- package/snippets/switch.html +6 -0
- package/snippets/table-actions.html +39 -0
- package/snippets/table-compact.html +24 -0
- package/snippets/table.html +29 -0
- package/snippets/tabs.html +9 -0
- package/snippets/tag-input.html +60 -0
- package/snippets/terminal-log.html +23 -0
- package/snippets/textarea.html +3 -0
- package/snippets/theme-switch.html +6 -0
- package/snippets/time-input.html +26 -0
- package/snippets/timeline.html +28 -0
- package/snippets/toast-stack.html +10 -0
- package/snippets/toast.html +36 -0
- package/snippets/toc.html +13 -0
- package/snippets/toggle-field.html +20 -0
- package/snippets/toggle.html +22 -0
- package/snippets/tooltip.html +4 -0
- package/snippets/top-progress.html +12 -0
- package/snippets/tree.html +38 -0
- package/snippets/upgrade-banner.html +28 -0
- package/snippets/user.html +15 -0
- package/snippets/version-banner.html +15 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/* File: packages/ui/src/parts/media-message-thread.css | Map: frame (grid: header / messages / composer) -> header (title, meta,
|
|
2
|
+
people, status, actions) -> wallpaper (masked doodles in a token color) -> scroll area (starts at the bottom)
|
|
3
|
+
-> composer footer -> sending overlay (aria-busy) -> reduced motion
|
|
4
|
+
Message thread: one conversation. The scroll area uses flex-direction: column-reverse, so it opens at the newest message
|
|
5
|
+
and stays there when messages are added, without a script. Based on the question chat of the Korrekt app. */
|
|
6
|
+
|
|
7
|
+
.oc-message-thread {
|
|
8
|
+
--oc-message-thread-height: 32rem;
|
|
9
|
+
position: relative;
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
12
|
+
grid-template-columns: minmax(0, 1fr);
|
|
13
|
+
block-size: var(--oc-message-thread-height);
|
|
14
|
+
min-inline-size: 0;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
border: 1px solid var(--oc-border);
|
|
17
|
+
border-radius: calc(var(--oc-radius) + 4px);
|
|
18
|
+
background: color-mix(in oklch, var(--oc-muted) 40%, var(--oc-background));
|
|
19
|
+
color: var(--oc-foreground);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* ---- Header ---- */
|
|
23
|
+
.oc-message-thread__header {
|
|
24
|
+
grid-row: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 0.75rem;
|
|
28
|
+
min-inline-size: 0;
|
|
29
|
+
padding: 0.6rem 0.6rem 0.6rem 1rem;
|
|
30
|
+
border-block-end: 1px solid var(--oc-border);
|
|
31
|
+
background: var(--oc-card);
|
|
32
|
+
}
|
|
33
|
+
.oc-message-thread__heading { display: grid; flex: 1 1 auto; gap: 0.1rem; min-inline-size: 0; }
|
|
34
|
+
/* Two classes, so global heading styles (text-wrap on h3) cannot make the title wrap */
|
|
35
|
+
.oc-message-thread__heading > .oc-message-thread__title {
|
|
36
|
+
margin: 0;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
font-size: 0.95rem;
|
|
39
|
+
font-weight: 650;
|
|
40
|
+
line-height: 1.3;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
text-overflow: ellipsis;
|
|
43
|
+
}
|
|
44
|
+
.oc-message-thread__heading > .oc-message-thread__meta {
|
|
45
|
+
margin: 0;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
color: var(--oc-muted-foreground);
|
|
48
|
+
font-size: 0.75rem;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
text-overflow: ellipsis;
|
|
51
|
+
}
|
|
52
|
+
.oc-message-thread__meta strong { color: var(--oc-primary); font-weight: 600; }
|
|
53
|
+
.oc-message-thread__people { flex: none; }
|
|
54
|
+
.oc-message-thread__people .oc-avatar { inline-size: 1.75rem; block-size: 1.75rem; font-size: 0.62rem; border-color: var(--oc-card); }
|
|
55
|
+
.oc-message-thread__actions { display: flex; flex: none; align-items: center; gap: 0.35rem; }
|
|
56
|
+
.oc-message-thread__icon-btn {
|
|
57
|
+
display: grid;
|
|
58
|
+
place-items: center;
|
|
59
|
+
inline-size: 2rem;
|
|
60
|
+
block-size: 2rem;
|
|
61
|
+
padding: 0;
|
|
62
|
+
border: 0;
|
|
63
|
+
border-radius: 50%;
|
|
64
|
+
background: transparent;
|
|
65
|
+
color: var(--oc-muted-foreground);
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
}
|
|
68
|
+
.oc-message-thread__icon-btn svg { inline-size: 1.1rem; block-size: 1.1rem; }
|
|
69
|
+
.oc-message-thread__icon-btn:hover { background: var(--oc-surface-strong); color: var(--oc-foreground); }
|
|
70
|
+
.oc-message-thread__icon-btn:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
71
|
+
|
|
72
|
+
/* ---- Wallpaper: line doodles (chat bubble, note, sun, house, lamp…) as a mask, painted in a token color ---- */
|
|
73
|
+
.oc-message-thread::before {
|
|
74
|
+
content: "";
|
|
75
|
+
grid-row: 2;
|
|
76
|
+
grid-column: 1;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
background: oklch(from var(--oc-muted-foreground) l c h / 0.11);
|
|
79
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cg fill='none' stroke='currentColor' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M28 36h28a6 6 0 0 1 6 6v14a6 6 0 0 1-6 6H40l-10 8v-8h-2a6 6 0 0 1-6-6V42a6 6 0 0 1 6-6z'/%3E%3Cpath d='M118 42h22v28H118z'/%3E%3Cpath d='M122 50h14M122 56h10'/%3E%3Ccircle cx='188' cy='52' r='10'/%3E%3Cpath d='M188 42v4M188 58v4M178 52h4M194 52h4'/%3E%3Cpath d='M42 118l8-4 8 4v10l-8 4-8-4z'/%3E%3Ccircle cx='50' cy='123' r='2.5'/%3E%3Cpath d='M128 112h24v18H128zM132 118h16M132 124h10'/%3E%3Cpath d='M178 118c6 0 10 4 10 10s-4 10-10 10-10-4-10-10 4-10 10-10z'/%3E%3Cpath d='M178 124v8M174 128h8'/%3E%3Cpath d='M36 178h20l4 12H32z'/%3E%3Cpath d='M120 176c8 0 14 6 14 14H106c0-8 6-14 14-14z'/%3E%3Ccircle cx='120' cy='168' r='7'/%3E%3Cpath d='M176 172h24v20h-24z'/%3E%3Cpath d='M182 178h12M182 184h8'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 220px 220px repeat;
|
|
80
|
+
}
|
|
81
|
+
.oc-message-thread--plain::before { display: none; }
|
|
82
|
+
|
|
83
|
+
/* ---- Scroll area: column-reverse keeps the newest message in view ---- */
|
|
84
|
+
.oc-message-thread__scroll {
|
|
85
|
+
grid-row: 2;
|
|
86
|
+
grid-column: 1;
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column-reverse;
|
|
89
|
+
min-block-size: 0;
|
|
90
|
+
overflow-y: auto;
|
|
91
|
+
overscroll-behavior: contain;
|
|
92
|
+
scrollbar-width: thin;
|
|
93
|
+
scrollbar-color: var(--oc-border-strong, var(--oc-border)) transparent;
|
|
94
|
+
}
|
|
95
|
+
.oc-message-thread__scroll:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
96
|
+
.oc-message-thread__scroll > .oc-message-list { padding: 1rem 0.85rem; }
|
|
97
|
+
|
|
98
|
+
/* ---- Composer footer: optional attachment chips + the chat-composer ---- */
|
|
99
|
+
.oc-message-thread__footer {
|
|
100
|
+
grid-row: 3;
|
|
101
|
+
display: grid;
|
|
102
|
+
gap: 0.5rem;
|
|
103
|
+
padding: 0.6rem 0.75rem 0.75rem;
|
|
104
|
+
border-block-start: 1px solid var(--oc-border);
|
|
105
|
+
background: var(--oc-card);
|
|
106
|
+
box-shadow: 0 -4px 16px oklch(from var(--color-black-60) l c h / 0.05);
|
|
107
|
+
}
|
|
108
|
+
.oc-message-thread__footer .oc-chat-composer { background: var(--oc-background); }
|
|
109
|
+
.oc-message-thread__note { margin: 0; color: var(--oc-muted-foreground); font-size: 0.75rem; text-align: center; }
|
|
110
|
+
|
|
111
|
+
/* ---- Sending overlay: set aria-busy="true" on the thread while a message or upload is on its way ---- */
|
|
112
|
+
.oc-message-thread__busy {
|
|
113
|
+
position: absolute;
|
|
114
|
+
inset: 0;
|
|
115
|
+
z-index: 3;
|
|
116
|
+
display: none;
|
|
117
|
+
place-content: center;
|
|
118
|
+
justify-items: center;
|
|
119
|
+
gap: 0.4rem;
|
|
120
|
+
padding: 1.5rem;
|
|
121
|
+
background: color-mix(in oklch, var(--oc-background) 82%, transparent);
|
|
122
|
+
backdrop-filter: blur(2px);
|
|
123
|
+
text-align: center;
|
|
124
|
+
}
|
|
125
|
+
.oc-message-thread[aria-busy="true"] > .oc-message-thread__busy { display: grid; }
|
|
126
|
+
.oc-message-thread__busy > .oc-spinner { margin-block-end: 0.35rem; color: var(--oc-primary); }
|
|
127
|
+
.oc-message-thread__busy strong { font-size: 0.9rem; }
|
|
128
|
+
.oc-message-thread__busy span { color: var(--oc-muted-foreground); font-size: 0.78rem; }
|
|
129
|
+
|
|
130
|
+
@container (width < 26rem) {
|
|
131
|
+
.oc-message-thread__people { display: none; }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@media (prefers-reduced-motion: reduce) {
|
|
135
|
+
.oc-message-thread__busy { backdrop-filter: none; }
|
|
136
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/* File: packages/ui/src/parts/media-message.css | Map: list -> row (in / out) -> avatar -> bubble (sender, quote, text, attachments, meta)
|
|
2
|
+
-> grouping (:has) -> hover actions -> date divider + system line -> reduced motion
|
|
3
|
+
Message: one chat bubble. Incoming on the left with the avatar, outgoing on the right in the primary tint.
|
|
4
|
+
Consecutive messages of one sender group by themselves: the avatar shows once (on the last one), the name once (on the
|
|
5
|
+
first one). Based on the question chat of the Korrekt app. */
|
|
6
|
+
|
|
7
|
+
.oc-message-list {
|
|
8
|
+
--oc-message-in: var(--oc-card);
|
|
9
|
+
--oc-message-out: color-mix(in oklch, var(--oc-primary) 14%, var(--oc-card));
|
|
10
|
+
--oc-message-shadow: 0 1px 2px oklch(from var(--color-black-60) l c h / 0.08), 0 4px 12px oklch(from var(--color-black-60) l c h / 0.06);
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
gap: 0.75rem;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0.75rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ---- Row: avatar | bubble | actions (mirrored for outgoing) ---- */
|
|
19
|
+
.oc-message {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: flex-end;
|
|
22
|
+
gap: 0.5rem;
|
|
23
|
+
min-inline-size: 0;
|
|
24
|
+
margin: 0;
|
|
25
|
+
}
|
|
26
|
+
.oc-message--out { flex-direction: row-reverse; }
|
|
27
|
+
.oc-message__avatar { inline-size: 2rem; block-size: 2rem; font-size: 0.7rem; border: 1px solid var(--oc-border); }
|
|
28
|
+
.oc-message--out .oc-message__avatar { background: color-mix(in oklch, var(--oc-primary) 18%, var(--oc-card)); color: var(--oc-primary); }
|
|
29
|
+
|
|
30
|
+
/* ---- Bubble ---- */
|
|
31
|
+
.oc-message__bubble {
|
|
32
|
+
display: grid;
|
|
33
|
+
gap: 0.25rem;
|
|
34
|
+
min-inline-size: 0;
|
|
35
|
+
max-inline-size: min(78%, 34rem);
|
|
36
|
+
padding: 0.5rem 0.8rem 0.4rem;
|
|
37
|
+
border: 1px solid var(--oc-border);
|
|
38
|
+
border-radius: 1rem 1rem 1rem 0.25rem;
|
|
39
|
+
background: var(--oc-message-in, var(--oc-card));
|
|
40
|
+
box-shadow: var(--oc-message-shadow, none);
|
|
41
|
+
color: var(--oc-foreground);
|
|
42
|
+
font-size: 0.875rem;
|
|
43
|
+
line-height: 1.5;
|
|
44
|
+
}
|
|
45
|
+
.oc-message--out .oc-message__bubble {
|
|
46
|
+
border-color: color-mix(in oklch, var(--oc-primary) 22%, var(--oc-border));
|
|
47
|
+
border-radius: 1rem 1rem 0.25rem 1rem;
|
|
48
|
+
background: var(--oc-message-out, var(--oc-muted));
|
|
49
|
+
}
|
|
50
|
+
.oc-message__sender { margin: 0; color: var(--oc-primary); font-size: 0.72rem; font-weight: 650; }
|
|
51
|
+
|
|
52
|
+
/* Message text: paragraphs, lists, bold/italic, links and inline code (the output of a small markdown renderer) */
|
|
53
|
+
.oc-message__text { min-inline-size: 0; overflow-wrap: anywhere; }
|
|
54
|
+
.oc-message__text > :is(p, ul, ol) { margin: 0; }
|
|
55
|
+
.oc-message__text > * + * { margin-block-start: 0.35rem; }
|
|
56
|
+
.oc-message__text :is(ul, ol) { padding-inline-start: 1.15rem; }
|
|
57
|
+
.oc-message__text a { color: var(--oc-primary); text-decoration: underline; text-underline-offset: 2px; }
|
|
58
|
+
.oc-message__text a:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; border-radius: 2px; }
|
|
59
|
+
.oc-message__text code { padding: 0.05rem 0.3rem; border-radius: 4px; background: var(--oc-surface-strong); font-size: 0.85em; }
|
|
60
|
+
|
|
61
|
+
/* Reply quote: the message this one answers (a link back to it) */
|
|
62
|
+
.oc-message__quote {
|
|
63
|
+
display: grid;
|
|
64
|
+
gap: 0.1rem;
|
|
65
|
+
padding: 0.35rem 0.6rem;
|
|
66
|
+
border-inline-start: 3px solid var(--oc-primary);
|
|
67
|
+
border-radius: 0.4rem;
|
|
68
|
+
background: var(--oc-surface-strong);
|
|
69
|
+
color: var(--oc-muted-foreground);
|
|
70
|
+
font-size: 0.8rem;
|
|
71
|
+
line-height: 1.4;
|
|
72
|
+
text-decoration: none;
|
|
73
|
+
}
|
|
74
|
+
.oc-message__quote > strong { color: var(--oc-foreground); font-size: 0.72rem; font-weight: 650; }
|
|
75
|
+
.oc-message__quote > span { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
|
76
|
+
a.oc-message__quote:hover { background: color-mix(in oklch, var(--oc-primary) 10%, transparent); }
|
|
77
|
+
a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
78
|
+
|
|
79
|
+
.oc-message__attachments { display: grid; gap: 0.35rem; margin-block-start: 0.15rem; }
|
|
80
|
+
|
|
81
|
+
/* Time + read receipt, small and right aligned */
|
|
82
|
+
.oc-message__meta {
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-wrap: wrap;
|
|
85
|
+
justify-content: flex-end;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 0.35rem;
|
|
88
|
+
margin: 0;
|
|
89
|
+
color: var(--oc-muted-foreground);
|
|
90
|
+
font-size: 0.68rem;
|
|
91
|
+
font-variant-numeric: tabular-nums;
|
|
92
|
+
}
|
|
93
|
+
.oc-message__status { display: inline-flex; align-items: center; gap: 0.2rem; }
|
|
94
|
+
.oc-message__status--read { color: var(--oc-success); font-weight: 600; }
|
|
95
|
+
.oc-message__status--failed { color: var(--oc-destructive); font-weight: 600; }
|
|
96
|
+
.oc-message__status svg { inline-size: 0.85rem; block-size: 0.85rem; }
|
|
97
|
+
|
|
98
|
+
/* ---- Grouping: a --continued message follows one of the same sender ---- */
|
|
99
|
+
.oc-message--continued { margin-block-start: -0.5rem; }
|
|
100
|
+
.oc-message--continued .oc-message__sender { display: none; }
|
|
101
|
+
.oc-message:has(+ .oc-message--continued) .oc-message__avatar { visibility: hidden; }
|
|
102
|
+
.oc-message:has(+ .oc-message--continued) .oc-message__bubble { border-end-start-radius: 1rem; }
|
|
103
|
+
.oc-message--out:has(+ .oc-message--continued) .oc-message__bubble { border-end-start-radius: 1rem; border-end-end-radius: 1rem; }
|
|
104
|
+
.oc-message--continued .oc-message__bubble { border-start-start-radius: 0.25rem; }
|
|
105
|
+
.oc-message--out.oc-message--continued .oc-message__bubble { border-start-start-radius: 1rem; border-start-end-radius: 0.25rem; }
|
|
106
|
+
|
|
107
|
+
/* ---- Actions: appear on hover and keyboard focus (always visible on touch screens) ---- */
|
|
108
|
+
.oc-message__actions {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-self: center;
|
|
111
|
+
gap: 0.15rem;
|
|
112
|
+
opacity: 0;
|
|
113
|
+
transition: opacity var(--oc-transition-normal);
|
|
114
|
+
}
|
|
115
|
+
.oc-message:hover .oc-message__actions,
|
|
116
|
+
.oc-message:focus-within .oc-message__actions { opacity: 1; }
|
|
117
|
+
@media (hover: none) { .oc-message__actions { opacity: 1; } }
|
|
118
|
+
.oc-message__action {
|
|
119
|
+
display: grid;
|
|
120
|
+
place-items: center;
|
|
121
|
+
inline-size: 1.85rem;
|
|
122
|
+
block-size: 1.85rem;
|
|
123
|
+
padding: 0;
|
|
124
|
+
border: 0;
|
|
125
|
+
border-radius: 50%;
|
|
126
|
+
background: transparent;
|
|
127
|
+
color: var(--oc-muted-foreground);
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
}
|
|
130
|
+
.oc-message__action svg { inline-size: 1rem; block-size: 1rem; }
|
|
131
|
+
.oc-message__action:hover { background: var(--oc-surface-strong); color: var(--oc-foreground); }
|
|
132
|
+
.oc-message__action--destructive:hover { background: oklch(from var(--oc-destructive) l c h / 0.12); color: var(--oc-destructive); }
|
|
133
|
+
.oc-message__action:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
134
|
+
|
|
135
|
+
/* ---- Date divider and system line ---- */
|
|
136
|
+
.oc-message-divider {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 0.75rem;
|
|
140
|
+
margin: 0.25rem 0;
|
|
141
|
+
color: var(--oc-muted-foreground);
|
|
142
|
+
font-size: 0.72rem;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
}
|
|
145
|
+
.oc-message-divider::before,
|
|
146
|
+
.oc-message-divider::after { content: ""; flex: 1; border-block-start: 1px solid var(--oc-border); }
|
|
147
|
+
.oc-message-divider > * {
|
|
148
|
+
padding: 0.15rem 0.6rem;
|
|
149
|
+
border: 1px solid var(--oc-border);
|
|
150
|
+
border-radius: 999px;
|
|
151
|
+
background: var(--oc-card);
|
|
152
|
+
}
|
|
153
|
+
.oc-message-divider--system { justify-content: center; font-weight: 500; }
|
|
154
|
+
.oc-message-divider--system::before,
|
|
155
|
+
.oc-message-divider--system::after { display: none; }
|
|
156
|
+
.oc-message-divider--system > * { max-inline-size: 85%; border-style: dashed; background: var(--oc-background); text-align: center; }
|
|
157
|
+
|
|
158
|
+
@media (prefers-reduced-motion: reduce) {
|
|
159
|
+
.oc-message__actions { transition: none; }
|
|
160
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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; } }
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* File: packages/ui/src/parts/site-fact-list.css
|
|
2
|
+
Map: plain -> compact -> stacked -> accent values -> narrow screens
|
|
3
|
+
Fact list component: key / value product facts (the marketing sibling of the definition list).
|
|
4
|
+
The base .oc-fact-list (card with <div><dt><dd> rows) lives in showcase.css. This part ADDS modifiers, plus one safe fix: rows may wrap in very narrow containers. */
|
|
5
|
+
|
|
6
|
+
/* Plain: no card, only lines between the rows. */
|
|
7
|
+
.oc-fact-list--plain {
|
|
8
|
+
border: 0;
|
|
9
|
+
border-radius: 0;
|
|
10
|
+
background: none;
|
|
11
|
+
}
|
|
12
|
+
.oc-fact-list--plain > div { padding-inline: 0; }
|
|
13
|
+
|
|
14
|
+
/* Compact rows (sidebars, small cards). */
|
|
15
|
+
.oc-fact-list--compact > div { padding-block: 0.6rem; font-size: 0.9rem; }
|
|
16
|
+
|
|
17
|
+
/* Stacked: the value goes below the label (long values). */
|
|
18
|
+
.oc-fact-list--stacked > div { flex-direction: column; gap: 0.2rem; }
|
|
19
|
+
.oc-fact-list--stacked dd { text-align: start; }
|
|
20
|
+
|
|
21
|
+
/* Values in the accent color. */
|
|
22
|
+
.oc-fact-list--accent dd { color: var(--oc-accent-from); }
|
|
23
|
+
|
|
24
|
+
/* Very narrow containers: wrap instead of squeezing label and value together. */
|
|
25
|
+
.oc-fact-list > div { flex-wrap: wrap; }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* File: packages/ui/src/parts/site-link-arrow.css
|
|
2
|
+
Map: focus ring -> back arrow -> external arrow -> color modifiers -> sizes -> reduced motion
|
|
3
|
+
Link arrow component. The base .oc-link-arrow (text + "→" that moves on hover) lives in showcase.css.
|
|
4
|
+
This part only ADDS modifiers. */
|
|
5
|
+
|
|
6
|
+
.oc-link-arrow:focus-visible {
|
|
7
|
+
border-radius: 4px;
|
|
8
|
+
outline: 2px solid var(--oc-ring);
|
|
9
|
+
outline-offset: 3px;
|
|
10
|
+
}
|
|
11
|
+
.oc-link-arrow:focus-visible::after { translate: 4px 0; }
|
|
12
|
+
|
|
13
|
+
/* Back link: the arrow points left, sits before the text and moves left on hover. */
|
|
14
|
+
.oc-link-arrow--back::after { content: none; }
|
|
15
|
+
.oc-link-arrow--back::before { content: "←"; transition: translate 0.2s var(--oc-ease-out); }
|
|
16
|
+
.oc-link-arrow--back:is(:hover, :focus-visible)::before { translate: -4px 0; }
|
|
17
|
+
|
|
18
|
+
/* External link: diagonal arrow that moves up-right. */
|
|
19
|
+
.oc-link-arrow--external::after { content: "↗"; }
|
|
20
|
+
.oc-link-arrow--external:is(:hover, :focus-visible)::after { translate: 3px -3px; }
|
|
21
|
+
|
|
22
|
+
/* Colors: accent of the element, or muted text that turns to the foreground color on hover. */
|
|
23
|
+
.oc-link-arrow--accent { color: var(--oc-accent-from); }
|
|
24
|
+
.oc-link-arrow--muted { color: var(--oc-muted-foreground); font-weight: 500; transition: color 0.2s; }
|
|
25
|
+
.oc-link-arrow--muted:hover { color: var(--oc-foreground); }
|
|
26
|
+
|
|
27
|
+
/* Sizes */
|
|
28
|
+
.oc-link-arrow--sm { font-size: 0.85rem; }
|
|
29
|
+
.oc-link-arrow--lg { font-size: 1.15rem; }
|
|
30
|
+
|
|
31
|
+
@media (prefers-reduced-motion: reduce) {
|
|
32
|
+
.oc-link-arrow::after,
|
|
33
|
+
.oc-link-arrow::before { transition: none; }
|
|
34
|
+
}
|