@cosxai/ui 0.25.0 → 1.0.0-alpha.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 +577 -0
- package/NOTICE +11 -0
- package/README.md +52 -0
- package/package.json +33 -7
- package/src/fonts.css +20 -0
- package/src/index.ts +8 -25
- package/src/lib/cn.ts +23 -6
- package/src/styles.css +17 -0
- package/src/theme.css +132 -0
- package/src/tokens/colors.css +112 -0
- package/src/tokens/compat.css +36 -0
- package/src/tokens/elevation.css +14 -0
- package/src/tokens/motion.css +42 -0
- package/src/tokens/spacing.css +55 -0
- package/src/tokens/typography-cjk.css +42 -0
- package/src/tokens/typography.css +81 -0
- package/src/actionbar/ActionBar.tsx +0 -837
- package/src/actionbar/ActionBarButton.tsx +0 -111
- package/src/actionbar/ActionBarMenuGroup.tsx +0 -116
- package/src/actionbar/ActionBarModeHandle.tsx +0 -171
- package/src/actionbar/ActionBarProvider.tsx +0 -91
- package/src/actionbar/actionbar-context.ts +0 -45
- package/src/actionbar/index.ts +0 -28
- package/src/actionbar/types.ts +0 -147
- package/src/actionbar/useActionBarItems.ts +0 -60
- package/src/actionbar/useActionBarMode.ts +0 -144
- package/src/actionbar/useActionBarPanel.ts +0 -56
- package/src/actionbar/useActionBarStatusDot.ts +0 -49
- package/src/actionbar/useActionBarToast.ts +0 -33
- package/src/ambient/AmbientBackdrop.tsx +0 -74
- package/src/ambient/CommandInput.tsx +0 -107
- package/src/ambient/SuperbarStrip.tsx +0 -36
- package/src/ambient/index.ts +0 -6
- package/src/bento/BentoCell.tsx +0 -66
- package/src/bento/BentoGrid.tsx +0 -42
- package/src/bento/index.ts +0 -2
- package/src/command/CommandPalette.tsx +0 -329
- package/src/command/CommandProvider.tsx +0 -57
- package/src/command/command-context.ts +0 -12
- package/src/command/index.ts +0 -6
- package/src/command/rank.ts +0 -50
- package/src/command/types.ts +0 -37
- package/src/command/useCommandSource.ts +0 -37
- package/src/dialogs/DialogsProvider.tsx +0 -216
- package/src/dialogs/Modal.tsx +0 -260
- package/src/dialogs/Toast.tsx +0 -85
- package/src/dialogs/dialogs-context.ts +0 -6
- package/src/dialogs/index.ts +0 -10
- package/src/dialogs/types.ts +0 -37
- package/src/dialogs/useDialogs.ts +0 -8
- package/src/editorial/EditorialSpotlight.tsx +0 -63
- package/src/editorial/Folio.tsx +0 -52
- package/src/editorial/PlateMarker.tsx +0 -33
- package/src/editorial/RomanSection.tsx +0 -65
- package/src/editorial/RunningMarginalia.tsx +0 -65
- package/src/editorial/index.ts +0 -10
- package/src/hooks/index.ts +0 -5
- package/src/hooks/useKeyboardHotkey.ts +0 -93
- package/src/hooks/useReducedMotion.ts +0 -20
- package/src/hooks/useViewport.ts +0 -61
- package/src/layout/Breadcrumb.tsx +0 -74
- package/src/layout/LeftNavRail.tsx +0 -139
- package/src/layout/MobileTabBar.tsx +0 -101
- package/src/layout/NavItem.tsx +0 -128
- package/src/layout/NavSearchTrigger.tsx +0 -88
- package/src/layout/NavSection.tsx +0 -40
- package/src/layout/RightSidebarPanel.tsx +0 -111
- package/src/layout/Shell.tsx +0 -91
- package/src/layout/SidePanel.tsx +0 -316
- package/src/layout/StickyBanner.tsx +0 -83
- package/src/layout/Topbar.tsx +0 -68
- package/src/layout/index.ts +0 -24
- package/src/layout/useNavRailState.ts +0 -69
- package/src/lib/time-utils.ts +0 -44
- package/src/neobrutalism/Marquee.tsx +0 -81
- package/src/neobrutalism/Sticker.tsx +0 -71
- package/src/neobrutalism/index.ts +0 -4
- package/src/primitives/Avatar.tsx +0 -53
- package/src/primitives/Button.tsx +0 -67
- package/src/primitives/Card.tsx +0 -41
- package/src/primitives/Checkbox.tsx +0 -87
- package/src/primitives/Chip.tsx +0 -191
- package/src/primitives/Combobox.tsx +0 -507
- package/src/primitives/CopyField.tsx +0 -139
- package/src/primitives/CountBadge.tsx +0 -50
- package/src/primitives/Input.tsx +0 -204
- package/src/primitives/Kbd.tsx +0 -45
- package/src/primitives/MentionCombobox.tsx +0 -612
- package/src/primitives/MultiCombobox.tsx +0 -327
- package/src/primitives/PageHeader.tsx +0 -77
- package/src/primitives/Radio.tsx +0 -131
- package/src/primitives/SegmentedControl.tsx +0 -135
- package/src/primitives/Select.tsx +0 -779
- package/src/primitives/SignaturePad.tsx +0 -461
- package/src/primitives/Tag.tsx +0 -56
- package/src/primitives/Textarea.tsx +0 -62
- package/src/primitives/ToggleSwitch.tsx +0 -79
- package/src/primitives/Tooltip.tsx +0 -213
- package/src/primitives/index.ts +0 -53
- package/src/pwa/InstallPromptBanner.tsx +0 -132
- package/src/pwa/index.ts +0 -4
- package/src/pwa/manifest.template.json +0 -20
- package/src/pwa/registerSW.ts +0 -55
- package/src/riso/Halftone.tsx +0 -85
- package/src/riso/Misregister.tsx +0 -63
- package/src/riso/RisoStamp.tsx +0 -76
- package/src/riso/index.ts +0 -3
- package/src/sketch/HandUnderline.tsx +0 -53
- package/src/sketch/RoughArrow.tsx +0 -91
- package/src/sketch/RoughBox.tsx +0 -73
- package/src/sketch/StickyNote.tsx +0 -56
- package/src/sketch/index.ts +0 -4
- package/src/styles/base.css +0 -186
- package/src/styles/chrome-ambient.css +0 -235
- package/src/styles/chrome-bento.css +0 -192
- package/src/styles/chrome-editorial.css +0 -168
- package/src/styles/chrome-neobrutalism.css +0 -326
- package/src/styles/chrome-riso.css +0 -339
- package/src/styles/chrome-sketch.css +0 -362
- package/src/styles/chrome-swiss.css +0 -265
- package/src/styles/chrome-terminal.css +0 -272
- package/src/styles/fonts.css +0 -1034
- package/src/styles/index.css +0 -343
- package/src/styles/tokens.css +0 -941
- package/src/terminal/AsciiBox.tsx +0 -65
- package/src/terminal/BrailleSpinner.tsx +0 -46
- package/src/terminal/index.ts +0 -4
- package/src/theme/ThemeProvider.tsx +0 -99
- package/src/theme/index.ts +0 -6
- package/src/theme/inline-script.ts +0 -40
- package/src/theme/theme-context.ts +0 -7
- package/src/theme/types.ts +0 -39
- package/src/theme/useTheme.ts +0 -8
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { useEffect, type ReactNode, type CSSProperties } from "react";
|
|
2
|
-
|
|
3
|
-
// Fixed-left vertical nav rail. Three slots — brand (top), children
|
|
4
|
-
// (the nav body, scrollable), footer (avatar / collapse toggle).
|
|
5
|
-
//
|
|
6
|
-
// Owns the CSS var --ck-leftnav-width. Page content reads this var
|
|
7
|
-
// to inset itself, so layouts react to the rail width changing
|
|
8
|
-
// without prop-drilling.
|
|
9
|
-
//
|
|
10
|
-
// Stateless visually: collapsed is a boolean prop. State management
|
|
11
|
-
// lives in useNavRailState(), which the parent owns; this keeps the
|
|
12
|
-
// component pure and testable.
|
|
13
|
-
|
|
14
|
-
export interface LeftNavRailProps {
|
|
15
|
-
brand?: ReactNode;
|
|
16
|
-
children: ReactNode;
|
|
17
|
-
footer?: ReactNode;
|
|
18
|
-
/**
|
|
19
|
-
* footerTop — a block pinned BETWEEN the scrolling nav area and the
|
|
20
|
-
* footer rule: always visible, above the divider, immune to a long
|
|
21
|
-
* menu (the nav list scrolls above it). The agent drawer's trigger
|
|
22
|
-
* is the motivating case.
|
|
23
|
-
*/
|
|
24
|
-
footerTop?: ReactNode;
|
|
25
|
-
collapsed?: boolean;
|
|
26
|
-
// Expanded / collapsed widths in px. Defaults 256 / 56.
|
|
27
|
-
widthExpanded?: number;
|
|
28
|
-
widthCollapsed?: number;
|
|
29
|
-
className?: string;
|
|
30
|
-
// Hide entirely (e.g. on phone). When true, sets --ck-leftnav-width: 0.
|
|
31
|
-
hidden?: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function LeftNavRail({
|
|
35
|
-
brand,
|
|
36
|
-
children,
|
|
37
|
-
footer,
|
|
38
|
-
footerTop,
|
|
39
|
-
collapsed = false,
|
|
40
|
-
widthExpanded = 256,
|
|
41
|
-
widthCollapsed = 56,
|
|
42
|
-
className,
|
|
43
|
-
hidden = false,
|
|
44
|
-
}: LeftNavRailProps) {
|
|
45
|
-
const width = hidden ? 0 : collapsed ? widthCollapsed : widthExpanded;
|
|
46
|
-
|
|
47
|
-
// Stamp --ck-leftnav-width on documentElement so page-level
|
|
48
|
-
// layouts (Shell's marginLeft, fixed AgentRail, ActionBar's right
|
|
49
|
-
// inset) can read it without a context.
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
document.documentElement.style.setProperty("--ck-leftnav-width", `${width}px`);
|
|
52
|
-
return () => {
|
|
53
|
-
// On unmount, clear to 0 so consumers without a rail don't inherit
|
|
54
|
-
// a stale inset.
|
|
55
|
-
document.documentElement.style.setProperty("--ck-leftnav-width", "0px");
|
|
56
|
-
};
|
|
57
|
-
}, [width]);
|
|
58
|
-
|
|
59
|
-
if (hidden) return null;
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<aside
|
|
63
|
-
data-ck-leftnav
|
|
64
|
-
className={className}
|
|
65
|
-
style={
|
|
66
|
-
{
|
|
67
|
-
position: "fixed",
|
|
68
|
-
left: 0,
|
|
69
|
-
top: 0,
|
|
70
|
-
bottom: 0,
|
|
71
|
-
width,
|
|
72
|
-
// Default to --ck-bg-surface so the rail blends seamlessly
|
|
73
|
-
// with the topbar + cards. Consumers wanting a tinted rail
|
|
74
|
-
// override via --ck-bg-sidebar in their own stylesheet or
|
|
75
|
-
// pass a className that sets background.
|
|
76
|
-
background: "var(--ck-bg-surface)",
|
|
77
|
-
borderRight: "1px solid var(--ck-border-subtle)",
|
|
78
|
-
display: "flex",
|
|
79
|
-
flexDirection: "column",
|
|
80
|
-
fontFamily: "var(--ck-font-sans)",
|
|
81
|
-
color: "var(--ck-text-primary)",
|
|
82
|
-
transition: "width var(--ck-dur-fast) var(--ck-ease), background-color 200ms var(--ck-ease)",
|
|
83
|
-
zIndex: 30,
|
|
84
|
-
} as CSSProperties
|
|
85
|
-
}
|
|
86
|
-
>
|
|
87
|
-
{brand && (
|
|
88
|
-
<div
|
|
89
|
-
style={{
|
|
90
|
-
// Match the topbar's height (Topbar stamps
|
|
91
|
-
// --ck-breadcrumb-height; default 64 px). Logo +
|
|
92
|
-
// crumbs sit on the same horizontal axis and the
|
|
93
|
-
// brand-area bottom rule aligns with the topbar's
|
|
94
|
-
// bottom rule — no per-app tuning.
|
|
95
|
-
height: "var(--ck-breadcrumb-height, 64px)",
|
|
96
|
-
padding: collapsed ? "0 4px" : "0 12px",
|
|
97
|
-
display: "flex",
|
|
98
|
-
alignItems: "center",
|
|
99
|
-
// Logo is brand mark, not nav item — centre it in both
|
|
100
|
-
// collapsed and expanded states so the visual anchor stays
|
|
101
|
-
// put across the width transition. Matches the centred
|
|
102
|
-
// favicon position when the rail is collapsed.
|
|
103
|
-
justifyContent: "center",
|
|
104
|
-
borderBottom: "1px solid var(--ck-border-subtle)",
|
|
105
|
-
transition: "padding var(--ck-dur-fast) var(--ck-ease)",
|
|
106
|
-
flexShrink: 0,
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
{brand}
|
|
110
|
-
</div>
|
|
111
|
-
)}
|
|
112
|
-
<div
|
|
113
|
-
style={{
|
|
114
|
-
flex: 1,
|
|
115
|
-
minHeight: 0,
|
|
116
|
-
overflowY: "auto",
|
|
117
|
-
padding: collapsed ? "8px 4px" : "12px 8px",
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
{children}
|
|
121
|
-
</div>
|
|
122
|
-
{footerTop && (
|
|
123
|
-
<div style={{ padding: collapsed ? "4px 4px 8px" : "4px 8px 12px", flexShrink: 0 }}>
|
|
124
|
-
{footerTop}
|
|
125
|
-
</div>
|
|
126
|
-
)}
|
|
127
|
-
{footer && (
|
|
128
|
-
<div
|
|
129
|
-
style={{
|
|
130
|
-
padding: collapsed ? "8px 4px" : "12px 8px",
|
|
131
|
-
borderTop: "1px solid var(--ck-border-subtle)",
|
|
132
|
-
}}
|
|
133
|
-
>
|
|
134
|
-
{footer}
|
|
135
|
-
</div>
|
|
136
|
-
)}
|
|
137
|
-
</aside>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { useEffect, type ReactNode, type CSSProperties } from "react";
|
|
2
|
-
|
|
3
|
-
// Fixed-bottom tab bar for phones. Sits above the home-indicator
|
|
4
|
-
// safe area on iOS, exposes --ck-tabbar-height so the GlobalActionBar
|
|
5
|
-
// and any sticky bottom UI can lift to clear it.
|
|
6
|
-
//
|
|
7
|
-
// Tab list is fully configurable — caller supplies items with an
|
|
8
|
-
// active match function so the bar can highlight the right one for
|
|
9
|
-
// the current pathname. No router coupling.
|
|
10
|
-
|
|
11
|
-
export interface MobileTab {
|
|
12
|
-
key: string;
|
|
13
|
-
label: string;
|
|
14
|
-
icon: ReactNode;
|
|
15
|
-
// Called when the tab is tapped. Caller handles navigation.
|
|
16
|
-
onSelect: () => void;
|
|
17
|
-
// Whether this tab represents the current route. Caller derives
|
|
18
|
-
// from their router (e.g. `pathname.startsWith("/shares")`).
|
|
19
|
-
active: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface MobileTabBarProps {
|
|
23
|
-
tabs: MobileTab[];
|
|
24
|
-
// Height of the bar (content area; safe-area inset added on top).
|
|
25
|
-
// Default 56 px.
|
|
26
|
-
height?: number;
|
|
27
|
-
className?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function MobileTabBar({
|
|
31
|
-
tabs,
|
|
32
|
-
height = 56,
|
|
33
|
-
className,
|
|
34
|
-
}: MobileTabBarProps) {
|
|
35
|
-
// Stamp --ck-tabbar-height. Includes safe-area inset so consumers
|
|
36
|
-
// (e.g. floating action bar) can lift cleanly above the home
|
|
37
|
-
// indicator. iOS env() works in calc() inside :root vars.
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
document.documentElement.style.setProperty(
|
|
40
|
-
"--ck-tabbar-height",
|
|
41
|
-
`calc(${height}px + env(safe-area-inset-bottom, 0px))`,
|
|
42
|
-
);
|
|
43
|
-
return () => {
|
|
44
|
-
document.documentElement.style.setProperty("--ck-tabbar-height", "0px");
|
|
45
|
-
};
|
|
46
|
-
}, [height]);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<nav
|
|
50
|
-
data-ck-tabbar
|
|
51
|
-
aria-label="Primary"
|
|
52
|
-
className={className}
|
|
53
|
-
style={
|
|
54
|
-
{
|
|
55
|
-
position: "fixed",
|
|
56
|
-
left: 0,
|
|
57
|
-
right: 0,
|
|
58
|
-
bottom: 0,
|
|
59
|
-
height: "var(--ck-tabbar-height)",
|
|
60
|
-
paddingBottom: "env(safe-area-inset-bottom, 0px)",
|
|
61
|
-
background: "var(--ck-bg-surface)",
|
|
62
|
-
borderTop: "1px solid var(--ck-border-subtle)",
|
|
63
|
-
display: "flex",
|
|
64
|
-
justifyContent: "space-around",
|
|
65
|
-
alignItems: "stretch",
|
|
66
|
-
zIndex: 50,
|
|
67
|
-
fontFamily: "var(--ck-font-sans)",
|
|
68
|
-
} as CSSProperties
|
|
69
|
-
}
|
|
70
|
-
>
|
|
71
|
-
{tabs.map((t) => (
|
|
72
|
-
<button
|
|
73
|
-
key={t.key}
|
|
74
|
-
type="button"
|
|
75
|
-
onClick={t.onSelect}
|
|
76
|
-
aria-current={t.active ? "page" : undefined}
|
|
77
|
-
style={{
|
|
78
|
-
flex: 1,
|
|
79
|
-
display: "flex",
|
|
80
|
-
flexDirection: "column",
|
|
81
|
-
alignItems: "center",
|
|
82
|
-
justifyContent: "center",
|
|
83
|
-
gap: 2,
|
|
84
|
-
padding: "6px 8px",
|
|
85
|
-
border: "none",
|
|
86
|
-
background: "transparent",
|
|
87
|
-
color: t.active ? "var(--ck-accent)" : "var(--ck-text-tertiary)",
|
|
88
|
-
cursor: "pointer",
|
|
89
|
-
font: "500 11px/1 var(--ck-font-sans)",
|
|
90
|
-
transition: "color var(--ck-dur-fast) var(--ck-ease)",
|
|
91
|
-
}}
|
|
92
|
-
>
|
|
93
|
-
<span style={{ fontSize: 18, lineHeight: 1, display: "inline-flex" }}>
|
|
94
|
-
{t.icon}
|
|
95
|
-
</span>
|
|
96
|
-
<span>{t.label}</span>
|
|
97
|
-
</button>
|
|
98
|
-
))}
|
|
99
|
-
</nav>
|
|
100
|
-
);
|
|
101
|
-
}
|
package/src/layout/NavItem.tsx
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, CSSProperties } from "react";
|
|
2
|
-
import { CountBadge } from "../primitives/CountBadge";
|
|
3
|
-
|
|
4
|
-
// Single nav row inside <LeftNavRail>. Router-agnostic — pass your
|
|
5
|
-
// own router's link primitive via the `as` prop, or fall back to a
|
|
6
|
-
// plain anchor. Collapsed mode renders icon-only with the label as
|
|
7
|
-
// a tooltip.
|
|
8
|
-
//
|
|
9
|
-
// Use with NavLink-style render-prop routers by wrapping NavItem
|
|
10
|
-
// with your router's link and forwarding `active`:
|
|
11
|
-
//
|
|
12
|
-
// <NavLink to="/x">
|
|
13
|
-
// {({ isActive }) =>
|
|
14
|
-
// <NavItem active={isActive} icon={<X/>} label="X" />
|
|
15
|
-
// }
|
|
16
|
-
// </NavLink>
|
|
17
|
-
|
|
18
|
-
export interface NavItemProps {
|
|
19
|
-
// Visible label (also used as tooltip when collapsed).
|
|
20
|
-
label: string;
|
|
21
|
-
icon: ReactNode;
|
|
22
|
-
active?: boolean;
|
|
23
|
-
// Optional notification count badge — renders nothing for 0.
|
|
24
|
-
badge?: number;
|
|
25
|
-
collapsed?: boolean;
|
|
26
|
-
onClick?: () => void;
|
|
27
|
-
// Render as an anchor with this href. When omitted, renders as
|
|
28
|
-
// a button (use onClick).
|
|
29
|
-
href?: string;
|
|
30
|
-
// Optional custom render — escape hatch for router-link wrappers
|
|
31
|
-
// that need to spread their own props on the element. Receives
|
|
32
|
-
// the rendered children + the inline style.
|
|
33
|
-
className?: string;
|
|
34
|
-
style?: CSSProperties;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function NavItem({
|
|
38
|
-
label,
|
|
39
|
-
icon,
|
|
40
|
-
active,
|
|
41
|
-
badge,
|
|
42
|
-
collapsed,
|
|
43
|
-
onClick,
|
|
44
|
-
href,
|
|
45
|
-
className,
|
|
46
|
-
style,
|
|
47
|
-
}: NavItemProps) {
|
|
48
|
-
const showBadge = badge !== undefined && badge > 0;
|
|
49
|
-
const baseStyle: CSSProperties = {
|
|
50
|
-
position: "relative",
|
|
51
|
-
display: "flex",
|
|
52
|
-
alignItems: "center",
|
|
53
|
-
borderRadius: "var(--ck-radius-md)",
|
|
54
|
-
transition: "background var(--ck-dur-fast) var(--ck-ease), color var(--ck-dur-fast) var(--ck-ease)",
|
|
55
|
-
background: active ? "var(--ck-accent-muted)" : "transparent",
|
|
56
|
-
color: active ? "var(--ck-accent)" : "var(--ck-text-secondary)",
|
|
57
|
-
font: "400 13px/1 var(--ck-font-sans)",
|
|
58
|
-
fontWeight: active ? 500 : 400,
|
|
59
|
-
cursor: "pointer",
|
|
60
|
-
textDecoration: "none",
|
|
61
|
-
border: "none",
|
|
62
|
-
...(collapsed
|
|
63
|
-
? {
|
|
64
|
-
justifyContent: "center",
|
|
65
|
-
width: 40,
|
|
66
|
-
height: 40,
|
|
67
|
-
}
|
|
68
|
-
: {
|
|
69
|
-
justifyContent: "space-between",
|
|
70
|
-
padding: "8px 12px",
|
|
71
|
-
}),
|
|
72
|
-
...style,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const content = collapsed ? (
|
|
76
|
-
<>
|
|
77
|
-
<span style={{ display: "inline-flex" }}>{icon}</span>
|
|
78
|
-
{showBadge && (
|
|
79
|
-
<span style={{ position: "absolute", top: 2, right: 2 }}>
|
|
80
|
-
<CountBadge count={badge} size="sm" tone="critical" />
|
|
81
|
-
</span>
|
|
82
|
-
)}
|
|
83
|
-
</>
|
|
84
|
-
) : (
|
|
85
|
-
<>
|
|
86
|
-
<span style={{ display: "inline-flex", alignItems: "center", gap: 10 }}>
|
|
87
|
-
{icon}
|
|
88
|
-
<span>{label}</span>
|
|
89
|
-
</span>
|
|
90
|
-
{showBadge && <CountBadge count={badge} size="sm" tone="critical" />}
|
|
91
|
-
</>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// data-ck-navitem + data-active are escape hatches for chrome
|
|
95
|
-
// CSS to override the inline visual state (e.g. neobrutalism
|
|
96
|
-
// wants a fully different chunky look on the active item).
|
|
97
|
-
const dataAttrs = {
|
|
98
|
-
"data-ck-navitem": "",
|
|
99
|
-
"data-active": active ? "true" : undefined,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
if (href !== undefined) {
|
|
103
|
-
return (
|
|
104
|
-
<a
|
|
105
|
-
href={href}
|
|
106
|
-
title={collapsed ? label : undefined}
|
|
107
|
-
className={className}
|
|
108
|
-
style={baseStyle}
|
|
109
|
-
{...dataAttrs}
|
|
110
|
-
>
|
|
111
|
-
{content}
|
|
112
|
-
</a>
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<button
|
|
118
|
-
type="button"
|
|
119
|
-
onClick={onClick}
|
|
120
|
-
title={collapsed ? label : undefined}
|
|
121
|
-
className={className}
|
|
122
|
-
style={baseStyle}
|
|
123
|
-
{...dataAttrs}
|
|
124
|
-
>
|
|
125
|
-
{content}
|
|
126
|
-
</button>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Kbd } from "../primitives/Kbd";
|
|
2
|
-
|
|
3
|
-
// Search-style command-palette opener for the left rail. Wide
|
|
4
|
-
// click target, search icon on the left, kbd hint on the right.
|
|
5
|
-
// Hidden in collapsed mode — the palette is still reachable via
|
|
6
|
-
// ⌘K, no need for a dedicated trigger when there's no label space.
|
|
7
|
-
|
|
8
|
-
export interface NavSearchTriggerProps {
|
|
9
|
-
onClick: () => void;
|
|
10
|
-
placeholder?: string;
|
|
11
|
-
hotkey?: string;
|
|
12
|
-
collapsed?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function NavSearchTrigger({
|
|
16
|
-
onClick,
|
|
17
|
-
placeholder = "Search",
|
|
18
|
-
hotkey = "K",
|
|
19
|
-
collapsed,
|
|
20
|
-
}: NavSearchTriggerProps) {
|
|
21
|
-
if (collapsed) return null;
|
|
22
|
-
return (
|
|
23
|
-
<button
|
|
24
|
-
type="button"
|
|
25
|
-
onClick={onClick}
|
|
26
|
-
aria-label="Open command palette"
|
|
27
|
-
title="Open command palette"
|
|
28
|
-
data-ck-search-trigger
|
|
29
|
-
style={{
|
|
30
|
-
position: "relative",
|
|
31
|
-
width: "100%",
|
|
32
|
-
height: 34,
|
|
33
|
-
padding: "0 8px 0 32px",
|
|
34
|
-
background: "var(--ck-bg-muted)",
|
|
35
|
-
border: "1px solid transparent",
|
|
36
|
-
borderRadius: "var(--ck-radius-sm)",
|
|
37
|
-
cursor: "pointer",
|
|
38
|
-
display: "flex",
|
|
39
|
-
alignItems: "center",
|
|
40
|
-
justifyContent: "space-between",
|
|
41
|
-
textAlign: "left",
|
|
42
|
-
transition: "background var(--ck-dur-fast) var(--ck-ease), border-color var(--ck-dur-fast) var(--ck-ease)",
|
|
43
|
-
}}
|
|
44
|
-
onMouseEnter={(e) => {
|
|
45
|
-
e.currentTarget.style.borderColor = "var(--ck-border-strong)";
|
|
46
|
-
}}
|
|
47
|
-
onMouseLeave={(e) => {
|
|
48
|
-
e.currentTarget.style.borderColor = "transparent";
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
<svg
|
|
52
|
-
width="14"
|
|
53
|
-
height="14"
|
|
54
|
-
viewBox="0 0 24 24"
|
|
55
|
-
fill="none"
|
|
56
|
-
stroke="currentColor"
|
|
57
|
-
strokeWidth="2"
|
|
58
|
-
strokeLinecap="round"
|
|
59
|
-
strokeLinejoin="round"
|
|
60
|
-
style={{
|
|
61
|
-
position: "absolute",
|
|
62
|
-
left: 10,
|
|
63
|
-
top: "50%",
|
|
64
|
-
transform: "translateY(-50%)",
|
|
65
|
-
color: "var(--ck-text-tertiary)",
|
|
66
|
-
pointerEvents: "none",
|
|
67
|
-
}}
|
|
68
|
-
aria-hidden
|
|
69
|
-
>
|
|
70
|
-
<circle cx="11" cy="11" r="7" />
|
|
71
|
-
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
72
|
-
</svg>
|
|
73
|
-
<span
|
|
74
|
-
style={{
|
|
75
|
-
flex: 1,
|
|
76
|
-
font: "400 12px/1 var(--ck-font-sans)",
|
|
77
|
-
color: "var(--ck-text-tertiary)",
|
|
78
|
-
}}
|
|
79
|
-
>
|
|
80
|
-
{placeholder}
|
|
81
|
-
</span>
|
|
82
|
-
<span style={{ display: "inline-flex", gap: 2 }}>
|
|
83
|
-
<Kbd>Mod</Kbd>
|
|
84
|
-
<Kbd>{hotkey}</Kbd>
|
|
85
|
-
</span>
|
|
86
|
-
</button>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
// Section header inside <LeftNavRail>. Mono uppercase eyebrow above
|
|
4
|
-
// a group of <NavItem>s. Hides its own label in collapsed mode —
|
|
5
|
-
// icons are self-explanatory at 56 px and the cluster delimiters
|
|
6
|
-
// become visual noise.
|
|
7
|
-
|
|
8
|
-
export interface NavSectionProps {
|
|
9
|
-
label: string;
|
|
10
|
-
collapsed?: boolean;
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function NavSection({ label, collapsed, children }: NavSectionProps) {
|
|
15
|
-
return (
|
|
16
|
-
<div style={{ marginBottom: 16 }}>
|
|
17
|
-
{!collapsed && (
|
|
18
|
-
<div
|
|
19
|
-
className="ck-tag"
|
|
20
|
-
style={{
|
|
21
|
-
padding: "0 12px",
|
|
22
|
-
marginBottom: 6,
|
|
23
|
-
}}
|
|
24
|
-
>
|
|
25
|
-
{label}
|
|
26
|
-
</div>
|
|
27
|
-
)}
|
|
28
|
-
<div
|
|
29
|
-
style={{
|
|
30
|
-
display: "flex",
|
|
31
|
-
flexDirection: "column",
|
|
32
|
-
gap: collapsed ? 4 : 1,
|
|
33
|
-
alignItems: collapsed ? "center" : "stretch",
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
{children}
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, CSSProperties } from "react";
|
|
2
|
-
|
|
3
|
-
// Floating right-side panel. Used for ephemeral side surfaces —
|
|
4
|
-
// comments, signing management, review-link list, etc. Unlike the
|
|
5
|
-
// always-on AgentRail-style right rail, this is summoned by user
|
|
6
|
-
// action and dismissed via the close button or Esc.
|
|
7
|
-
//
|
|
8
|
-
// Sticks below the topbar (reads --ck-breadcrumb-height), max-height
|
|
9
|
-
// leaves room for any bottom-fixed UI (--ck-tabbar-height).
|
|
10
|
-
// Caller owns the open/close state.
|
|
11
|
-
|
|
12
|
-
export interface RightSidebarPanelProps {
|
|
13
|
-
open: boolean;
|
|
14
|
-
onClose: () => void;
|
|
15
|
-
// Required — small uppercase eyebrow above the title slot.
|
|
16
|
-
eyebrow: string;
|
|
17
|
-
title?: ReactNode;
|
|
18
|
-
// Right-side header slot (e.g. filter dropdown). Sits beside the
|
|
19
|
-
// close button.
|
|
20
|
-
headerExtras?: ReactNode;
|
|
21
|
-
children: ReactNode;
|
|
22
|
-
// px. Default 320.
|
|
23
|
-
width?: number;
|
|
24
|
-
// px offset from viewport edges. Default 12.
|
|
25
|
-
edgeOffset?: number;
|
|
26
|
-
className?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function RightSidebarPanel({
|
|
30
|
-
open,
|
|
31
|
-
onClose,
|
|
32
|
-
eyebrow,
|
|
33
|
-
title,
|
|
34
|
-
headerExtras,
|
|
35
|
-
children,
|
|
36
|
-
width = 320,
|
|
37
|
-
edgeOffset = 12,
|
|
38
|
-
className,
|
|
39
|
-
}: RightSidebarPanelProps) {
|
|
40
|
-
if (!open) return null;
|
|
41
|
-
const topOffset = `calc(var(--ck-breadcrumb-height, 64px) + ${edgeOffset}px)`;
|
|
42
|
-
const bottomOffset = `calc(var(--ck-tabbar-height, 0px) + ${edgeOffset}px)`;
|
|
43
|
-
return (
|
|
44
|
-
<aside
|
|
45
|
-
role="complementary"
|
|
46
|
-
className={className}
|
|
47
|
-
style={
|
|
48
|
-
{
|
|
49
|
-
position: "fixed",
|
|
50
|
-
top: topOffset,
|
|
51
|
-
right: edgeOffset,
|
|
52
|
-
width,
|
|
53
|
-
maxHeight: `calc(100vh - ${topOffset} - ${bottomOffset})`,
|
|
54
|
-
background: "var(--ck-bg-surface)",
|
|
55
|
-
border: "1px solid var(--ck-border-subtle)",
|
|
56
|
-
borderRadius: "var(--ck-radius-md)",
|
|
57
|
-
boxShadow: "var(--ck-shadow-2)",
|
|
58
|
-
display: "flex",
|
|
59
|
-
flexDirection: "column",
|
|
60
|
-
zIndex: 60,
|
|
61
|
-
fontFamily: "var(--ck-font-sans)",
|
|
62
|
-
} as CSSProperties
|
|
63
|
-
}
|
|
64
|
-
>
|
|
65
|
-
<div
|
|
66
|
-
style={{
|
|
67
|
-
padding: "14px 16px",
|
|
68
|
-
borderBottom: "1px solid var(--ck-border-subtle)",
|
|
69
|
-
display: "flex",
|
|
70
|
-
alignItems: "flex-start",
|
|
71
|
-
gap: 8,
|
|
72
|
-
}}
|
|
73
|
-
>
|
|
74
|
-
<div style={{ flex: 1, minWidth: 0 }}>
|
|
75
|
-
<div className="ck-eyebrow" style={{ marginBottom: title ? 4 : 0 }}>
|
|
76
|
-
{eyebrow}
|
|
77
|
-
</div>
|
|
78
|
-
{title && (
|
|
79
|
-
<div
|
|
80
|
-
style={{
|
|
81
|
-
font: "500 14px/1.3 var(--ck-font-sans)",
|
|
82
|
-
color: "var(--ck-text-primary)",
|
|
83
|
-
}}
|
|
84
|
-
>
|
|
85
|
-
{title}
|
|
86
|
-
</div>
|
|
87
|
-
)}
|
|
88
|
-
</div>
|
|
89
|
-
{headerExtras}
|
|
90
|
-
<button
|
|
91
|
-
type="button"
|
|
92
|
-
onClick={onClose}
|
|
93
|
-
aria-label="Close"
|
|
94
|
-
style={{
|
|
95
|
-
border: "none",
|
|
96
|
-
background: "transparent",
|
|
97
|
-
color: "var(--ck-text-tertiary)",
|
|
98
|
-
cursor: "pointer",
|
|
99
|
-
fontSize: 18,
|
|
100
|
-
lineHeight: 1,
|
|
101
|
-
padding: 2,
|
|
102
|
-
marginLeft: 4,
|
|
103
|
-
}}
|
|
104
|
-
>
|
|
105
|
-
×
|
|
106
|
-
</button>
|
|
107
|
-
</div>
|
|
108
|
-
<div style={{ flex: 1, minHeight: 0, overflowY: "auto" }}>{children}</div>
|
|
109
|
-
</aside>
|
|
110
|
-
);
|
|
111
|
-
}
|
package/src/layout/Shell.tsx
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, CSSProperties } from "react";
|
|
2
|
-
|
|
3
|
-
// Layout shell. The kit is unopinionated about WHICH navigation
|
|
4
|
-
// primitives sit in each slot — pass <LeftNavRail>, <Topbar>,
|
|
5
|
-
// <MobileTabBar> etc. (or your own equivalents) and Shell composes
|
|
6
|
-
// them into the standard layout:
|
|
7
|
-
//
|
|
8
|
-
// ┌──────────────────────────────────────────┐
|
|
9
|
-
// │ topbar (full width, fixed) │
|
|
10
|
-
// ├────────┬─────────────────────────┬───────┤
|
|
11
|
-
// │ │ │ │
|
|
12
|
-
// │ left │ main (children) │ right │
|
|
13
|
-
// │ nav │ │ rail │
|
|
14
|
-
// │ (fix) │ insets via CSS vars │ (fix) │
|
|
15
|
-
// │ │ │ │
|
|
16
|
-
// └────────┴─────────────────────────┴───────┘
|
|
17
|
-
//
|
|
18
|
-
// All three rails are position:fixed and stamp their widths/heights
|
|
19
|
-
// as CSS vars (--ck-leftnav-width, --ck-rightrail-width,
|
|
20
|
-
// --ck-tabbar-height). Shell reads those vars to inset the main
|
|
21
|
-
// region. No prop drilling.
|
|
22
|
-
|
|
23
|
-
export interface ShellProps {
|
|
24
|
-
// Drop <LeftNavRail> here. Shell renders it as-is; the rail itself
|
|
25
|
-
// handles fixed positioning.
|
|
26
|
-
leftRail?: ReactNode;
|
|
27
|
-
// <Topbar>. Sticky at the top of the main column.
|
|
28
|
-
topbar?: ReactNode;
|
|
29
|
-
// Page body.
|
|
30
|
-
children: ReactNode;
|
|
31
|
-
// Right rail (e.g. agent panel, comments panel) — rendered as-is.
|
|
32
|
-
rightRail?: ReactNode;
|
|
33
|
-
// Mobile bottom tab bar — rendered as-is.
|
|
34
|
-
tabBar?: ReactNode;
|
|
35
|
-
// Inline style overrides for the main region (useful for setting
|
|
36
|
-
// background per route).
|
|
37
|
-
mainStyle?: CSSProperties;
|
|
38
|
-
className?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function Shell({
|
|
42
|
-
leftRail,
|
|
43
|
-
topbar,
|
|
44
|
-
children,
|
|
45
|
-
rightRail,
|
|
46
|
-
tabBar,
|
|
47
|
-
mainStyle,
|
|
48
|
-
className,
|
|
49
|
-
}: ShellProps) {
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
data-ck-shell
|
|
53
|
-
className={className}
|
|
54
|
-
style={{
|
|
55
|
-
minHeight: "100vh",
|
|
56
|
-
background: "var(--ck-bg-canvas)",
|
|
57
|
-
color: "var(--ck-text-primary)",
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
{leftRail}
|
|
61
|
-
{rightRail}
|
|
62
|
-
{tabBar}
|
|
63
|
-
<div
|
|
64
|
-
style={
|
|
65
|
-
{
|
|
66
|
-
marginLeft: "var(--ck-leftnav-width, 0px)",
|
|
67
|
-
marginRight: "var(--ck-rightrail-width, 0px)",
|
|
68
|
-
paddingBottom: "var(--ck-tabbar-height, 0px)",
|
|
69
|
-
minHeight: "100vh",
|
|
70
|
-
display: "flex",
|
|
71
|
-
flexDirection: "column",
|
|
72
|
-
transition: "margin var(--ck-dur-fast) var(--ck-ease)",
|
|
73
|
-
} as CSSProperties
|
|
74
|
-
}
|
|
75
|
-
>
|
|
76
|
-
{topbar && (
|
|
77
|
-
<div
|
|
78
|
-
style={{
|
|
79
|
-
position: "sticky",
|
|
80
|
-
top: 0,
|
|
81
|
-
zIndex: 20,
|
|
82
|
-
}}
|
|
83
|
-
>
|
|
84
|
-
{topbar}
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
<main style={{ flex: 1, minHeight: 0, ...mainStyle }}>{children}</main>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|