@xenide-io/the-old-ui-theme 0.4.4 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-54ZR4VL5.mjs → chunk-RZXHZWUB.mjs} +44 -17
- package/dist/{index-B5NOyoKS.d.mts → index-Od4pIP4F.d.mts} +7 -1
- package/dist/{index-B5NOyoKS.d.ts → index-Od4pIP4F.d.ts} +7 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -10
- package/dist/index.mjs +1 -1
- package/dist/suite.d.mts +152 -41
- package/dist/suite.d.ts +152 -41
- package/dist/suite.js +1366 -671
- package/dist/suite.mjs +1304 -610
- package/dist/ui.d.mts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +37 -10
- package/dist/ui.mjs +1 -1
- package/package.json +7 -3
- package/src/components/ui/Modal.tsx +70 -26
- package/src/styles/suite-skin.css +284 -24
- package/src/suite/components/ai-panel.test.ts +20 -0
- package/src/suite/components/ai-panel.tsx +494 -103
- package/src/suite/components/suite-app-layout.tsx +48 -28
- package/src/suite/components/suite-layout.tsx +84 -40
- package/src/suite/components/suite-mobile-drawer.tsx +35 -22
- package/src/suite/components/suite-notification-bell.tsx +9 -3
- package/src/suite/components/suite-settings-layout.tsx +82 -0
- package/src/suite/components/suite-settings-mobile-nav.tsx +18 -17
- package/src/suite/components/suite-skeleton.tsx +3 -3
- package/src/suite/components/today-calibrating.tsx +11 -35
- package/src/suite/components/today-page-frame.tsx +19 -11
- package/src/suite/components/today-ui.tsx +276 -19
- package/src/suite/index.ts +41 -25
- package/src/suite/lib/apps.ts +32 -2
- package/src/suite/lib/use-sidebar-width.ts +114 -0
- package/src/components/sections/AccordionShowcase.tsx +0 -45
- package/src/components/sections/AlertShowcase.tsx +0 -40
- package/src/components/sections/AvatarShowcase.tsx +0 -80
- package/src/components/sections/BadgeShowcase.tsx +0 -65
- package/src/components/sections/ButtonShowcase.tsx +0 -308
- package/src/components/sections/CalendarShowcase.tsx +0 -35
- package/src/components/sections/CardShowcase.tsx +0 -159
- package/src/components/sections/CodeMockupShowcase.tsx +0 -56
- package/src/components/sections/ColorPalette.tsx +0 -117
- package/src/components/sections/CommandPaletteShowcase.tsx +0 -48
- package/src/components/sections/CountdownShowcase.tsx +0 -43
- package/src/components/sections/DiffShowcase.tsx +0 -70
- package/src/components/sections/DrawerShowcase.tsx +0 -97
- package/src/components/sections/DropdownShowcase.tsx +0 -98
- package/src/components/sections/EmptyStateShowcase.tsx +0 -50
- package/src/components/sections/FilterChipsShowcase.tsx +0 -98
- package/src/components/sections/FormShowcase.tsx +0 -127
- package/src/components/sections/HoverCardShowcase.tsx +0 -50
- package/src/components/sections/IconShowcase.tsx +0 -121
- package/src/components/sections/IndicatorShowcase.tsx +0 -52
- package/src/components/sections/KbdShowcase.tsx +0 -57
- package/src/components/sections/ModalShowcase.tsx +0 -211
- package/src/components/sections/NavigationShowcase.tsx +0 -199
- package/src/components/sections/NewComponentsShowcase.tsx +0 -1052
- package/src/components/sections/ProductLayoutsShowcase.tsx +0 -78
- package/src/components/sections/ProgressShowcase.tsx +0 -82
- package/src/components/sections/QuillChartShowcase.tsx +0 -92
- package/src/components/sections/QuillDashboardShowcase.tsx +0 -149
- package/src/components/sections/SegmentedControlShowcase.tsx +0 -49
- package/src/components/sections/SetupThemeShowcase.tsx +0 -262
- package/src/components/sections/SidebarShowcase.tsx +0 -152
- package/src/components/sections/StackShowcase.tsx +0 -33
- package/src/components/sections/StepperShowcase.tsx +0 -37
- package/src/components/sections/SuiteShowcase.tsx +0 -669
- package/src/components/sections/SwapShowcase.tsx +0 -99
- package/src/components/sections/TabShowcase.tsx +0 -84
- package/src/components/sections/TableShowcase.tsx +0 -142
- package/src/components/sections/TimelineShowcase.tsx +0 -83
- package/src/components/sections/ToastShowcase.tsx +0 -108
- package/src/components/sections/TooltipShowcase.tsx +0 -38
- package/src/components/sections/UtilityShowcase.tsx +0 -81
- package/src/styles/excel-themes.css +0 -110
- package/src/styles/lemon-primitives.css +0 -550
|
@@ -7,58 +7,40 @@ import type { SuiteSpinnerComponent } from '../lib/injected';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Today-page loading/empty calibrating state. Apps inject their branded
|
|
10
|
-
* AppSpinner
|
|
11
|
-
*
|
|
12
|
-
* - `pulse` — pulsing sun only (Tides/Kraken)
|
|
10
|
+
* AppSpinner. Kept deliberately quiet — single soft fade + one spinner,
|
|
11
|
+
* no ping/pulse stacks that compete with OAuth/launch handoffs.
|
|
13
12
|
*/
|
|
14
13
|
export function TodayCalibrating({
|
|
15
14
|
onRetry,
|
|
16
15
|
retrying = false,
|
|
17
16
|
className,
|
|
18
17
|
spinner: Spinner,
|
|
19
|
-
variant = 'ring',
|
|
18
|
+
variant: _variant = 'ring',
|
|
20
19
|
retrySpinnerClassName = 'text-ph-brand',
|
|
21
20
|
}: {
|
|
22
21
|
onRetry?: () => void;
|
|
23
22
|
retrying?: boolean;
|
|
24
23
|
className?: string;
|
|
25
24
|
spinner: SuiteSpinnerComponent;
|
|
25
|
+
/** @deprecated Kept for call-site compat; ornamentation is always calm. */
|
|
26
26
|
variant?: 'ring' | 'pulse';
|
|
27
27
|
retrySpinnerClassName?: string;
|
|
28
28
|
}) {
|
|
29
|
+
void _variant;
|
|
29
30
|
return (
|
|
30
31
|
<div
|
|
31
32
|
className={cn(
|
|
32
|
-
'relative flex min-h-[14rem] flex-col items-center justify-center overflow-hidden rounded-2xl border border-ph-border bg-ph-surface px-5 py-8 text-center shadow-sm',
|
|
33
|
+
'suite-auth-handoff relative flex min-h-[14rem] flex-col items-center justify-center overflow-hidden rounded-2xl border border-ph-border bg-ph-surface px-5 py-8 text-center shadow-sm',
|
|
33
34
|
className,
|
|
34
35
|
)}
|
|
35
36
|
data-test="today-calibrating"
|
|
36
37
|
>
|
|
37
38
|
<div
|
|
38
|
-
className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(251,191,36,0.
|
|
39
|
+
className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(251,191,36,0.1),transparent_55%)]"
|
|
39
40
|
aria-hidden
|
|
40
41
|
/>
|
|
41
|
-
<div className="relative mb-
|
|
42
|
-
|
|
43
|
-
<>
|
|
44
|
-
<Spinner
|
|
45
|
-
size="lg"
|
|
46
|
-
className="absolute inset-0 m-auto opacity-40"
|
|
47
|
-
label="Loading today"
|
|
48
|
-
/>
|
|
49
|
-
<span
|
|
50
|
-
className="bg-ph-muted/30 absolute inset-2 animate-ping rounded-full"
|
|
51
|
-
aria-hidden
|
|
52
|
-
/>
|
|
53
|
-
</>
|
|
54
|
-
) : null}
|
|
55
|
-
<span className="relative flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm">
|
|
56
|
-
<Sun
|
|
57
|
-
className={cn('h-9 w-9', variant === 'pulse' && 'animate-pulse')}
|
|
58
|
-
strokeWidth={2}
|
|
59
|
-
aria-hidden
|
|
60
|
-
/>
|
|
61
|
-
</span>
|
|
42
|
+
<div className="relative mb-5 flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm">
|
|
43
|
+
<Sun className="h-8 w-8" strokeWidth={2} aria-hidden />
|
|
62
44
|
</div>
|
|
63
45
|
<h2 className="relative text-base font-semibold tracking-tight text-ph-ink sm:text-lg md:text-xl">
|
|
64
46
|
Calibrating your day
|
|
@@ -66,14 +48,8 @@ export function TodayCalibrating({
|
|
|
66
48
|
<p className="relative mt-1.5 max-w-sm text-sm sm:text-[15px] leading-relaxed text-ph-subtle">
|
|
67
49
|
Pulling together tasks, time and updates from your workspace…
|
|
68
50
|
</p>
|
|
69
|
-
<div className="relative mt-5 flex
|
|
70
|
-
|
|
71
|
-
<span
|
|
72
|
-
key={i}
|
|
73
|
-
className="h-1.5 w-5 animate-pulse rounded-full bg-ph-muted"
|
|
74
|
-
style={{ animationDelay: `${i * 120}ms` }}
|
|
75
|
-
/>
|
|
76
|
-
))}
|
|
51
|
+
<div className="relative mt-5 flex justify-center">
|
|
52
|
+
<Spinner size="sm" className="opacity-70" label="Loading today" />
|
|
77
53
|
</div>
|
|
78
54
|
{onRetry ? (
|
|
79
55
|
<button
|
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import type { ReactNode } from
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Today page content wrapper with soft atmosphere.
|
|
7
|
+
* Does not own scrolling — `#main-content` is the scrollport so sticky headers work.
|
|
8
|
+
* Glow/clouds are absolute and do not create a nested scrollport.
|
|
9
|
+
*/
|
|
6
10
|
export function TodayPageFrame({ children }: { children: ReactNode }) {
|
|
7
11
|
return (
|
|
8
12
|
<div
|
|
9
13
|
data-test="today-page"
|
|
10
|
-
className="today-page-frame relative flex min-h-0 flex-1 flex-col overflow-
|
|
14
|
+
className="today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-hidden"
|
|
11
15
|
>
|
|
12
16
|
<div
|
|
13
|
-
className="pointer-events-none absolute inset-
|
|
17
|
+
className="pointer-events-none absolute inset-0 overflow-hidden"
|
|
14
18
|
aria-hidden
|
|
15
19
|
>
|
|
16
20
|
<div className="today-page-frame__glow absolute inset-0" />
|
|
17
|
-
<div className="today-page-
|
|
18
|
-
<div className="today-page-
|
|
19
|
-
<div className="today-page-frame__cloud today-page-frame__cloud--
|
|
20
|
-
<div className="today-page-frame__cloud today-page-frame__cloud--
|
|
21
|
-
<div className="today-page-frame__cloud today-page-frame__cloud--
|
|
21
|
+
<div className="today-page-frame__top-fade absolute inset-x-0 top-0 h-[28rem]" />
|
|
22
|
+
<div className="today-page-frame__cloud today-page-frame__cloud--1 absolute -left-28 top-16 h-96 w-[30rem] rounded-[45%]" />
|
|
23
|
+
<div className="today-page-frame__cloud today-page-frame__cloud--2 absolute -right-24 top-24 h-80 w-[22rem] rounded-[40%]" />
|
|
24
|
+
<div className="today-page-frame__cloud today-page-frame__cloud--3 absolute left-[22%] top-48 h-72 w-[24rem] rounded-[50%]" />
|
|
25
|
+
<div className="today-page-frame__cloud today-page-frame__cloud--4 absolute right-[18%] top-[42%] h-64 w-[20rem] rounded-[48%]" />
|
|
26
|
+
<div className="today-page-frame__cloud today-page-frame__cloud--5 absolute left-[8%] top-[68%] h-56 w-[18rem] rounded-[42%]" />
|
|
22
27
|
</div>
|
|
23
|
-
<div
|
|
28
|
+
<div
|
|
29
|
+
data-width="full"
|
|
30
|
+
className="suite-page-stage suite-page-inset relative z-[1] flex w-full min-w-0 flex-1 flex-col [&_.list-row]:min-h-[52px] [&_.list-row]:sm:min-h-[44px]"
|
|
31
|
+
>
|
|
24
32
|
{children}
|
|
25
33
|
</div>
|
|
26
34
|
</div>
|
|
@@ -6,7 +6,9 @@ import { cn } from '../lib/cn';
|
|
|
6
6
|
import { SuiteAppIcon } from '../icons/suite-app-icon';
|
|
7
7
|
import { SuiteIcon } from '../icons/suite-icon';
|
|
8
8
|
import type { SuiteIconName } from '../icons/glyphs';
|
|
9
|
-
type LucideIcon = import('react').ComponentType<
|
|
9
|
+
type LucideIcon = import('react').ComponentType<
|
|
10
|
+
import('react').SVGProps<SVGSVGElement>
|
|
11
|
+
>;
|
|
10
12
|
|
|
11
13
|
export type SuiteAppSlug = 'shellstack' | 'tides' | 'turtletime' | 'kraken';
|
|
12
14
|
|
|
@@ -117,16 +119,17 @@ export function AnimatedSun({ className }: { className?: string }) {
|
|
|
117
119
|
<stop offset="1" stopColor="#fb923c" />
|
|
118
120
|
</linearGradient>
|
|
119
121
|
</defs>
|
|
120
|
-
|
|
122
|
+
{/* ponytail: static rays + soft opacity pulse; spin was too busy for a sticky header */}
|
|
123
|
+
<g className="origin-center opacity-80 motion-safe:animate-[pulse_8s_ease-in-out_infinite] motion-reduce:animate-none">
|
|
121
124
|
{[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => (
|
|
122
125
|
<line
|
|
123
126
|
key={angle}
|
|
124
127
|
x1="20"
|
|
125
|
-
y1="
|
|
128
|
+
y1="5"
|
|
126
129
|
x2="20"
|
|
127
130
|
y2="9"
|
|
128
131
|
stroke="#fbbf24"
|
|
129
|
-
strokeWidth="
|
|
132
|
+
strokeWidth="1.75"
|
|
130
133
|
strokeLinecap="round"
|
|
131
134
|
transform={`rotate(${angle} 20 20)`}
|
|
132
135
|
/>
|
|
@@ -158,10 +161,9 @@ export function AnimatedMoon({ className }: { className?: string }) {
|
|
|
158
161
|
d="M27.5 25.5A11 11 0 1 1 14.5 9.6a9 9 0 1 0 13 15.9Z"
|
|
159
162
|
fill="url(#animatedMoonBody)"
|
|
160
163
|
/>
|
|
161
|
-
<g className="motion-safe:animate-[
|
|
162
|
-
<circle cx="29" cy="10" r="1.
|
|
163
|
-
<circle cx="34" cy="16" r="
|
|
164
|
-
<circle cx="25" cy="5.5" r="0.9" fill="#c7d2fe" />
|
|
164
|
+
<g className="opacity-70 motion-safe:animate-[pulse_10s_ease-in-out_infinite] motion-reduce:animate-none">
|
|
165
|
+
<circle cx="29" cy="10" r="1.2" fill="#c7d2fe" />
|
|
166
|
+
<circle cx="34" cy="16" r="0.9" fill="#c7d2fe" />
|
|
165
167
|
</g>
|
|
166
168
|
</svg>
|
|
167
169
|
);
|
|
@@ -190,7 +192,9 @@ export function TodayTopBar({
|
|
|
190
192
|
appIcon?: ReactNode;
|
|
191
193
|
appName?: string;
|
|
192
194
|
}) {
|
|
193
|
-
const icon = appIcon ??
|
|
195
|
+
const icon = appIcon ?? (
|
|
196
|
+
<TodayTimeIcon className="h-6 w-6 sm:h-7 sm:w-7 text-amber-500" />
|
|
197
|
+
);
|
|
194
198
|
return (
|
|
195
199
|
<header className="flex items-center justify-between gap-4">
|
|
196
200
|
<div className="flex min-w-0 items-center gap-3">
|
|
@@ -252,33 +256,287 @@ export function getTodayGreeting(
|
|
|
252
256
|
const hours = stats?.hours ?? 0;
|
|
253
257
|
|
|
254
258
|
if (overdueCount > 0) {
|
|
255
|
-
return `${greeting}.
|
|
259
|
+
return `${greeting}. ${taskCount} task${taskCount === 1 ? '' : 's'} due today, ${overdueCount} overdue.`;
|
|
256
260
|
}
|
|
257
261
|
if (taskCount > 0) {
|
|
258
|
-
return `${greeting}.
|
|
262
|
+
return `${greeting}. ${taskCount} task${taskCount === 1 ? '' : 's'} due today.`;
|
|
259
263
|
}
|
|
260
264
|
if (hours > 0) {
|
|
261
|
-
return `${greeting}.
|
|
265
|
+
return `${greeting}. ${hours} hour${hours === 1 ? '' : 's'} logged today.`;
|
|
262
266
|
}
|
|
263
267
|
if (period === 'evening' || period === 'night') {
|
|
264
|
-
return `${greeting}.
|
|
268
|
+
return `${greeting}. Nice work — time to wrap up.`;
|
|
265
269
|
}
|
|
266
|
-
return `${greeting}.
|
|
270
|
+
return `${greeting}. Clear queue — take a nice, deep breath.`;
|
|
267
271
|
}
|
|
268
272
|
|
|
269
273
|
export function TodayHero({
|
|
270
274
|
message = 'Take a nice, deep breath.',
|
|
275
|
+
brief,
|
|
276
|
+
briefMeta,
|
|
271
277
|
}: {
|
|
272
278
|
message?: ReactNode;
|
|
279
|
+
/** AI / local focus brief under the greeting. */
|
|
280
|
+
brief?: ReactNode;
|
|
281
|
+
briefMeta?: ReactNode;
|
|
273
282
|
}) {
|
|
274
283
|
return (
|
|
275
|
-
<div className="mt-
|
|
284
|
+
<div className="mt-4 sm:mt-6">
|
|
276
285
|
<p
|
|
277
286
|
key={typeof message === 'string' ? message : 'hero'}
|
|
278
|
-
className="today-hero font-display text-
|
|
287
|
+
className="today-hero max-w-2xl font-display text-lg font-semibold tracking-tight text-ph-ink sm:text-xl sm:leading-snug"
|
|
279
288
|
>
|
|
280
289
|
{message}
|
|
281
290
|
</p>
|
|
291
|
+
{brief ? (
|
|
292
|
+
<div className="mt-4 max-w-2xl" data-test="today-focus-brief">
|
|
293
|
+
<p className="text-[15px] leading-[1.65] text-ph-ink">{brief}</p>
|
|
294
|
+
{briefMeta ? (
|
|
295
|
+
<p className="mt-1.5 text-xs text-ph-mutedtext">{briefMeta}</p>
|
|
296
|
+
) : null}
|
|
297
|
+
</div>
|
|
298
|
+
) : null}
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export type TodayPrimaryAccent =
|
|
304
|
+
'tides' | 'turtletime' | 'kraken' | 'shellstack' | 'neutral';
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Compact primary CTA for Today — one action per app.
|
|
308
|
+
* Colours live in suite-skin (.today-primary-action); no idle animation.
|
|
309
|
+
*/
|
|
310
|
+
export function TodayPrimaryAction({
|
|
311
|
+
label,
|
|
312
|
+
description,
|
|
313
|
+
icon,
|
|
314
|
+
accent = 'neutral',
|
|
315
|
+
onClick,
|
|
316
|
+
href,
|
|
317
|
+
loading = false,
|
|
318
|
+
active = false,
|
|
319
|
+
className,
|
|
320
|
+
dataTest = 'today-primary-action',
|
|
321
|
+
}: {
|
|
322
|
+
label: string;
|
|
323
|
+
description?: string;
|
|
324
|
+
icon?: ReactNode;
|
|
325
|
+
accent?: TodayPrimaryAccent;
|
|
326
|
+
onClick?: () => void;
|
|
327
|
+
href?: string;
|
|
328
|
+
loading?: boolean;
|
|
329
|
+
/** e.g. timer already running */
|
|
330
|
+
active?: boolean;
|
|
331
|
+
className?: string;
|
|
332
|
+
dataTest?: string;
|
|
333
|
+
}) {
|
|
334
|
+
const classes = cn(
|
|
335
|
+
'today-primary-action group relative flex w-full max-w-md items-center gap-3 overflow-hidden rounded-xl px-3.5 py-2.5 text-left transition sm:px-4 sm:py-3',
|
|
336
|
+
`today-primary-action--${accent}`,
|
|
337
|
+
active && 'today-primary-action--active',
|
|
338
|
+
loading && 'pointer-events-none opacity-70',
|
|
339
|
+
className,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const body = (
|
|
343
|
+
<>
|
|
344
|
+
<span className="today-primary-action__icon inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg sm:h-10 sm:w-10">
|
|
345
|
+
{icon}
|
|
346
|
+
</span>
|
|
347
|
+
<span className="min-w-0 flex-1">
|
|
348
|
+
<span className="block text-sm font-semibold tracking-tight sm:text-base">
|
|
349
|
+
{label}
|
|
350
|
+
</span>
|
|
351
|
+
{description ? (
|
|
352
|
+
<span className="mt-0.5 block text-xs opacity-80 sm:text-sm">
|
|
353
|
+
{description}
|
|
354
|
+
</span>
|
|
355
|
+
) : null}
|
|
356
|
+
</span>
|
|
357
|
+
<span
|
|
358
|
+
className="today-primary-action__chevron shrink-0 text-base opacity-60 transition group-hover:translate-x-0.5 group-hover:opacity-100"
|
|
359
|
+
aria-hidden
|
|
360
|
+
>
|
|
361
|
+
→
|
|
362
|
+
</span>
|
|
363
|
+
</>
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
if (href && !onClick) {
|
|
367
|
+
return (
|
|
368
|
+
<a
|
|
369
|
+
href={href}
|
|
370
|
+
className={classes}
|
|
371
|
+
data-test={dataTest}
|
|
372
|
+
aria-busy={loading}
|
|
373
|
+
>
|
|
374
|
+
{body}
|
|
375
|
+
</a>
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
<button
|
|
381
|
+
type="button"
|
|
382
|
+
onClick={onClick}
|
|
383
|
+
disabled={loading}
|
|
384
|
+
className={classes}
|
|
385
|
+
data-test={dataTest}
|
|
386
|
+
aria-busy={loading}
|
|
387
|
+
>
|
|
388
|
+
{body}
|
|
389
|
+
</button>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function TodayEmptyAction({
|
|
394
|
+
title,
|
|
395
|
+
description,
|
|
396
|
+
actionLabel,
|
|
397
|
+
href,
|
|
398
|
+
onClick,
|
|
399
|
+
dataTest,
|
|
400
|
+
}: {
|
|
401
|
+
title: string;
|
|
402
|
+
description?: string;
|
|
403
|
+
actionLabel?: string;
|
|
404
|
+
href?: string;
|
|
405
|
+
onClick?: () => void;
|
|
406
|
+
dataTest?: string;
|
|
407
|
+
}) {
|
|
408
|
+
return (
|
|
409
|
+
<div
|
|
410
|
+
className="rounded-lg border border-dashed border-ph-border/80 bg-ph-muted/30 px-4 py-4 text-center"
|
|
411
|
+
data-test={dataTest}
|
|
412
|
+
>
|
|
413
|
+
<p className="text-sm font-semibold text-ph-ink">{title}</p>
|
|
414
|
+
{description ? (
|
|
415
|
+
<p className="mx-auto mt-1 max-w-sm text-xs leading-relaxed text-ph-subtle sm:text-sm">
|
|
416
|
+
{description}
|
|
417
|
+
</p>
|
|
418
|
+
) : null}
|
|
419
|
+
{actionLabel && (href || onClick) ? (
|
|
420
|
+
href ? (
|
|
421
|
+
<a
|
|
422
|
+
href={href}
|
|
423
|
+
className="mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline"
|
|
424
|
+
>
|
|
425
|
+
{actionLabel}
|
|
426
|
+
</a>
|
|
427
|
+
) : (
|
|
428
|
+
<button
|
|
429
|
+
type="button"
|
|
430
|
+
onClick={onClick}
|
|
431
|
+
className="mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline"
|
|
432
|
+
>
|
|
433
|
+
{actionLabel}
|
|
434
|
+
</button>
|
|
435
|
+
)
|
|
436
|
+
) : null}
|
|
437
|
+
</div>
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Desktop Today shell: main column + sticky Ask AI / brief aside. */
|
|
442
|
+
export function TodayLayout({
|
|
443
|
+
primary,
|
|
444
|
+
main,
|
|
445
|
+
aside,
|
|
446
|
+
className,
|
|
447
|
+
}: {
|
|
448
|
+
primary?: ReactNode;
|
|
449
|
+
main: ReactNode;
|
|
450
|
+
aside?: ReactNode;
|
|
451
|
+
className?: string;
|
|
452
|
+
}) {
|
|
453
|
+
return (
|
|
454
|
+
<div
|
|
455
|
+
className={cn('mt-5 space-y-6 sm:mt-6', className)}
|
|
456
|
+
data-test="today-layout"
|
|
457
|
+
>
|
|
458
|
+
{primary ? <div className="max-w-md">{primary}</div> : null}
|
|
459
|
+
<div className="grid gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(16rem,20rem)] lg:items-start lg:gap-8">
|
|
460
|
+
<div className="min-w-0 space-y-8">{main}</div>
|
|
461
|
+
{aside ? (
|
|
462
|
+
<aside className="space-y-3 lg:sticky lg:top-6 lg:self-start">
|
|
463
|
+
{aside}
|
|
464
|
+
</aside>
|
|
465
|
+
) : null}
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Today Ask AI CTA — opens the suite assistant (not Kraken Deep Research).
|
|
473
|
+
* Prefer onClick → openSuiteAskAi(); href is a fallback only.
|
|
474
|
+
*/
|
|
475
|
+
export function TodayAskAiCard({
|
|
476
|
+
title = 'Ask AI',
|
|
477
|
+
description = 'Ask about your workspace, draft something, or look a fact up online.',
|
|
478
|
+
cta = 'Ask',
|
|
479
|
+
className,
|
|
480
|
+
onClick,
|
|
481
|
+
href,
|
|
482
|
+
}: {
|
|
483
|
+
title?: string;
|
|
484
|
+
description?: string;
|
|
485
|
+
cta?: string;
|
|
486
|
+
className?: string;
|
|
487
|
+
onClick?: () => void;
|
|
488
|
+
href?: string;
|
|
489
|
+
}) {
|
|
490
|
+
const classes = cn(
|
|
491
|
+
'group flex w-full items-start gap-3.5 rounded-2xl border border-ph-border/70 bg-ph-surface px-4 py-3.5 text-left shadow-[0_1px_12px_-8px_rgba(15,23,42,0.1)] transition hover:border-ph-brand/35 hover:bg-[color-mix(in_oklab,var(--ph-accent)_6%,var(--ph-surface))] sm:px-5',
|
|
492
|
+
className,
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
const body = (
|
|
496
|
+
<>
|
|
497
|
+
<span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-ph-brand/15 text-ph-brand shadow-sm ring-1 ring-black/[0.06]">
|
|
498
|
+
<SuiteIcon name="stack-hex" accent="shellstack" className="h-5 w-5" />
|
|
499
|
+
</span>
|
|
500
|
+
<span className="min-w-0 flex-1">
|
|
501
|
+
<span className="flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1">
|
|
502
|
+
<span className="font-display text-sm font-bold tracking-tight text-ph-ink">
|
|
503
|
+
{title}
|
|
504
|
+
</span>
|
|
505
|
+
<span className="text-sm font-medium text-ph-brand transition group-hover:underline">
|
|
506
|
+
{cta}
|
|
507
|
+
</span>
|
|
508
|
+
</span>
|
|
509
|
+
<span className="mt-1 block text-sm leading-relaxed text-ph-subtle">
|
|
510
|
+
{description}
|
|
511
|
+
</span>
|
|
512
|
+
</span>
|
|
513
|
+
</>
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
if (onClick) {
|
|
517
|
+
return (
|
|
518
|
+
<button
|
|
519
|
+
type="button"
|
|
520
|
+
onClick={onClick}
|
|
521
|
+
className={classes}
|
|
522
|
+
data-test="today-ask-ai"
|
|
523
|
+
>
|
|
524
|
+
{body}
|
|
525
|
+
</button>
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (href) {
|
|
530
|
+
return (
|
|
531
|
+
<a href={href} className={classes} data-test="today-ask-ai">
|
|
532
|
+
{body}
|
|
533
|
+
</a>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return (
|
|
538
|
+
<div className={classes} data-test="today-ask-ai">
|
|
539
|
+
{body}
|
|
282
540
|
</div>
|
|
283
541
|
);
|
|
284
542
|
}
|
|
@@ -301,7 +559,7 @@ export function TodaySection({
|
|
|
301
559
|
children: ReactNode;
|
|
302
560
|
}) {
|
|
303
561
|
return (
|
|
304
|
-
<section data-test={testId} className="space-y-
|
|
562
|
+
<section data-test={testId} className="space-y-5">
|
|
305
563
|
<div className="flex items-start justify-between gap-4">
|
|
306
564
|
<div className="flex min-w-0 items-start gap-3.5">
|
|
307
565
|
<span
|
|
@@ -340,8 +598,7 @@ export function TodayPanel({
|
|
|
340
598
|
return (
|
|
341
599
|
<div
|
|
342
600
|
className={cn(
|
|
343
|
-
'border-ph-border/70 rounded-2xl border bg-ph-surface p-
|
|
344
|
-
'hover:shadow-[0_8px_32px_-12px_rgba(15,23,42,0.18)] hover:-translate-y-0.5 motion-reduce:transition-none motion-reduce:hover:transform-none',
|
|
601
|
+
'border-ph-border/70 rounded-2xl border bg-ph-surface p-5 shadow-[0_1px_16px_-8px_rgba(15,23,42,0.12)] sm:p-5',
|
|
345
602
|
className,
|
|
346
603
|
)}
|
|
347
604
|
>
|
package/src/suite/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { TodayPageFrame } from
|
|
2
|
-
export * from
|
|
1
|
+
export { TodayPageFrame } from "./components/today-page-frame";
|
|
2
|
+
export * from "./components/today-ui";
|
|
3
3
|
export {
|
|
4
4
|
AppSwitcher,
|
|
5
5
|
AppSwitcherChevron,
|
|
@@ -8,32 +8,37 @@ export {
|
|
|
8
8
|
appSwitcherMenuItemClass,
|
|
9
9
|
appSwitcherTriggerClass,
|
|
10
10
|
type SuiteAppEntry,
|
|
11
|
-
} from
|
|
11
|
+
} from "./components/app-switcher";
|
|
12
12
|
export {
|
|
13
13
|
SuiteNotificationBell,
|
|
14
14
|
type SuiteNotification,
|
|
15
15
|
type SuiteNotificationsResponse,
|
|
16
|
-
} from
|
|
17
|
-
export { CommandPaletteHost } from
|
|
18
|
-
export { DeferredChrome } from
|
|
19
|
-
export { SuiteMobileDrawer } from
|
|
20
|
-
export { SuiteMobileHeader } from
|
|
16
|
+
} from "./components/suite-notification-bell";
|
|
17
|
+
export { CommandPaletteHost } from "./components/command-palette-host";
|
|
18
|
+
export { DeferredChrome } from "./components/deferred-chrome";
|
|
19
|
+
export { SuiteMobileDrawer } from "./components/suite-mobile-drawer";
|
|
20
|
+
export { SuiteMobileHeader } from "./components/suite-mobile-header";
|
|
21
|
+
export {
|
|
22
|
+
SuiteSettingsLayout,
|
|
23
|
+
type SuiteSettingsLayoutProps,
|
|
24
|
+
} from "./components/suite-settings-layout";
|
|
21
25
|
export {
|
|
22
26
|
SuiteUserMenu,
|
|
23
27
|
type SuiteUserMenuProps,
|
|
24
|
-
} from
|
|
28
|
+
} from "./components/suite-user-menu";
|
|
25
29
|
export {
|
|
26
30
|
SuiteBottomNav,
|
|
27
31
|
type SuiteBottomNavItem,
|
|
28
|
-
} from
|
|
32
|
+
} from "./components/suite-bottom-nav";
|
|
29
33
|
export {
|
|
30
34
|
SUITE_APPS,
|
|
31
35
|
SUITE_APP_MAP,
|
|
32
36
|
suiteAppBaseUrl,
|
|
37
|
+
resolveSuiteNotificationHref,
|
|
33
38
|
type SuiteAppDefinition,
|
|
34
39
|
type SuiteAppSlug,
|
|
35
|
-
} from
|
|
36
|
-
export { TodayCalibrating } from
|
|
40
|
+
} from "./lib/apps";
|
|
41
|
+
export { TodayCalibrating } from "./components/today-calibrating";
|
|
37
42
|
export {
|
|
38
43
|
SuiteThemeProvider,
|
|
39
44
|
useSuiteTheme,
|
|
@@ -41,11 +46,15 @@ export {
|
|
|
41
46
|
type SuiteTheme,
|
|
42
47
|
type SuiteThemeConfig,
|
|
43
48
|
type SuiteThemeContextValue,
|
|
44
|
-
} from
|
|
49
|
+
} from "./components/theme-provider";
|
|
45
50
|
export {
|
|
46
51
|
SuiteAiPanel,
|
|
52
|
+
openSuiteAskAi,
|
|
53
|
+
SUITE_OPEN_ASK_AI_EVENT,
|
|
47
54
|
type SuiteAiPreset,
|
|
48
|
-
|
|
55
|
+
type SuiteAiChatMessage,
|
|
56
|
+
type SuiteAskAiOpenDetail,
|
|
57
|
+
} from "./components/ai-panel";
|
|
49
58
|
export {
|
|
50
59
|
APP_ACCENTS,
|
|
51
60
|
APP_GLYPHS,
|
|
@@ -60,7 +69,7 @@ export {
|
|
|
60
69
|
type SuiteGlyphElement,
|
|
61
70
|
type SuiteIconName,
|
|
62
71
|
type SuiteIconProps,
|
|
63
|
-
} from
|
|
72
|
+
} from "./icons";
|
|
64
73
|
export type {
|
|
65
74
|
SuiteCommandItem,
|
|
66
75
|
SuiteCommandPaletteComponent,
|
|
@@ -68,15 +77,23 @@ export type {
|
|
|
68
77
|
SuiteDropdownMenuComponent,
|
|
69
78
|
SuiteDropdownMenuProps,
|
|
70
79
|
SuiteSpinnerComponent,
|
|
71
|
-
} from
|
|
72
|
-
export { useIdleMount } from
|
|
73
|
-
export {
|
|
80
|
+
} from "./lib/injected";
|
|
81
|
+
export { useIdleMount } from "./lib/use-idle-mount";
|
|
82
|
+
export {
|
|
83
|
+
SIDEBAR_COLLAPSE_THRESHOLD,
|
|
84
|
+
SIDEBAR_DEFAULT_WIDTH,
|
|
85
|
+
SIDEBAR_MAX_WIDTH,
|
|
86
|
+
SIDEBAR_MIN_EXPANDED_WIDTH,
|
|
87
|
+
SIDEBAR_RAIL_WIDTH,
|
|
88
|
+
useSidebarWidth,
|
|
89
|
+
} from "./lib/use-sidebar-width";
|
|
90
|
+
export { cn } from "./lib/cn";
|
|
74
91
|
export {
|
|
75
92
|
SuiteMotionProvider,
|
|
76
93
|
m,
|
|
77
94
|
SUITE_SPRINGS,
|
|
78
95
|
type SuiteSpringName,
|
|
79
|
-
} from
|
|
96
|
+
} from "./lib/motion";
|
|
80
97
|
export {
|
|
81
98
|
SuitePage,
|
|
82
99
|
SuitePageHeader,
|
|
@@ -86,23 +103,22 @@ export {
|
|
|
86
103
|
SuiteSectionHeader,
|
|
87
104
|
type SuitePageWidth,
|
|
88
105
|
type SuiteBreadcrumbsProps,
|
|
89
|
-
} from
|
|
106
|
+
} from "./components/suite-layout";
|
|
90
107
|
export {
|
|
91
108
|
SuiteSkeleton,
|
|
92
109
|
SuiteSkeletonCard,
|
|
93
110
|
SuiteSkeletonList,
|
|
94
111
|
SuiteEmptyState,
|
|
95
|
-
} from
|
|
112
|
+
} from "./components/suite-skeleton";
|
|
96
113
|
export {
|
|
97
114
|
SuiteSettingsMobileNav,
|
|
98
115
|
type SuiteSettingsNavItem,
|
|
99
|
-
} from
|
|
116
|
+
} from "./components/suite-settings-mobile-nav";
|
|
100
117
|
export {
|
|
101
118
|
SuiteSidebar,
|
|
102
119
|
type SuiteSidebarNavItem,
|
|
103
|
-
} from
|
|
120
|
+
} from "./components/suite-sidebar";
|
|
104
121
|
export {
|
|
105
122
|
SuiteAppLayout,
|
|
106
123
|
type SuiteAppLayoutProps,
|
|
107
|
-
} from
|
|
108
|
-
|
|
124
|
+
} from "./components/suite-app-layout";
|