@linhey/rhine-design 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +24 -7
- package/components/AdvancedForms.tsx +184 -0
- package/components/AppShell.tsx +71 -0
- package/components/Background.tsx +29 -0
- package/components/COMMON_COMPONENTS.md +2 -2
- package/components/Charts.tsx +94 -0
- package/components/Data.tsx +98 -18
- package/components/Forms.tsx +14 -8
- package/components/MOTION.md +9 -1
- package/components/Media.tsx +82 -0
- package/components/OrbitBackdrop.tsx +33 -0
- package/components/Overlays.tsx +4 -3
- package/components/README.md +12 -1
- package/components/StatusTimeline.tsx +50 -12
- package/components/background.css +43 -0
- package/components/charts.css +27 -0
- package/components/common.css +5 -5
- package/components/data.css +6 -0
- package/components/drawer-placement.css +4 -0
- package/components/extensions.css +70 -0
- package/components/index.ts +14 -2
- package/components/media-parity.css +3 -0
- package/components/orbit.css +42 -0
- package/components/orbitRenderer.ts +230 -0
- package/components/patterns.css +1 -1
- package/components/styles.css +5 -1
- package/components/theme-arknights.css +10 -5
- package/components/theme-neo-brutalism.css +10 -4
- package/components/timeline.css +2 -2
- package/components/tokens.css +43 -0
- package/docs/ANTD_MUI_AUDIT.md +38 -0
- package/docs/APPLICATION_COMPONENTS.md +175 -0
- package/docs/DESIGN_SYSTEM_AUDIT.md +2 -0
- package/docs/ISSUE_4_VALIDATION.md +21 -0
- package/docs/ISSUE_VALIDATION.md +52 -0
- package/docs/ORBIT_BACKDROP.md +81 -0
- package/docs/REFERENCE_RESEARCH.md +2 -0
- package/docs/THEMING.md +41 -0
- package/docs/assets/application-shell.png +0 -0
- package/docs/assets/issue4-shell.png +0 -0
- package/docs/assets/media-viewer-mobile.png +0 -0
- package/docs/assets/monitoring-desktop.png +0 -0
- package/docs/assets/orbit-backdrop.png +0 -0
- package/docs/audits/DATA_ANTD_MUI.md +75 -0
- package/docs/audits/FORMS_ANTD_MUI.md +88 -0
- package/docs/audits/MONITORING_ANTD_MUI.md +44 -0
- package/docs/audits/SHELL_MEDIA_ANTD_MUI.md +91 -0
- package/package.json +1 -1
- package/preview/BackgroundGallery.tsx +46 -0
- package/preview/ExtensionsGallery.tsx +95 -0
- package/preview/GalleryShell.tsx +4 -3
- package/preview/MonitoringGallery.tsx +27 -0
- package/preview/OrbitGallery.tsx +47 -0
- package/preview/backgrounds.css +10 -0
- package/preview/extensions.css +6 -0
- package/preview/main.tsx +12 -1
- package/skills/rhine-design/SKILL.md +24 -3
- package/skills/rhine-design/references/API_MAP.md +6 -0
- package/skills/rhine-design/references/TASK_MAP.md +3 -1
- package/skills/rhine-design/references/integration.md +4 -2
- package/tests/Background.test.tsx +22 -0
- package/tests/DataParity.test.tsx +148 -0
- package/tests/Extensions.test.tsx +145 -0
- package/tests/FormParity.test.tsx +185 -0
- package/tests/Monitoring.test.tsx +38 -0
- package/tests/MonitoringParity.test.tsx +125 -0
- package/tests/OrbitBackdrop.test.tsx +183 -0
- package/tests/ShellMediaParity.test.tsx +180 -0
package/components/common.css
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
.rhine-table caption { text-align:left; font-size:var(--rhine-text-heading); line-height:var(--rhine-leading-heading); font-weight:var(--rhine-weight-heading); margin-bottom:var(--rhine-space-4); }
|
|
22
22
|
.rhine-table th,.rhine-table td { padding:12px; border-bottom:1px solid var(--rhine-line); max-width:240px; overflow-wrap:anywhere; }
|
|
23
23
|
.rhine-table th { color:var(--rhine-muted); font-weight:500; }.rhine-table td { font-variant-numeric:tabular-nums; }
|
|
24
|
-
.rhine-table [data-align=right] { text-align:right; }.rhine-table tbody tr:hover { background:var(--rhine-
|
|
24
|
+
.rhine-table [data-align=right] { text-align:right; }.rhine-table tbody tr:hover { background:var(--rhine-table-hover-bg); }
|
|
25
25
|
.rhine-table th button { font:inherit; color:inherit; background:none; border:0; min-height:44px; cursor:pointer; padding:0; }
|
|
26
26
|
.rhine-table th button:disabled { cursor:default; }
|
|
27
27
|
.rhine-pagination { display:flex; flex-wrap:wrap; justify-content:flex-end; align-items:center; gap:12px; }
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
.rhine-combobox { position:relative; }
|
|
44
44
|
.rhine-combobox__input { position:relative; }.rhine-combobox__input input { padding-right:40px; }
|
|
45
45
|
.rhine-combobox__arrow { position:absolute; right:12px; top:50%; transform:translateY(-50%); pointer-events:none; }
|
|
46
|
-
.rhine-combobox__list { z-index:50; width:var(--radix-popover-trigger-width); max-width:calc(100vw - 24px); max-height:min(240px,var(--radix-popover-content-available-height)); overflow:auto; background:var(--rhine-
|
|
46
|
+
.rhine-combobox__list { z-index:50; width:var(--radix-popover-trigger-width); max-width:calc(100vw - 24px); max-height:min(240px,var(--radix-popover-content-available-height)); overflow:auto; background:var(--rhine-overlay-bg); color:var(--rhine-overlay-text); border:1px solid var(--rhine-control); border-radius:4px; box-shadow:0 8px 24px #242b2818; }
|
|
47
47
|
.rhine-combobox__list [role=option],.rhine-combobox__empty { padding:12px; min-height:44px; cursor:pointer; overflow-wrap:anywhere; }
|
|
48
48
|
.rhine-combobox__list [role=option][data-active=true],.rhine-combobox__list [role=option][aria-selected=true] { background:var(--rhine-selected); }
|
|
49
49
|
.rhine-combobox__list [role=option][aria-disabled=true],.rhine-combobox__empty { color:var(--rhine-muted); cursor:default; }
|
|
50
50
|
.rhine-overlay-anchor { display:inline-block; vertical-align:middle; max-width:100%; }
|
|
51
|
-
.rhine-overlay { position:fixed; inset:0; background
|
|
52
|
-
.rhine-dialog { position:fixed; z-index:41; top:50%; left:50%; transform:translate(-50%,-50%); width:min(480px,calc(100vw - 32px)); max-height:calc(100dvh - 32px); overflow:auto; padding:24px; border:1px solid var(--rhine-line); border-radius:4px; background:var(--rhine-
|
|
51
|
+
.rhine-overlay { position:fixed; inset:0; background:var(--rhine-backdrop-bg); z-index:40; }
|
|
52
|
+
.rhine-dialog { position:fixed; z-index:41; top:50%; left:50%; transform:translate(-50%,-50%); width:min(480px,calc(100vw - 32px)); max-height:calc(100dvh - 32px); overflow:auto; padding:24px; border:1px solid var(--rhine-line); border-radius:4px; background:var(--rhine-overlay-bg); color:var(--rhine-overlay-text); box-shadow:0 16px 48px #242b2826; }
|
|
53
53
|
.rhine-dialog>p,.rhine-dialog__main>p { margin-top:12px; }.rhine-dialog>.rhine-notice { margin-top:16px; }
|
|
54
54
|
.rhine-dialog__main { min-width:0; }
|
|
55
55
|
.rhine-dialog--split { width:min(960px,calc(100vw - 32px)); display:grid; grid-template-columns:minmax(240px,0.8fr) minmax(0,1.2fr); gap:24px; }
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
.rhine-dialog__head { display:flex; align-items:center; justify-content:space-between; gap:12px; }
|
|
64
64
|
.rhine-dialog__head>:first-child { min-width:0; overflow-wrap:anywhere; }
|
|
65
65
|
.rhine-dialog__body { margin-top:24px; }.rhine-dialog__actions { display:flex; justify-content:flex-end; flex-wrap:wrap; gap:12px; margin-top:24px; }
|
|
66
|
-
.rhine-popover,.rhine-menu { z-index:50; background:var(--rhine-
|
|
66
|
+
.rhine-popover,.rhine-menu { z-index:50; background:var(--rhine-overlay-bg); color:var(--rhine-overlay-text); border:1px solid var(--rhine-control); border-radius:4px; box-shadow:0 8px 24px #242b2820; max-width:calc(100vw - 24px); overflow:auto; }
|
|
67
67
|
.rhine-popover { width:300px; padding:16px; max-height:var(--radix-popover-content-available-height); }
|
|
68
68
|
.rhine-menu { min-width:180px; max-height:var(--radix-dropdown-menu-content-available-height); padding:4px; }
|
|
69
69
|
.rhine-menu__item { min-height:44px; padding:10px 12px; cursor:pointer; outline:none; overflow-wrap:anywhere; }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
.rhine-data .rhine-table tbody th[scope=row] { position:static; top:auto; z-index:auto; color:var(--rhine-ink); background:var(--rhine-surface); font-weight:var(--rhine-weight-label); }
|
|
2
|
+
.rhine-data .rhine-table tbody th[scope=row][data-sticky] { position:sticky; z-index:1; }
|
|
3
|
+
.rhine-data .rhine-table tr[data-selected=true] th[scope=row] { background:var(--rhine-table-selected-bg); }
|
|
4
|
+
.rhine-table__radio { display:flex; align-items:center; gap:8px; min-height:44px; cursor:pointer; }
|
|
5
|
+
.rhine-table__radio input { flex:none; width:18px; height:18px; accent-color:var(--rhine-green); }
|
|
6
|
+
.rhine-table__radio:has(input:disabled) { color:var(--rhine-muted); cursor:default; }
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
.rhine-dialog.rhine-drawer[data-side=left] { left:0; right:auto; animation-name:rhine-drawer-enter-left; }
|
|
2
|
+
.rhine-dialog.rhine-drawer[data-side=right] { left:auto; right:0; }
|
|
3
|
+
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-drawer[data-side=left] { border-radius:0 24px 24px 0; box-shadow:5px 0 0 var(--rhine-ink); }
|
|
4
|
+
@keyframes rhine-drawer-enter-left { from { opacity:0; transform:translateX(-3px); } to { opacity:1; transform:translateX(0); } }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
.rhine-shell { height:100%; min-height:0; min-width:0; display:flex; flex-direction:column; border:1px solid var(--rhine-line); background:var(--rhine-canvas-bg); }
|
|
2
|
+
.rhine-shell__header { flex:none; display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:12px; border-bottom:1px solid var(--rhine-line); background:var(--rhine-surface); }
|
|
3
|
+
.rhine-shell__body { display:flex; flex:1; min-height:0; min-width:0; }
|
|
4
|
+
.rhine-shell__nav, .rhine-shell__secondary { flex:0 0 224px; min-width:0; overflow:auto; padding:16px; background:var(--rhine-sidebar-bg); border-right:1px solid var(--rhine-line); overflow-wrap:anywhere; }
|
|
5
|
+
.rhine-shell__secondary { flex-basis:256px; }
|
|
6
|
+
.rhine-shell[data-layout=left-right] .rhine-shell__secondary { order:2; border-right:0; border-left:1px solid var(--rhine-line); }
|
|
7
|
+
.rhine-shell__content { flex:1; min-width:0; min-height:0; overflow:auto; padding:24px; overflow-wrap:anywhere; }
|
|
8
|
+
.rhine-date-range { margin:0; min-width:0; padding:16px; border:1px solid var(--rhine-line); background:var(--rhine-field-group-bg); }
|
|
9
|
+
.rhine-date-range legend { padding:0 4px; font-weight:600; }
|
|
10
|
+
.rhine-date-range__fields { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr)); gap:16px; margin-bottom:16px; }
|
|
11
|
+
.rhine-date-range input { max-width:100%; min-width:0; }
|
|
12
|
+
.rhine-number-field { display:grid; gap:8px; min-width:0; }
|
|
13
|
+
.rhine-multi-select { min-width:0; }
|
|
14
|
+
.rhine-multi-select__tags { display:flex; flex-wrap:wrap; gap:8px; list-style:none; padding:0; margin:8px 0; }
|
|
15
|
+
.rhine-multi-select__tags li { display:flex; align-items:center; max-width:100%; padding-left:12px; border:1px solid var(--rhine-line); background:var(--rhine-selected); border-radius:var(--rhine-radius-control); }
|
|
16
|
+
.rhine-multi-select__tags li>span { min-width:0; overflow-wrap:anywhere; }
|
|
17
|
+
.rhine-multi-select__tags .rhine-button { flex:none; }
|
|
18
|
+
.rhine-tree { min-width:0; padding:8px; border:1px solid var(--rhine-line); background:var(--rhine-field-group-bg); }
|
|
19
|
+
.rhine-tree [role=group] { padding-left:var(--rhine-tree-indent); }
|
|
20
|
+
.rhine-tree__row { display:flex; align-items:center; gap:8px; min-height:44px; padding:4px; overflow-wrap:anywhere; cursor:pointer; }
|
|
21
|
+
.rhine-tree__row>span:last-of-type { min-width:0; flex:1; }
|
|
22
|
+
.rhine-tree__row[data-selected=true] { background:var(--rhine-selected); }
|
|
23
|
+
.rhine-tree [aria-disabled=true]>.rhine-tree__row { color:var(--rhine-muted); cursor:default; }
|
|
24
|
+
.rhine-tree__row button { min-height:44px; min-width:44px; border:1px solid var(--rhine-line); background:var(--rhine-surface); color:var(--rhine-ink); font:inherit; cursor:pointer; }
|
|
25
|
+
.rhine-tree__spacer { flex:0 0 12px; }
|
|
26
|
+
.rhine-data[data-density=compact] { --rhine-table-cell-padding:6px 12px; }
|
|
27
|
+
.rhine-data .rhine-table-scroll { max-width:100%; overflow:auto; scroll-padding:48px; }
|
|
28
|
+
.rhine-data .rhine-table :is(th,td) { padding:var(--rhine-table-cell-padding); overflow-wrap:anywhere; font-size:14px; }
|
|
29
|
+
.rhine-table th { background:var(--rhine-table-header-bg); }
|
|
30
|
+
.rhine-table td { background:var(--rhine-surface); }
|
|
31
|
+
.rhine-table tbody tr:hover:not([data-selected=true]) > :is(td,th[scope=row]) { background:var(--rhine-table-hover-bg); }
|
|
32
|
+
.rhine-table tr[data-selected=true] td { background:var(--rhine-table-selected-bg); }
|
|
33
|
+
.rhine-table[data-sticky-header=true] th { position:sticky; top:0; z-index:2; }
|
|
34
|
+
.rhine-table :is(th,td)[data-sticky] { position:sticky; z-index:1; box-shadow:0 0 0 1px var(--rhine-line); }
|
|
35
|
+
.rhine-table[data-sticky-header=true] th[data-sticky] { z-index:3; }
|
|
36
|
+
.rhine-table__depth { display:block; white-space:nowrap; color:var(--rhine-muted); font-size:12px; }
|
|
37
|
+
.rhine-table .rhine-check label { min-height:44px; }
|
|
38
|
+
.rhine-pagination .rhine-select { width:auto; }
|
|
39
|
+
.rhine-media-card { min-width:0; border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card); background:var(--rhine-surface); }
|
|
40
|
+
.rhine-media-card[data-selected=true] { border:2px solid var(--rhine-green); }
|
|
41
|
+
.rhine-media-card__open { display:block; width:100%; min-width:0; padding:0; border:0; background:none; color:inherit; font:inherit; text-align:left; cursor:pointer; }
|
|
42
|
+
.rhine-media-card__open:disabled { cursor:default; opacity:.6; }
|
|
43
|
+
.rhine-media-card__preview { position:relative; display:flex; align-items:center; justify-content:center; width:100%; overflow:hidden; background:var(--rhine-media-canvas); color:var(--rhine-media-text); border-radius:var(--rhine-radius-card) var(--rhine-radius-card) 0 0; }
|
|
44
|
+
.rhine-media-card__preview :is(img,video) { width:100%; height:100%; object-fit:contain; }
|
|
45
|
+
.rhine-media-card__kind { position:absolute; top:8px; left:8px; padding:4px 8px; background:var(--rhine-media-overlay); color:var(--rhine-media-text); border:1px solid var(--rhine-media-border); font-size:12px; }
|
|
46
|
+
.rhine-media-card__caption { display:grid; gap:4px; padding:16px; overflow-wrap:anywhere; }
|
|
47
|
+
.rhine-media-card__caption>span { font-size:12px; color:var(--rhine-muted); }
|
|
48
|
+
.rhine-media-card>.rhine-check { padding:0 16px 12px; overflow-wrap:anywhere; }
|
|
49
|
+
.rhine-media-card>.rhine-check label { min-height:44px; }
|
|
50
|
+
.rhine-media-viewer { position:fixed; inset:0; z-index:41; width:100%; height:100dvh; display:flex; flex-direction:column; background:var(--rhine-media-canvas); color:var(--rhine-media-text); color-scheme:dark; overflow:auto; }
|
|
51
|
+
.rhine-media-viewer__header { flex:none; display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:16px; padding:16px; background:var(--rhine-media-overlay); border-bottom:1px solid var(--rhine-media-border); }
|
|
52
|
+
.rhine-media-viewer__header>div { min-width:0; }
|
|
53
|
+
.rhine-media-viewer__header h2 { font-size:18px; line-height:26px; overflow-wrap:anywhere; margin:0; }
|
|
54
|
+
.rhine-media-viewer__header p { color:var(--rhine-media-muted); font-size:12px; margin:4px 0 0; }
|
|
55
|
+
.rhine-media-viewer__actions { display:flex; flex-wrap:wrap; gap:8px; }
|
|
56
|
+
.rhine-media-viewer :is(button,select,a) { min-height:44px; min-width:44px; max-width:100%; padding:8px 12px; border:1px solid var(--rhine-media-border); border-radius:4px; background:var(--rhine-media-overlay); color:var(--rhine-media-text); font:inherit; overflow-wrap:anywhere; }
|
|
57
|
+
.rhine-media-viewer button { cursor:pointer; }
|
|
58
|
+
.rhine-media-viewer button:disabled { color:var(--rhine-media-muted); opacity:.5; cursor:default; }
|
|
59
|
+
.rhine-theme .rhine-media-viewer.rhine-media-viewer :is(button,input,select,textarea,summary,a,[tabindex]):focus-visible { outline:3px solid var(--rhine-media-focus); outline-offset:-3px; }
|
|
60
|
+
.rhine-media-viewer__body { display:grid; grid-template-columns:var(--rhine-media-columns); flex:1; min-height:0; min-width:0; }
|
|
61
|
+
.rhine-media-viewer__canvas { display:flex; align-items:center; justify-content:center; min-height:0; min-width:0; overflow:auto; padding:16px; }
|
|
62
|
+
.rhine-media-viewer__canvas :is(img,video) { display:block; max-width:100%; max-height:100%; object-fit:contain; }
|
|
63
|
+
.rhine-media-viewer__metadata { min-width:0; overflow:auto; padding:24px; border-left:1px solid var(--rhine-media-border); background:var(--rhine-media-overlay); overflow-wrap:anywhere; }
|
|
64
|
+
@media(max-width:760px) {
|
|
65
|
+
.rhine-media-viewer__body { display:flex; flex-direction:column; overflow:auto; }
|
|
66
|
+
.rhine-media-viewer__canvas { flex:1 0 220px; }
|
|
67
|
+
.rhine-media-viewer__canvas :is(img,video) { max-height:50dvh; }
|
|
68
|
+
.rhine-media-viewer__metadata { flex:none; overflow:visible; border-left:0; border-top:1px solid var(--rhine-media-border); }
|
|
69
|
+
.rhine-shell__content { padding:16px; }
|
|
70
|
+
}
|
package/components/index.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import './styles.css';
|
|
2
|
+
export { OrbitBackdrop } from './OrbitBackdrop';
|
|
3
|
+
export type { OrbitBackdropProps } from './OrbitBackdrop';
|
|
4
|
+
export { Background } from './Background';
|
|
5
|
+
export type { BackgroundProps, BackgroundRole, BackgroundDecoration, BackgroundAppearance } from './Background';
|
|
6
|
+
export { AppShell } from './AppShell';
|
|
7
|
+
export type { AppShellProps, ShellPanel } from './AppShell';
|
|
8
|
+
export { MediaCard, MediaViewer } from './Media';
|
|
9
|
+
export type { MediaCardProps, MediaViewerProps } from './Media';
|
|
10
|
+
export { DateField, DateRangePicker, NumberField, RemoteMultiSelect, TreeSelect } from './AdvancedForms';
|
|
11
|
+
export type { DateFieldProps, DateRange, DateRangePickerProps, NumberFieldProps, RemoteMultiSelectProps, TreeNode, TreeSelectProps } from './AdvancedForms';
|
|
2
12
|
export { StatusTimeline, TimelineLegend } from './StatusTimeline';
|
|
3
|
-
export type { TimelineSegment, TimelineStatus } from './StatusTimeline';
|
|
13
|
+
export type { TimelineSegment, TimelineStatus, TimelineDetail, StatusTimelineProps } from './StatusTimeline';
|
|
14
|
+
export { TrendChart, StackedBar } from './Charts';
|
|
15
|
+
export type { ChartPoint, ChartPart, TrendChartProps, StackedBarProps } from './Charts';
|
|
4
16
|
|
|
5
17
|
export { Logo } from './Logo';
|
|
6
18
|
export type { LogoProps } from './Logo';
|
|
@@ -15,7 +27,7 @@ export type { IconName } from './Actions';
|
|
|
15
27
|
export { Divider, Stack, Inline, Grid } from './Layout';
|
|
16
28
|
export type { Spacing } from './Layout';
|
|
17
29
|
export { Metric, KeyValue, DataTable, Pagination } from './Data';
|
|
18
|
-
export type { DataColumn, DataTableProps, TableSort } from './Data';
|
|
30
|
+
export type { DataColumn, DataTableProps, TableSort, PaginationProps } from './Data';
|
|
19
31
|
export { Checkbox, RadioGroup, Switch, Textarea, SearchField, Combobox } from './Forms';
|
|
20
32
|
export type { ComboboxProps } from './Forms';
|
|
21
33
|
export { Dialog, Drawer, ConfirmDialog, Popover, Menu, Tooltip } from './Overlays';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.rhine-orbit {
|
|
2
|
+
position:relative; isolation:isolate; display:flex; flex-direction:column;
|
|
3
|
+
min-width:0; min-height:280px; overflow:hidden;
|
|
4
|
+
border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card);
|
|
5
|
+
background:
|
|
6
|
+
radial-gradient(ellipse at 90% 78%, #15508066 0, transparent 43%),
|
|
7
|
+
radial-gradient(ellipse at 8% 54%, #84603626 0, transparent 35%),
|
|
8
|
+
radial-gradient(ellipse at 62% 18%, #213b653b 0, transparent 48%),
|
|
9
|
+
linear-gradient(155deg, #03070f 12%, #081426 58%, #030a13);
|
|
10
|
+
}
|
|
11
|
+
.rhine-orbit::before, .rhine-orbit::after { content:''; position:absolute; inset:0; pointer-events:none; }
|
|
12
|
+
.rhine-orbit::before {
|
|
13
|
+
background-image:
|
|
14
|
+
radial-gradient(circle at 17px 37px, #d7eaffb3 .7px, transparent 1.4px),
|
|
15
|
+
radial-gradient(circle at 73px 19px, #8bb8e780 .6px, transparent 1.2px),
|
|
16
|
+
radial-gradient(circle at 41px 89px, #d7ba8f80 .7px, transparent 1.3px),
|
|
17
|
+
radial-gradient(circle at 113px 157px, #c4dcff66 .5px, transparent 1.2px);
|
|
18
|
+
background-size:173px 211px, 127px 181px, 251px 239px, 97px 139px;
|
|
19
|
+
opacity:.55;
|
|
20
|
+
}
|
|
21
|
+
.rhine-orbit::after {
|
|
22
|
+
background:
|
|
23
|
+
radial-gradient(ellipse at 77% 66%, #52a4f21a 0, transparent 28%),
|
|
24
|
+
radial-gradient(ellipse at 24% 84%, #b8874220 0, transparent 30%),
|
|
25
|
+
linear-gradient(125deg, transparent 40%, #6295d109 49%, transparent 58%);
|
|
26
|
+
}
|
|
27
|
+
.rhine-orbit-canvas { position:absolute; inset:0; display:block; width:100%; height:100%; pointer-events:none; }
|
|
28
|
+
/* Keep host control tokens intact; only unpainted content inherits the artwork foreground. */
|
|
29
|
+
.rhine-orbit-content {
|
|
30
|
+
position:relative; z-index:1; flex:1; min-width:0;
|
|
31
|
+
display:flex; flex-direction:column; justify-content:space-between; gap:var(--rhine-space-6);
|
|
32
|
+
padding:var(--rhine-space-6); padding-bottom:calc(44px + var(--rhine-space-6) * 2);
|
|
33
|
+
color:#f2f7ff;
|
|
34
|
+
}
|
|
35
|
+
.rhine-orbit-content :is(.rhine-text--muted, .rhine-field__hint) { color:inherit; opacity:.8; }
|
|
36
|
+
.rhine-orbit-content .rhine-logo:not(.rhine-logo--icon) { color:inherit; }
|
|
37
|
+
/* Transparent actions follow their backdrop; painted hover/disabled states retain the host palette. */
|
|
38
|
+
.rhine-orbit-content .rhine-button--quiet:not(:disabled):not(:hover),
|
|
39
|
+
.rhine-orbit-content .rhine-button--quiet[aria-disabled=true]:not(:disabled) { color:inherit; }
|
|
40
|
+
.rhine-orbit .rhine-orbit-content .rhine-button--quiet:focus-visible { outline:none; box-shadow:inset 0 0 0 2px currentColor; }
|
|
41
|
+
.rhine-orbit-controls { position:absolute; right:var(--rhine-space-4); bottom:var(--rhine-space-4); z-index:2; max-width:calc(100% - var(--rhine-space-4) * 2); }
|
|
42
|
+
.rhine-orbit-controls .rhine-button { max-width:100%; }
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
type Point = { x: number; y: number; depth: number; perspective: number };
|
|
2
|
+
type Edge = { a: number; sweep: number; phase: number; waist: number; lift: number; color: number; speed: number };
|
|
3
|
+
type Layer =
|
|
4
|
+
| { kind: 'void'; points: Point[] }
|
|
5
|
+
| { kind: 'line'; p: Point; q: Point; color: number }
|
|
6
|
+
| { kind: 'particle'; p: Point; color: number }
|
|
7
|
+
| { kind: 'spike'; p: Point; q: Point; i: number; pulse: number };
|
|
8
|
+
type CanvasScene = { el: HTMLCanvasElement; ctx: CanvasRenderingContext2D; w: number; h: number };
|
|
9
|
+
export type OrbitState = 'playing' | 'paused' | 'reduced' | 'compact' | 'hidden' | 'offscreen' | 'empty' | 'unavailable';
|
|
10
|
+
export interface OrbitRenderer { setPaused(value: boolean): void; setReducedMotion(value: boolean): void; dispose(): void }
|
|
11
|
+
|
|
12
|
+
/** The seeded artwork is stable across mounts; only elapsed visible time advances it. */
|
|
13
|
+
export function mountOrbit(canvas: HTMLCanvasElement, onState: (state: OrbitState) => void): OrbitRenderer {
|
|
14
|
+
let ctx: CanvasRenderingContext2D | null = null;
|
|
15
|
+
try { ctx = canvas.getContext('2d'); } catch { /* Canvas may be disabled by the host. */ }
|
|
16
|
+
if (!ctx) {
|
|
17
|
+
onState('unavailable');
|
|
18
|
+
return { setPaused() {}, setReducedMotion() {}, dispose() {} };
|
|
19
|
+
}
|
|
20
|
+
const TAU = Math.PI * 2, colors = ["#51b7f6", "#e5b94d", "#2ec7a1", "#bdcbe1"];
|
|
21
|
+
let seed = 1823;
|
|
22
|
+
function rand() {
|
|
23
|
+
seed = seed * 1664525 + 1013904223 >>> 0;
|
|
24
|
+
return seed / 4294967296;
|
|
25
|
+
}
|
|
26
|
+
const nodes = Array.from({ length: 420 }, (_, i) => ({ a: i / 420 * TAU, r: 1.025 + rand() * 0.07, z: (rand() - 0.5) * 0.34, length: 0.035 + rand() * 0.19, color: i % 7 === 0 ? 1 : i % 11 === 0 ? 2 : 3 }));
|
|
27
|
+
const emissions = nodes.map(() => ({ phase: rand(), rate: 0.28 + rand() * 0.3 }));
|
|
28
|
+
const edges = Array.from({ length: 185 }, () => ({ a: rand() * TAU, sweep: 2.1 + rand() * 3.8, phase: rand() * TAU, waist: 0.5 + rand() * 0.32, lift: (rand() - 0.3) * 0.6, color: rand() < 0.32 ? 1 : rand() < 0.1 ? 2 : 0, speed: 0.026 + rand() * 0.024 }));
|
|
29
|
+
function edgePoint(e: Edge, t: number) {
|
|
30
|
+
const a = e.a + t * e.sweep, envelope = Math.sin(Math.PI * t);
|
|
31
|
+
return { a, r: 1.035 - (1.035 - e.waist) * Math.pow(envelope, 0.72), z: e.lift * envelope + 0.06 * Math.sin(e.phase + t * TAU) * envelope };
|
|
32
|
+
}
|
|
33
|
+
const paths = edges.map((e) => Array.from({ length: 81 }, (_, i) => edgePoint(e, i / 80)));
|
|
34
|
+
const canvases = { network: { el: canvas, ctx, w: 0, h: 0 } };
|
|
35
|
+
let time = 0, orbit = 0, projected: Point[] = [], last: number | null = null, frame = 0;
|
|
36
|
+
const yaw = -0.72, tilt = 0.22;
|
|
37
|
+
let paused = false, manualReduced = false, disposed = false, visible = true;
|
|
38
|
+
let previousState: OrbitState | undefined;
|
|
39
|
+
function resize() {
|
|
40
|
+
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
41
|
+
// Layout CSS pixels exclude CSS zoom; visual scaling must not change stroke proportions.
|
|
42
|
+
const c = canvases.network;
|
|
43
|
+
c.w = c.el.clientWidth;
|
|
44
|
+
c.h = c.el.clientHeight;
|
|
45
|
+
c.el.width = Math.round(c.w * dpr);
|
|
46
|
+
c.el.height = Math.round(c.h * dpr);
|
|
47
|
+
c.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
48
|
+
draw();
|
|
49
|
+
}
|
|
50
|
+
function line(ctx2: CanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: string | CanvasGradient, width = 1) {
|
|
51
|
+
ctx2.strokeStyle = color;
|
|
52
|
+
ctx2.lineWidth = width;
|
|
53
|
+
ctx2.beginPath();
|
|
54
|
+
ctx2.moveTo(x1, y1);
|
|
55
|
+
ctx2.lineTo(x2, y2);
|
|
56
|
+
ctx2.stroke();
|
|
57
|
+
}
|
|
58
|
+
function dot(ctx2: CanvasRenderingContext2D, x: number, y: number, r: number, color: string | CanvasGradient) {
|
|
59
|
+
ctx2.fillStyle = color;
|
|
60
|
+
ctx2.beginPath();
|
|
61
|
+
ctx2.arc(x, y, r, 0, TAU);
|
|
62
|
+
ctx2.fill();
|
|
63
|
+
}
|
|
64
|
+
function clear(c: CanvasScene) {
|
|
65
|
+
c.ctx.clearRect(0, 0, c.w, c.h);
|
|
66
|
+
}
|
|
67
|
+
function project(a: number, r = 1, z = 0) {
|
|
68
|
+
const c = canvases.network, scale = Math.min(c.w * 0.66, c.h * 0.39), x = Math.cos(a) * r, y = Math.sin(a) * r;
|
|
69
|
+
const yy = y * Math.cos(tilt) - z * Math.sin(tilt), zz = y * Math.sin(tilt) + z * Math.cos(tilt);
|
|
70
|
+
const xx = x * Math.cos(yaw) + zz * Math.sin(yaw), depth = -x * Math.sin(yaw) + zz * Math.cos(yaw);
|
|
71
|
+
const spin = 0.34, px = xx * Math.cos(spin) - yy * Math.sin(spin), py = xx * Math.sin(spin) + yy * Math.cos(spin), perspective = 3.6 / (3.6 - depth);
|
|
72
|
+
return { x: c.w * 0.62 + px * scale * perspective, y: c.h * 0.57 + py * scale * perspective * 1.08, depth, perspective };
|
|
73
|
+
}
|
|
74
|
+
function network() {
|
|
75
|
+
const c = canvases.network, { ctx: ctx2 } = c;
|
|
76
|
+
clear(c);
|
|
77
|
+
const buckets: Layer[][] = Array.from({ length: 80 }, () => []), offset = orbit;
|
|
78
|
+
function add(item: Layer, depth: number) {
|
|
79
|
+
buckets[Math.max(0, Math.min(79, Math.floor((depth + 1.5) / 3 * 80)))].push(item);
|
|
80
|
+
}
|
|
81
|
+
const horizon = Array.from({ length: 101 }, (_, i) => project(i / 100 * TAU, 0.46, -0.06));
|
|
82
|
+
add({ kind: "void", points: horizon }, -0.04);
|
|
83
|
+
edges.forEach((e, index) => {
|
|
84
|
+
const pts = paths[index].map((p) => project(p.a + offset, p.r, p.z));
|
|
85
|
+
for (let i = 1; i < pts.length; i++) add({ kind: "line", p: pts[i - 1], q: pts[i], color: e.color }, (pts[i - 1].depth + pts[i].depth) / 2 + 7e-3);
|
|
86
|
+
if (index % 3 === 0) {
|
|
87
|
+
const t = (time * e.speed + e.phase / TAU) % 1, p3 = edgePoint(e, t), p = project(p3.a + offset, p3.r, p3.z);
|
|
88
|
+
add({ kind: "particle", p, color: e.color }, p.depth + 0.012);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
projected = nodes.map((n) => project(n.a + offset, n.r, n.z));
|
|
92
|
+
nodes.forEach((n, i) => {
|
|
93
|
+
const emission = emissions[i], pulse = (time * emission.rate + emission.phase) % 1, breath = 1 + 0.18 * Math.sin(time * 1.7 + n.a * 5), p = projected[i], q = project(n.a + offset, n.r + n.length * breath, n.z * 1.1);
|
|
94
|
+
add({ kind: "spike", p, q, i, pulse }, (p.depth + q.depth) / 2);
|
|
95
|
+
});
|
|
96
|
+
const palette = ["104,178,244", "223,187,92", "72,182,179"];
|
|
97
|
+
for (const bucket of buckets) for (const item of bucket) {
|
|
98
|
+
if (item.kind === "void") {
|
|
99
|
+
ctx2.beginPath();
|
|
100
|
+
item.points.forEach((p2, i) => i ? ctx2.lineTo(p2.x, p2.y) : ctx2.moveTo(p2.x, p2.y));
|
|
101
|
+
ctx2.closePath();
|
|
102
|
+
ctx2.fillStyle = "#010205";
|
|
103
|
+
ctx2.fill();
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const p = item.p, near = Math.max(0, Math.min(1, (p.depth + 1) / 2));
|
|
107
|
+
if (item.kind === "line") {
|
|
108
|
+
ctx2.strokeStyle = "rgba(" + palette[item.color] + "," + (0.07 + near * near * 0.57) + ")";
|
|
109
|
+
ctx2.lineWidth = 0.35 + near * 0.65;
|
|
110
|
+
ctx2.beginPath();
|
|
111
|
+
ctx2.moveTo(p.x, p.y);
|
|
112
|
+
ctx2.lineTo(item.q.x, item.q.y);
|
|
113
|
+
ctx2.stroke();
|
|
114
|
+
} else if (item.kind === "spike") {
|
|
115
|
+
const q = item.q, bright = near > 0.48, rgb = bright ? "173,218,255" : "225,161,71", dx = q.x - p.x, dy = q.y - p.y, len = Math.hypot(dx, dy) || 1, ux = dx / len, uy = dy / len;
|
|
116
|
+
line(ctx2, p.x, p.y, q.x, q.y, bright ? "rgba(213,224,241," + (0.16 + near * 0.35) + ")" : "rgba(181,118,53," + (0.12 + near * 0.3) + ")", 0.4 + near * 0.4);
|
|
117
|
+
const t = item.pulse, fade = Math.sin(Math.PI * t), alpha = fade * (0.25 + near * 0.75), x = p.x + dx * t, y = p.y + dy * t, tail = Math.max(0, t - 0.38), tx = p.x + dx * tail, ty = p.y + dy * tail;
|
|
118
|
+
const trail = ctx2.createLinearGradient(tx, ty, x + 1e-3, y + 1e-3);
|
|
119
|
+
trail.addColorStop(0, "rgba(" + rgb + ",0)");
|
|
120
|
+
trail.addColorStop(1, "rgba(" + rgb + "," + alpha + ")");
|
|
121
|
+
line(ctx2, tx, ty, x, y, trail, 0.7 + near * 0.9);
|
|
122
|
+
const size = (1.6 + near * 1.5) * q.perspective;
|
|
123
|
+
ctx2.strokeStyle = "rgba(" + rgb + "," + alpha + ")";
|
|
124
|
+
ctx2.lineWidth = 0.65 + near * 0.5;
|
|
125
|
+
ctx2.beginPath();
|
|
126
|
+
ctx2.moveTo(x - ux * size - uy * size * 0.55, y - uy * size + ux * size * 0.55);
|
|
127
|
+
ctx2.lineTo(x, y);
|
|
128
|
+
ctx2.lineTo(x - ux * size + uy * size * 0.55, y - uy * size - ux * size * 0.55);
|
|
129
|
+
ctx2.stroke();
|
|
130
|
+
if (item.i % 3 === 0) {
|
|
131
|
+
const radius = (4 + near * 4) * q.perspective, glow = ctx2.createRadialGradient(x, y, 0, x, y, radius);
|
|
132
|
+
glow.addColorStop(0, "rgba(" + rgb + "," + alpha * 0.45 + ")");
|
|
133
|
+
glow.addColorStop(1, "rgba(" + rgb + ",0)");
|
|
134
|
+
dot(ctx2, x, y, radius, glow);
|
|
135
|
+
dot(ctx2, x, y, 0.65 + near * 0.45, "rgba(242,247,255," + alpha + ")");
|
|
136
|
+
}
|
|
137
|
+
const flash = Math.pow(Math.max(0, 1 - Math.abs(t - 0.88) / 0.12), 2);
|
|
138
|
+
dot(ctx2, q.x, q.y, (0.55 + flash * 1.1) * q.perspective, "rgba(" + rgb + "," + (0.18 + near * 0.25 + flash * 0.35) + ")");
|
|
139
|
+
} else {
|
|
140
|
+
ctx2.shadowBlur = 5;
|
|
141
|
+
ctx2.shadowColor = colors[item.color];
|
|
142
|
+
dot(ctx2, p.x, p.y, 1.1 * p.perspective, colors[item.color]);
|
|
143
|
+
ctx2.shadowBlur = 0;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (let i = 0; i < 8; i++) {
|
|
147
|
+
const e = edges[i * 19], v = edgePoint(e, 0.4), p = project(v.a + offset, v.r, v.z);
|
|
148
|
+
if (p.depth < -0.1) continue;
|
|
149
|
+
ctx2.shadowColor = "#f25380";
|
|
150
|
+
ctx2.shadowBlur = 10;
|
|
151
|
+
dot(ctx2, p.x, p.y, 2.2 * p.perspective, "#ff658c");
|
|
152
|
+
ctx2.shadowBlur = 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)');
|
|
156
|
+
const compact = window.matchMedia?.('(max-width: 760px)');
|
|
157
|
+
function draw() {
|
|
158
|
+
if (canvases.network.w && canvases.network.h) network();
|
|
159
|
+
}
|
|
160
|
+
function state(): OrbitState {
|
|
161
|
+
if (manualReduced || reduced?.matches || canvas.closest('[data-rhine-motion="reduced"]')) return 'reduced';
|
|
162
|
+
if (compact?.matches) return 'compact';
|
|
163
|
+
if (document.hidden) return 'hidden';
|
|
164
|
+
if (!visible) return 'offscreen';
|
|
165
|
+
if (canvases.network.w <= 0 || canvases.network.h <= 0) return 'empty';
|
|
166
|
+
return paused ? 'paused' : 'playing';
|
|
167
|
+
}
|
|
168
|
+
function animate(now: number) {
|
|
169
|
+
frame = 0;
|
|
170
|
+
if (disposed) return;
|
|
171
|
+
// A frame can observe a media change before its change event is delivered.
|
|
172
|
+
if (state() !== 'playing') { sync(); return; }
|
|
173
|
+
const dt = last === null ? 0 : Math.min((now - last) / 1e3, 0.1);
|
|
174
|
+
last = now;
|
|
175
|
+
time += dt;
|
|
176
|
+
orbit += dt * 0.028;
|
|
177
|
+
draw();
|
|
178
|
+
frame = requestAnimationFrame(animate);
|
|
179
|
+
}
|
|
180
|
+
function sync() {
|
|
181
|
+
if (disposed) return;
|
|
182
|
+
cancelAnimationFrame(frame);
|
|
183
|
+
frame = 0;
|
|
184
|
+
last = null;
|
|
185
|
+
resize();
|
|
186
|
+
const next = state();
|
|
187
|
+
if (next !== previousState) { previousState = next; onState(next); }
|
|
188
|
+
if (next === 'playing') frame = requestAnimationFrame(animate);
|
|
189
|
+
}
|
|
190
|
+
const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(sync);
|
|
191
|
+
observer?.observe(canvas);
|
|
192
|
+
const intersection = typeof IntersectionObserver === 'undefined' ? null : new IntersectionObserver(entries => {
|
|
193
|
+
visible = entries.some(entry => entry.target === canvas && entry.isIntersecting);
|
|
194
|
+
sync();
|
|
195
|
+
});
|
|
196
|
+
intersection?.observe(canvas);
|
|
197
|
+
const motion = new MutationObserver(sync);
|
|
198
|
+
// Observe ancestors only: canvas sizing and React state writes must not retrigger drawing.
|
|
199
|
+
for (let ancestor = canvas.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
200
|
+
motion.observe(ancestor, { attributes: true, attributeFilter: ['data-rhine-motion'] });
|
|
201
|
+
}
|
|
202
|
+
reduced?.addEventListener?.('change', sync);
|
|
203
|
+
compact?.addEventListener?.('change', sync);
|
|
204
|
+
window.addEventListener('resize', sync);
|
|
205
|
+
document.addEventListener("visibilitychange", sync);
|
|
206
|
+
sync();
|
|
207
|
+
return {
|
|
208
|
+
setPaused(value) {
|
|
209
|
+
if (paused === value) return;
|
|
210
|
+
paused = value;
|
|
211
|
+
sync();
|
|
212
|
+
},
|
|
213
|
+
setReducedMotion(value) {
|
|
214
|
+
if (manualReduced === value) return;
|
|
215
|
+
manualReduced = value;
|
|
216
|
+
sync();
|
|
217
|
+
},
|
|
218
|
+
dispose() {
|
|
219
|
+
disposed = true;
|
|
220
|
+
cancelAnimationFrame(frame);
|
|
221
|
+
observer?.disconnect();
|
|
222
|
+
intersection?.disconnect();
|
|
223
|
+
motion.disconnect();
|
|
224
|
+
reduced?.removeEventListener?.('change', sync);
|
|
225
|
+
compact?.removeEventListener?.('change', sync);
|
|
226
|
+
window.removeEventListener('resize', sync);
|
|
227
|
+
document.removeEventListener("visibilitychange", sync);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
package/components/patterns.css
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
.rhine-steps li[data-state=current]>div { background:var(--rhine-selected); color:var(--rhine-green); animation:rhine-pattern-enter var(--rhine-duration-panel) var(--rhine-ease-standard); }
|
|
27
27
|
.rhine-steps li[data-state=error] { border-color:var(--rhine-error); }
|
|
28
28
|
.rhine-steps li[data-state=error]>div { color:var(--rhine-error); background:var(--rhine-error-bg); }
|
|
29
|
-
.rhine-fieldset { min-width:0; margin:0; padding:20px; border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card); }
|
|
29
|
+
.rhine-fieldset { background:var(--rhine-surface-bg); color:var(--rhine-surface-text); min-width:0; margin:0; padding:20px; border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card); }
|
|
30
30
|
.rhine-fieldset legend { padding:0 8px; font-weight:600; }
|
|
31
31
|
.rhine-fieldset>p { margin:0 0 20px; color:var(--rhine-muted); font-size:12px; }
|
|
32
32
|
.rhine-fieldset__body { display:grid; gap:16px; }
|
package/components/styles.css
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
@import './common.css';
|
|
4
4
|
@import './patterns.css';
|
|
5
5
|
@import './timeline.css';
|
|
6
|
+
@import './extensions.css';
|
|
7
|
+
@import './background.css';
|
|
8
|
+
@import './orbit.css';
|
|
9
|
+
@import './charts.css';
|
|
6
10
|
|
|
7
11
|
.rhine-theme { color:var(--rhine-ink); background:var(--rhine-bg); font:var(--rhine-text-body)/var(--rhine-leading-body) var(--rhine-font); font-synthesis:none; }
|
|
8
12
|
.rhine-theme[data-rhine-theme="rhine"] { color-scheme:light; }
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
.rhine-tone-warning { --rhine-tone:var(--rhine-warning); --rhine-tone-bg:var(--rhine-warning-bg); }
|
|
29
33
|
.rhine-tone-error { --rhine-tone:var(--rhine-error); --rhine-tone-bg:var(--rhine-error-bg); }
|
|
30
34
|
.rhine-badge { display:inline-block; padding:2px 8px; border-radius:2px; background:var(--rhine-tone-bg); color:var(--rhine-tone); font:500 12px/20px var(--rhine-font); }
|
|
31
|
-
.rhine-surface { padding:var(--rhine-space-6); border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card); background:var(--rhine-surface); min-width:0; }
|
|
35
|
+
.rhine-surface { padding:var(--rhine-space-6); border:1px solid var(--rhine-line); border-radius:var(--rhine-radius-card); background:var(--rhine-surface-bg); color:var(--rhine-surface-text); min-width:0; }
|
|
32
36
|
.rhine-selection { display:block; border:1px solid var(--rhine-control); background:var(--rhine-surface); border-radius:var(--rhine-radius-card); padding:var(--rhine-space-6); cursor:pointer; min-width:0; transition:background-color var(--rhine-duration-hover) var(--rhine-ease-standard),border-color var(--rhine-duration-hover) var(--rhine-ease-standard),box-shadow var(--rhine-duration-hover) var(--rhine-ease-standard); }
|
|
33
37
|
.rhine-selection:hover:not([data-disabled=true]) { border-color:var(--rhine-green); background:#f4f7ef; }
|
|
34
38
|
.rhine-selection[data-selected=true] { border-color:var(--rhine-green); background:var(--rhine-selected); box-shadow:inset 0 0 0 1px var(--rhine-green); }
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
.rhine-theme[data-rhine-theme="arknights"] {
|
|
3
3
|
/* ---- 色彩:暗舱底 + 信号黄 + 警戒橙 ---- */
|
|
4
4
|
--rhine-bg: #0b0d10;
|
|
5
|
+
--rhine-overlay-bg: #1a1d23;
|
|
6
|
+
--rhine-backdrop-bg: rgba(4, 5, 7, .72);
|
|
7
|
+
--rhine-background-mark: #20242a;
|
|
8
|
+
--rhine-background-texture: linear-gradient(var(--rhine-background-mark) 1px, transparent 1px), linear-gradient(90deg, var(--rhine-background-mark) 1px, transparent 1px);
|
|
9
|
+
--rhine-background-scale: 32px 32px;
|
|
5
10
|
--rhine-surface: #14161b;
|
|
6
11
|
--rhine-ink: #eef0ec;
|
|
7
12
|
--rhine-muted: #878f96;
|
|
8
13
|
--rhine-line: #272b31;
|
|
9
14
|
--rhine-control: #454c54;
|
|
10
15
|
--rhine-selected: #1c2026;
|
|
16
|
+
--rhine-table-hover-bg: color-mix(in srgb, #ffd400 6%, var(--rhine-surface));
|
|
11
17
|
--rhine-green: #ffd400;
|
|
12
18
|
--rhine-signal: #ff6a1a;
|
|
13
19
|
--rhine-warning: #ffb020;
|
|
@@ -77,7 +83,7 @@
|
|
|
77
83
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-surface,
|
|
78
84
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-empty,
|
|
79
85
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-fieldset {
|
|
80
|
-
background: var(--
|
|
86
|
+
background: var(--rhine-surface-bg);
|
|
81
87
|
clip-path: polygon(0 0, calc(100% - var(--ak-cut)) 0, 100% var(--ak-cut), 100% 100%, 0 100%);
|
|
82
88
|
}
|
|
83
89
|
/* 左下角小角标点缀 */
|
|
@@ -173,7 +179,7 @@
|
|
|
173
179
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-combobox__list,
|
|
174
180
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-popover,
|
|
175
181
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-menu {
|
|
176
|
-
background: var(--
|
|
182
|
+
background: var(--rhine-overlay-bg);
|
|
177
183
|
border-color: var(--rhine-control);
|
|
178
184
|
border-radius: 0;
|
|
179
185
|
box-shadow: 0 12px 32px rgba(0, 0, 0, .55);
|
|
@@ -223,7 +229,6 @@
|
|
|
223
229
|
letter-spacing: .08em;
|
|
224
230
|
border-bottom: 2px solid var(--ak-accent);
|
|
225
231
|
}
|
|
226
|
-
.rhine-theme[data-rhine-theme="arknights"] .rhine-table tbody tr:hover { background: rgba(255, 212, 0, .06); }
|
|
227
232
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-metric { font-variant-numeric: tabular-nums; }
|
|
228
233
|
|
|
229
234
|
/* ================= 反馈 ================= */
|
|
@@ -240,9 +245,9 @@
|
|
|
240
245
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-disclosure summary>span { color: var(--ak-accent); }
|
|
241
246
|
|
|
242
247
|
/* ================= 浮层 / 对话框 ================= */
|
|
243
|
-
.rhine-theme[data-rhine-theme="arknights"] .rhine-overlay { background:
|
|
248
|
+
.rhine-theme[data-rhine-theme="arknights"] .rhine-overlay { background: var(--rhine-backdrop-bg); }
|
|
244
249
|
.rhine-theme[data-rhine-theme="arknights"] .rhine-dialog {
|
|
245
|
-
background: var(--
|
|
250
|
+
background: var(--rhine-overlay-bg);
|
|
246
251
|
border-color: var(--rhine-control);
|
|
247
252
|
border-radius: 0;
|
|
248
253
|
box-shadow: 0 24px 64px rgba(0, 0, 0, .6);
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
.rhine-theme[data-rhine-theme="neo-brutalism"] {
|
|
3
3
|
color-scheme: light;
|
|
4
4
|
--rhine-bg: #eaf0f4;
|
|
5
|
+
--rhine-backdrop-bg: #20232360;
|
|
6
|
+
--rhine-background-mark: #b7c2cc;
|
|
7
|
+
--rhine-background-texture: radial-gradient(circle, var(--rhine-background-mark) .8px, transparent .9px);
|
|
8
|
+
--rhine-background-scale: 14px 14px;
|
|
5
9
|
--rhine-surface: #fffdf5;
|
|
6
10
|
--rhine-ink: #202323;
|
|
7
11
|
--rhine-muted: #59616a;
|
|
8
12
|
--rhine-line: #b9c1c7;
|
|
9
13
|
--rhine-control: #202323;
|
|
10
14
|
--rhine-selected: #fce4cc;
|
|
15
|
+
--rhine-table-header-bg: #edf0e9;
|
|
16
|
+
--rhine-table-cell-padding: 16px 12px;
|
|
11
17
|
--rhine-green: #286043;
|
|
12
18
|
--rhine-signal: #ff8b3d;
|
|
13
19
|
--rhine-warning: #854216;
|
|
@@ -24,7 +30,7 @@
|
|
|
24
30
|
--rhine-tag-green: #dcebd7;
|
|
25
31
|
--rhine-tag-orange: #fce0c4;
|
|
26
32
|
--rhine-tag-violet: #e3e0f7;
|
|
27
|
-
background:
|
|
33
|
+
background: var(--rhine-background-texture) 0 0 / var(--rhine-background-scale), var(--rhine-bg);
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
.rhine-theme[data-rhine-theme="neo-brutalism"] :is(.rhine-surface, .rhine-selection, .rhine-empty, .rhine-fieldset) {
|
|
@@ -67,13 +73,13 @@
|
|
|
67
73
|
.rhine-theme[data-rhine-theme="neo-brutalism"] :is(.rhine-dialog, .rhine-popover, .rhine-menu, .rhine-combobox__list) { border: 2px solid var(--rhine-ink); border-radius: 18px; box-shadow: var(--rhine-hard-shadow); }
|
|
68
74
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-dialog { border-radius: 24px; box-shadow: 8px 8px 0 var(--rhine-ink); }
|
|
69
75
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-drawer { border-radius: 24px 0 0 24px; box-shadow: -5px 0 0 var(--rhine-ink); }
|
|
70
|
-
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-overlay { background:
|
|
76
|
+
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-overlay { background: var(--rhine-backdrop-bg); backdrop-filter: none; }
|
|
71
77
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-menu__item { border-radius: 10px; }
|
|
72
78
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-menu__item[data-highlighted] { box-shadow: inset 0 0 0 2px var(--rhine-ink); }
|
|
73
79
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-tooltip { border-radius: 8px; }
|
|
74
80
|
.rhine-theme[data-rhine-theme="neo-brutalism"] :is(.rhine-notice, .rhine-toast, .rhine-error-summary) { border: 2px solid var(--rhine-tone, var(--rhine-error)); border-radius: 14px; }
|
|
75
|
-
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-table th { color: var(--rhine-ink); background:
|
|
76
|
-
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-table :is(th, td) { padding:
|
|
81
|
+
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-table th { color: var(--rhine-ink); background: var(--rhine-table-header-bg); font-weight: 700; border-bottom: 2px solid var(--rhine-ink); }
|
|
82
|
+
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-table :is(th, td) { padding: var(--rhine-table-cell-padding); }
|
|
77
83
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-table td { font-size: 14px; }
|
|
78
84
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-progress__track { height: 10px; border: 1.5px solid var(--rhine-ink); border-radius: 6px; background: #e7ebee; }
|
|
79
85
|
.rhine-theme[data-rhine-theme="neo-brutalism"] .rhine-progress__track>span { background: var(--rhine-signal); }
|
package/components/timeline.css
CHANGED
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
.rhine-timeline--compact { position:relative; gap:0; }
|
|
19
19
|
.rhine-timeline--compact .rhine-timeline__track { height:20px; }
|
|
20
20
|
.rhine-timeline--compact .rhine-timeline__track input { top:-12px; bottom:auto; }
|
|
21
|
-
.rhine-timeline
|
|
22
|
-
.rhine-timeline
|
|
21
|
+
.rhine-timeline-popover { z-index:50; width:min(360px,calc(100vw - 24px)); max-height:var(--radix-popover-content-available-height); overflow:auto; padding:16px; border:1px solid var(--rhine-control); border-radius:var(--rhine-radius-card); background:var(--rhine-overlay-bg); color:var(--rhine-overlay-text); box-shadow:0 4px 12px #242b2814; overflow-wrap:anywhere; }
|
|
22
|
+
.rhine-timeline-popover .rhine-key-value { margin-block:16px; }
|
|
23
23
|
.rhine-timeline--compact:not(:hover):not(:focus-within) .rhine-timeline__bars [data-selected=true] { height:20px; outline:none; }
|
package/components/tokens.css
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
/* Canonical tokens for the component library and design previews. */
|
|
2
2
|
:root, :where(.rhine-theme[data-rhine-theme]) {
|
|
3
3
|
--rhine-bg: #f2f1e9;
|
|
4
|
+
--rhine-backdrop-bg: #242b2870;
|
|
5
|
+
--rhine-content-texture: none;
|
|
6
|
+
--rhine-sidebar-texture: none;
|
|
7
|
+
--rhine-surface-texture: none;
|
|
8
|
+
--rhine-overlay-texture: none;
|
|
9
|
+
--rhine-media-texture: none;
|
|
10
|
+
--rhine-background-texture: none;
|
|
11
|
+
--rhine-background-scale: 24px 24px;
|
|
12
|
+
--rhine-background-mark: #c5ccc1;
|
|
13
|
+
--rhine-table-cell-padding: 12px 16px;
|
|
14
|
+
--rhine-tree-indent: 20px;
|
|
15
|
+
--rhine-chart-series-3: #477aa8;
|
|
16
|
+
--rhine-chart-series-4: #8763a7;
|
|
17
|
+
--rhine-media-canvas: #101214;
|
|
18
|
+
--rhine-media-overlay: #202428;
|
|
19
|
+
--rhine-media-text: #f6f7f8;
|
|
20
|
+
--rhine-media-muted: #bcc3ca;
|
|
21
|
+
--rhine-media-border: #68727c;
|
|
22
|
+
--rhine-media-focus: #9bceff;
|
|
4
23
|
--rhine-surface: #fcfcf8;
|
|
5
24
|
--rhine-ink: #242b28;
|
|
6
25
|
--rhine-muted: #59645d;
|
|
@@ -61,3 +80,27 @@
|
|
|
61
80
|
--rhine-ease-exit: cubic-bezier(.4, 0, 1, 1);
|
|
62
81
|
--rhine-motion-distance: 3px;
|
|
63
82
|
}
|
|
83
|
+
|
|
84
|
+
/* Resolve palette aliases at CSS-only roots as well as ThemeProvider roots. */
|
|
85
|
+
:root, :where(.rhine-theme) {
|
|
86
|
+
--rhine-canvas-bg: var(--rhine-bg);
|
|
87
|
+
--rhine-content-bg: var(--rhine-bg);
|
|
88
|
+
--rhine-sidebar-bg: var(--rhine-surface);
|
|
89
|
+
--rhine-surface-bg: var(--rhine-surface);
|
|
90
|
+
--rhine-overlay-bg: var(--rhine-surface);
|
|
91
|
+
--rhine-media-bg: var(--rhine-media-canvas);
|
|
92
|
+
--rhine-canvas-text: var(--rhine-ink);
|
|
93
|
+
--rhine-content-text: var(--rhine-ink);
|
|
94
|
+
--rhine-sidebar-text: var(--rhine-ink);
|
|
95
|
+
--rhine-surface-text: var(--rhine-ink);
|
|
96
|
+
--rhine-overlay-text: var(--rhine-ink);
|
|
97
|
+
--rhine-canvas-texture: var(--rhine-background-texture);
|
|
98
|
+
--rhine-table-header-bg: var(--rhine-surface);
|
|
99
|
+
--rhine-table-hover-bg: var(--rhine-selected);
|
|
100
|
+
--rhine-table-selected-bg: var(--rhine-selected);
|
|
101
|
+
--rhine-field-group-bg: var(--rhine-surface);
|
|
102
|
+
--rhine-chart-series-1: var(--rhine-green);
|
|
103
|
+
--rhine-chart-series-2: var(--rhine-signal);
|
|
104
|
+
--rhine-chart-grid: var(--rhine-line);
|
|
105
|
+
--rhine-chart-missing: var(--rhine-muted);
|
|
106
|
+
}
|