@open-aippt/core 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/bin.js +2 -0
- package/dist/build-DxTqmvsO.js +17 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +86 -0
- package/dist/config-CjzqjrEA.js +4280 -0
- package/dist/config-DIC-yVPp.d.ts +23 -0
- package/dist/design-cpzS8aud.js +35 -0
- package/dist/dev-BYuTeJbA.js +20 -0
- package/dist/format-BCeKbTOM.js +1605 -0
- package/dist/index.d.ts +134 -0
- package/dist/index.js +467 -0
- package/dist/locale/index.d.ts +24 -0
- package/dist/locale/index.js +3 -0
- package/dist/preview-DlQvnJPq.js +18 -0
- package/dist/sync-BPZ0m27m.js +139 -0
- package/dist/sync-EsYusbbL.js +3 -0
- package/dist/types-CHmFPIG_.d.ts +430 -0
- package/dist/vite/index.d.ts +14 -0
- package/dist/vite/index.js +4 -0
- package/env.d.ts +59 -0
- package/package.json +103 -0
- package/skills/apply-comments/SKILL.md +83 -0
- package/skills/create-slide/SKILL.md +91 -0
- package/skills/create-theme/SKILL.md +250 -0
- package/skills/current-slide/SKILL.md +110 -0
- package/skills/slide-authoring/SKILL.md +625 -0
- package/src/app/app.tsx +47 -0
- package/src/app/components/asset-view.tsx +966 -0
- package/src/app/components/history-provider.tsx +120 -0
- package/src/app/components/image-placeholder.tsx +243 -0
- package/src/app/components/inspector/asset-picker-dialog.tsx +196 -0
- package/src/app/components/inspector/comment-widget.tsx +93 -0
- package/src/app/components/inspector/image-crop-dialog.tsx +212 -0
- package/src/app/components/inspector/inspect-overlay.tsx +387 -0
- package/src/app/components/inspector/inspector-panel.tsx +1115 -0
- package/src/app/components/inspector/inspector-provider.tsx +1218 -0
- package/src/app/components/inspector/save-bar.tsx +48 -0
- package/src/app/components/language-toggle.tsx +39 -0
- package/src/app/components/notes-drawer.tsx +120 -0
- package/src/app/components/overview-grid.tsx +363 -0
- package/src/app/components/panel/panel-fields.tsx +60 -0
- package/src/app/components/panel/panel-shell.tsx +80 -0
- package/src/app/components/panel/save-card.tsx +142 -0
- package/src/app/components/pdf-progress-toast.tsx +32 -0
- package/src/app/components/player.tsx +466 -0
- package/src/app/components/pptx-progress-toast.tsx +32 -0
- package/src/app/components/present/blackout-overlay.tsx +18 -0
- package/src/app/components/present/control-bar.tsx +315 -0
- package/src/app/components/present/help-overlay.tsx +57 -0
- package/src/app/components/present/jump-input.tsx +74 -0
- package/src/app/components/present/laser-pointer.tsx +39 -0
- package/src/app/components/present/progress-bar.tsx +26 -0
- package/src/app/components/present/use-idle.ts +46 -0
- package/src/app/components/present/use-pointer-near-bottom.ts +34 -0
- package/src/app/components/present/use-presenter-channel.ts +66 -0
- package/src/app/components/present/use-touch-swipe.ts +66 -0
- package/src/app/components/shared-element.tsx +48 -0
- package/src/app/components/sidebar/folder-item.tsx +258 -0
- package/src/app/components/sidebar/icon-picker.tsx +61 -0
- package/src/app/components/sidebar/mobile-pill.tsx +34 -0
- package/src/app/components/sidebar/sidebar-footer.tsx +105 -0
- package/src/app/components/sidebar/sidebar.tsx +284 -0
- package/src/app/components/slide-canvas.tsx +102 -0
- package/src/app/components/slide-transition-layer.tsx +844 -0
- package/src/app/components/style-panel/design-provider.tsx +148 -0
- package/src/app/components/style-panel/style-panel.tsx +349 -0
- package/src/app/components/style-panel/use-design.ts +112 -0
- package/src/app/components/theme-toggle.tsx +59 -0
- package/src/app/components/themes/theme-detail.tsx +305 -0
- package/src/app/components/themes/themes-gallery.tsx +149 -0
- package/src/app/components/thumbnail-rail.tsx +805 -0
- package/src/app/components/ui/badge.tsx +45 -0
- package/src/app/components/ui/button.tsx +99 -0
- package/src/app/components/ui/card.tsx +92 -0
- package/src/app/components/ui/context-menu.tsx +237 -0
- package/src/app/components/ui/dialog.tsx +157 -0
- package/src/app/components/ui/dropdown-menu.tsx +245 -0
- package/src/app/components/ui/input.tsx +25 -0
- package/src/app/components/ui/label.tsx +24 -0
- package/src/app/components/ui/popover.tsx +75 -0
- package/src/app/components/ui/progress.tsx +31 -0
- package/src/app/components/ui/scroll-area.tsx +53 -0
- package/src/app/components/ui/select.tsx +196 -0
- package/src/app/components/ui/separator.tsx +28 -0
- package/src/app/components/ui/slider.tsx +61 -0
- package/src/app/components/ui/sonner.tsx +48 -0
- package/src/app/components/ui/tabs.tsx +79 -0
- package/src/app/components/ui/textarea.tsx +22 -0
- package/src/app/components/ui/toggle-group.tsx +83 -0
- package/src/app/components/ui/toggle.tsx +45 -0
- package/src/app/components/ui/tooltip.tsx +58 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/index.html +13 -0
- package/src/app/lib/assets.ts +242 -0
- package/src/app/lib/design-presets.ts +94 -0
- package/src/app/lib/design.ts +58 -0
- package/src/app/lib/export-html.ts +326 -0
- package/src/app/lib/export-pdf.ts +298 -0
- package/src/app/lib/export-pptx.ts +284 -0
- package/src/app/lib/folders.ts +239 -0
- package/src/app/lib/inspector/fiber.test.ts +154 -0
- package/src/app/lib/inspector/fiber.ts +85 -0
- package/src/app/lib/inspector/use-comments.ts +74 -0
- package/src/app/lib/inspector/use-editor.ts +73 -0
- package/src/app/lib/inspector/use-notes.ts +134 -0
- package/src/app/lib/locale-store.ts +67 -0
- package/src/app/lib/page-context.tsx +38 -0
- package/src/app/lib/print-ready.test.ts +32 -0
- package/src/app/lib/print-ready.ts +51 -0
- package/src/app/lib/sdk.test.ts +13 -0
- package/src/app/lib/sdk.ts +37 -0
- package/src/app/lib/slides.ts +26 -0
- package/src/app/lib/step-context.tsx +261 -0
- package/src/app/lib/themes.ts +22 -0
- package/src/app/lib/transition.ts +30 -0
- package/src/app/lib/use-agent-socket.ts +18 -0
- package/src/app/lib/use-click-page-navigation.ts +60 -0
- package/src/app/lib/use-is-mobile.ts +21 -0
- package/src/app/lib/use-locale.ts +8 -0
- package/src/app/lib/use-prefers-reduced-motion.ts +19 -0
- package/src/app/lib/use-slide-module.ts +48 -0
- package/src/app/lib/use-wheel-page-navigation.ts +99 -0
- package/src/app/lib/utils.test.ts +25 -0
- package/src/app/lib/utils.ts +6 -0
- package/src/app/main.tsx +14 -0
- package/src/app/routes/assets.tsx +9 -0
- package/src/app/routes/home-shell.tsx +213 -0
- package/src/app/routes/home.tsx +807 -0
- package/src/app/routes/presenter.tsx +418 -0
- package/src/app/routes/slide.tsx +1108 -0
- package/src/app/routes/themes.tsx +34 -0
- package/src/app/styles.css +429 -0
- package/src/app/virtual.d.ts +51 -0
- package/src/locale/en.ts +416 -0
- package/src/locale/format.ts +12 -0
- package/src/locale/index.ts +6 -0
- package/src/locale/ja.ts +422 -0
- package/src/locale/types.ts +443 -0
- package/src/locale/zh-cn.ts +414 -0
- package/src/locale/zh-tw.ts +414 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { Slot } from 'radix-ui';
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
|
|
13
|
+
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
|
|
14
|
+
destructive:
|
|
15
|
+
'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20',
|
|
16
|
+
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
|
|
17
|
+
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
|
|
18
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: 'default',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
function Badge({
|
|
28
|
+
className,
|
|
29
|
+
variant = 'default',
|
|
30
|
+
asChild = false,
|
|
31
|
+
...props
|
|
32
|
+
}: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
33
|
+
const Comp = asChild ? Slot.Root : 'span';
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Comp
|
|
37
|
+
data-slot="badge"
|
|
38
|
+
data-variant={variant}
|
|
39
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { Slot } from 'radix-ui';
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Editorial button. Tight square-ish radius, hairline borders instead of
|
|
9
|
+
* shadcn's default ring/shadow stack. The default variant is the strongest
|
|
10
|
+
* affordance — solid ink with subtle inner highlight on hover so the press
|
|
11
|
+
* feels physical without glow.
|
|
12
|
+
*/
|
|
13
|
+
const buttonVariants = cva(
|
|
14
|
+
[
|
|
15
|
+
"group/button relative inline-flex shrink-0 items-center justify-center",
|
|
16
|
+
"rounded-[6px] text-[13px] font-medium whitespace-nowrap select-none",
|
|
17
|
+
"outline-none transition-[background-color,color,border-color,box-shadow,transform] duration-100",
|
|
18
|
+
"focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
19
|
+
"active:not-aria-[haspopup]:translate-y-px",
|
|
20
|
+
"disabled:pointer-events-none disabled:opacity-45",
|
|
21
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/30",
|
|
22
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
23
|
+
].join(' '),
|
|
24
|
+
{
|
|
25
|
+
variants: {
|
|
26
|
+
variant: {
|
|
27
|
+
default: [
|
|
28
|
+
'bg-foreground text-background',
|
|
29
|
+
'shadow-[inset_0_1px_0_oklch(1_0_0/0.12),0_1px_0_oklch(0_0_0/0.12)]',
|
|
30
|
+
'hover:bg-foreground/90',
|
|
31
|
+
'aria-expanded:bg-foreground/85',
|
|
32
|
+
].join(' '),
|
|
33
|
+
brand: [
|
|
34
|
+
'bg-brand text-brand-foreground',
|
|
35
|
+
'shadow-[inset_0_1px_0_oklch(1_0_0/0.18),0_1px_0_oklch(0_0_0/0.16)]',
|
|
36
|
+
'hover:brightness-105 active:brightness-95',
|
|
37
|
+
].join(' '),
|
|
38
|
+
outline: [
|
|
39
|
+
'border border-border bg-card text-foreground',
|
|
40
|
+
'hover:bg-muted/60 hover:border-foreground/20',
|
|
41
|
+
'aria-expanded:bg-muted aria-expanded:border-foreground/25',
|
|
42
|
+
'data-[state=on]:bg-foreground data-[state=on]:text-background data-[state=on]:border-foreground',
|
|
43
|
+
].join(' '),
|
|
44
|
+
secondary:
|
|
45
|
+
'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary/90',
|
|
46
|
+
ghost: [
|
|
47
|
+
'text-foreground/75 hover:text-foreground hover:bg-muted',
|
|
48
|
+
'aria-expanded:bg-muted aria-expanded:text-foreground',
|
|
49
|
+
].join(' '),
|
|
50
|
+
destructive: [
|
|
51
|
+
'bg-destructive text-white',
|
|
52
|
+
'shadow-[inset_0_1px_0_oklch(1_0_0/0.16),0_1px_0_oklch(0_0_0/0.12)]',
|
|
53
|
+
'hover:brightness-105 active:brightness-95',
|
|
54
|
+
'focus-visible:ring-destructive/35',
|
|
55
|
+
].join(' '),
|
|
56
|
+
link: 'text-foreground underline decoration-foreground/30 decoration-1 underline-offset-[3px] hover:decoration-foreground/70 [&_svg]:hidden',
|
|
57
|
+
},
|
|
58
|
+
size: {
|
|
59
|
+
default: 'h-8 gap-1.5 px-3',
|
|
60
|
+
xs: 'h-6 gap-1 rounded-[5px] px-2 text-[11.5px]',
|
|
61
|
+
sm: 'h-7 gap-1.5 rounded-[5px] px-2.5 text-[12px]',
|
|
62
|
+
lg: 'h-9 gap-1.5 px-3.5 text-[13.5px]',
|
|
63
|
+
icon: 'size-8',
|
|
64
|
+
'icon-xs': 'size-6 rounded-[5px]',
|
|
65
|
+
'icon-sm': 'size-7 rounded-[5px]',
|
|
66
|
+
'icon-lg': 'size-9',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
defaultVariants: {
|
|
70
|
+
variant: 'default',
|
|
71
|
+
size: 'default',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
function Button({
|
|
77
|
+
className,
|
|
78
|
+
variant = 'default',
|
|
79
|
+
size = 'default',
|
|
80
|
+
asChild = false,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<'button'> &
|
|
83
|
+
VariantProps<typeof buttonVariants> & {
|
|
84
|
+
asChild?: boolean;
|
|
85
|
+
}) {
|
|
86
|
+
const Comp = asChild ? Slot.Root : 'button';
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Comp
|
|
90
|
+
data-slot="button"
|
|
91
|
+
data-variant={variant}
|
|
92
|
+
data-size={size}
|
|
93
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
function Card({
|
|
6
|
+
className,
|
|
7
|
+
size = 'default',
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card"
|
|
13
|
+
data-size={size}
|
|
14
|
+
className={cn(
|
|
15
|
+
'group/card flex flex-col gap-4 overflow-hidden rounded-[10px] bg-card py-4 text-sm text-card-foreground border border-border has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-[10px] *:[img:last-child]:rounded-b-[10px]',
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
data-slot="card-header"
|
|
27
|
+
className={cn(
|
|
28
|
+
'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3',
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
data-slot="card-title"
|
|
40
|
+
className={cn(
|
|
41
|
+
'font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm',
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-slot="card-description"
|
|
53
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
data-slot="card-action"
|
|
63
|
+
className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
70
|
+
return (
|
|
71
|
+
<div
|
|
72
|
+
data-slot="card-content"
|
|
73
|
+
className={cn('px-4 group-data-[size=sm]/card:px-3', className)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
data-slot="card-footer"
|
|
83
|
+
className={cn(
|
|
84
|
+
'flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3',
|
|
85
|
+
className,
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
|
|
5
|
+
import { ContextMenu as ContextMenuPrimitive } from 'radix-ui';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
function ContextMenu({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
|
|
10
|
+
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function ContextMenuTrigger({
|
|
14
|
+
...props
|
|
15
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
|
|
16
|
+
return <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ContextMenuGroup({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
|
|
20
|
+
return <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ContextMenuPortal({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
|
|
24
|
+
return <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function ContextMenuSub({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
|
|
28
|
+
return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ContextMenuRadioGroup({
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
|
|
34
|
+
return <ContextMenuPrimitive.RadioGroup data-slot="context-menu-radio-group" {...props} />;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ContextMenuSubTrigger({
|
|
38
|
+
className,
|
|
39
|
+
inset,
|
|
40
|
+
children,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
|
|
43
|
+
inset?: boolean;
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<ContextMenuPrimitive.SubTrigger
|
|
47
|
+
data-slot="context-menu-sub-trigger"
|
|
48
|
+
data-inset={inset}
|
|
49
|
+
className={cn(
|
|
50
|
+
'flex cursor-default items-center gap-2 rounded-[5px] px-2 py-1.5 text-[12.5px] outline-hidden select-none focus:bg-foreground focus:text-background data-[inset]:pl-8 data-[state=open]:bg-muted',
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
<ChevronRightIcon className="ml-auto size-3.5 opacity-60" />
|
|
57
|
+
</ContextMenuPrimitive.SubTrigger>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function ContextMenuSubContent({
|
|
62
|
+
className,
|
|
63
|
+
...props
|
|
64
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
|
|
65
|
+
return (
|
|
66
|
+
<ContextMenuPrimitive.SubContent
|
|
67
|
+
data-slot="context-menu-sub-content"
|
|
68
|
+
className={cn(
|
|
69
|
+
'z-50 min-w-[9rem] overflow-hidden rounded-[8px] border border-border bg-popover p-1 text-popover-foreground shadow-floating',
|
|
70
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
71
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
72
|
+
className,
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function ContextMenuContent({
|
|
80
|
+
className,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
|
|
83
|
+
return (
|
|
84
|
+
<ContextMenuPrimitive.Portal>
|
|
85
|
+
<ContextMenuPrimitive.Content
|
|
86
|
+
data-slot="context-menu-content"
|
|
87
|
+
className={cn(
|
|
88
|
+
'z-50 max-h-(--radix-context-menu-content-available-height) min-w-[9rem] origin-(--radix-context-menu-content-transform-origin)',
|
|
89
|
+
'overflow-x-hidden overflow-y-auto rounded-[8px] border border-border bg-popover p-1 text-popover-foreground shadow-floating',
|
|
90
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
91
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
</ContextMenuPrimitive.Portal>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function ContextMenuItem({
|
|
101
|
+
className,
|
|
102
|
+
inset,
|
|
103
|
+
variant = 'default',
|
|
104
|
+
...props
|
|
105
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
|
|
106
|
+
inset?: boolean;
|
|
107
|
+
variant?: 'default' | 'destructive';
|
|
108
|
+
}) {
|
|
109
|
+
return (
|
|
110
|
+
<ContextMenuPrimitive.Item
|
|
111
|
+
data-slot="context-menu-item"
|
|
112
|
+
data-inset={inset}
|
|
113
|
+
data-variant={variant}
|
|
114
|
+
className={cn(
|
|
115
|
+
'relative flex cursor-default items-center gap-2 rounded-[5px] px-2 py-1.5 text-[12.5px] outline-hidden select-none transition-colors',
|
|
116
|
+
'focus:bg-foreground focus:text-background',
|
|
117
|
+
'data-[active=true]:bg-muted data-[active=true]:text-foreground',
|
|
118
|
+
'data-[disabled]:pointer-events-none data-[disabled]:opacity-45 data-[inset]:pl-8',
|
|
119
|
+
'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive data-[variant=destructive]:focus:text-white',
|
|
120
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-current [&_svg]:opacity-80",
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function ContextMenuCheckboxItem({
|
|
129
|
+
className,
|
|
130
|
+
children,
|
|
131
|
+
checked,
|
|
132
|
+
...props
|
|
133
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
|
|
134
|
+
return (
|
|
135
|
+
<ContextMenuPrimitive.CheckboxItem
|
|
136
|
+
data-slot="context-menu-checkbox-item"
|
|
137
|
+
className={cn(
|
|
138
|
+
'relative flex cursor-default items-center gap-2 rounded-[5px] py-1.5 pr-2 pl-8 text-[12.5px] outline-hidden select-none focus:bg-foreground focus:text-background data-[disabled]:pointer-events-none data-[disabled]:opacity-45',
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
checked={checked}
|
|
142
|
+
{...props}
|
|
143
|
+
>
|
|
144
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
145
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
146
|
+
<CheckIcon className="size-3.5" />
|
|
147
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
148
|
+
</span>
|
|
149
|
+
{children}
|
|
150
|
+
</ContextMenuPrimitive.CheckboxItem>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function ContextMenuRadioItem({
|
|
155
|
+
className,
|
|
156
|
+
children,
|
|
157
|
+
...props
|
|
158
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
|
|
159
|
+
return (
|
|
160
|
+
<ContextMenuPrimitive.RadioItem
|
|
161
|
+
data-slot="context-menu-radio-item"
|
|
162
|
+
className={cn(
|
|
163
|
+
'relative flex cursor-default items-center gap-2 rounded-[5px] py-1.5 pr-2 pl-8 text-[12.5px] outline-hidden select-none focus:bg-foreground focus:text-background data-[disabled]:pointer-events-none data-[disabled]:opacity-45',
|
|
164
|
+
className,
|
|
165
|
+
)}
|
|
166
|
+
{...props}
|
|
167
|
+
>
|
|
168
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
169
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
170
|
+
<CircleIcon className="size-2 fill-current" />
|
|
171
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
172
|
+
</span>
|
|
173
|
+
{children}
|
|
174
|
+
</ContextMenuPrimitive.RadioItem>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function ContextMenuLabel({
|
|
179
|
+
className,
|
|
180
|
+
inset,
|
|
181
|
+
...props
|
|
182
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
|
|
183
|
+
inset?: boolean;
|
|
184
|
+
}) {
|
|
185
|
+
return (
|
|
186
|
+
<ContextMenuPrimitive.Label
|
|
187
|
+
data-slot="context-menu-label"
|
|
188
|
+
data-inset={inset}
|
|
189
|
+
className={cn('eyebrow px-2 py-1.5 data-[inset]:pl-8', className)}
|
|
190
|
+
{...props}
|
|
191
|
+
/>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function ContextMenuSeparator({
|
|
196
|
+
className,
|
|
197
|
+
...props
|
|
198
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
|
|
199
|
+
return (
|
|
200
|
+
<ContextMenuPrimitive.Separator
|
|
201
|
+
data-slot="context-menu-separator"
|
|
202
|
+
className={cn('-mx-1 my-1 h-px bg-hairline', className)}
|
|
203
|
+
{...props}
|
|
204
|
+
/>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function ContextMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
209
|
+
return (
|
|
210
|
+
<span
|
|
211
|
+
data-slot="context-menu-shortcut"
|
|
212
|
+
className={cn(
|
|
213
|
+
'ml-auto font-mono text-[10.5px] tracking-[0.06em] text-muted-foreground/80',
|
|
214
|
+
className,
|
|
215
|
+
)}
|
|
216
|
+
{...props}
|
|
217
|
+
/>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export {
|
|
222
|
+
ContextMenu,
|
|
223
|
+
ContextMenuTrigger,
|
|
224
|
+
ContextMenuContent,
|
|
225
|
+
ContextMenuItem,
|
|
226
|
+
ContextMenuCheckboxItem,
|
|
227
|
+
ContextMenuRadioItem,
|
|
228
|
+
ContextMenuLabel,
|
|
229
|
+
ContextMenuSeparator,
|
|
230
|
+
ContextMenuShortcut,
|
|
231
|
+
ContextMenuGroup,
|
|
232
|
+
ContextMenuPortal,
|
|
233
|
+
ContextMenuSub,
|
|
234
|
+
ContextMenuSubContent,
|
|
235
|
+
ContextMenuSubTrigger,
|
|
236
|
+
ContextMenuRadioGroup,
|
|
237
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { XIcon } from 'lucide-react';
|
|
2
|
+
import { Dialog as DialogPrimitive } from 'radix-ui';
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
8
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
12
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
16
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
20
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function DialogOverlay({
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
27
|
+
return (
|
|
28
|
+
<DialogPrimitive.Overlay
|
|
29
|
+
data-slot="dialog-overlay"
|
|
30
|
+
className={cn(
|
|
31
|
+
'fixed inset-0 z-50 bg-foreground/35 backdrop-blur-[2px] data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0',
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function DialogContent({
|
|
40
|
+
className,
|
|
41
|
+
children,
|
|
42
|
+
showCloseButton = true,
|
|
43
|
+
container,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
46
|
+
showCloseButton?: boolean;
|
|
47
|
+
container?: React.ComponentProps<typeof DialogPrimitive.Portal>['container'];
|
|
48
|
+
}) {
|
|
49
|
+
return (
|
|
50
|
+
<DialogPortal data-slot="dialog-portal" container={container}>
|
|
51
|
+
<DialogOverlay />
|
|
52
|
+
<DialogPrimitive.Content
|
|
53
|
+
data-slot="dialog-content"
|
|
54
|
+
className={cn(
|
|
55
|
+
// Crisp paper card with hairline edge + soft drop. No oversized
|
|
56
|
+
// shadcn-glow ring; sits cleanly on the dimmed canvas.
|
|
57
|
+
'fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-5',
|
|
58
|
+
'rounded-[10px] border border-border bg-card p-6 text-card-foreground',
|
|
59
|
+
'shadow-overlay outline-none',
|
|
60
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
61
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
62
|
+
'duration-200 sm:max-w-md',
|
|
63
|
+
className,
|
|
64
|
+
)}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
{showCloseButton && (
|
|
69
|
+
<DialogPrimitive.Close
|
|
70
|
+
data-slot="dialog-close"
|
|
71
|
+
aria-label="Close"
|
|
72
|
+
className="absolute top-3.5 right-3.5 inline-flex size-7 items-center justify-center rounded-[5px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40"
|
|
73
|
+
>
|
|
74
|
+
<XIcon className="size-3.5" />
|
|
75
|
+
<span className="sr-only">Close</span>
|
|
76
|
+
</DialogPrimitive.Close>
|
|
77
|
+
)}
|
|
78
|
+
</DialogPrimitive.Content>
|
|
79
|
+
</DialogPortal>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-slot="dialog-header"
|
|
87
|
+
className={cn('flex flex-col gap-1.5 text-left', className)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function DialogFooter({
|
|
94
|
+
className,
|
|
95
|
+
showCloseButton = false,
|
|
96
|
+
children,
|
|
97
|
+
...props
|
|
98
|
+
}: React.ComponentProps<'div'> & {
|
|
99
|
+
showCloseButton?: boolean;
|
|
100
|
+
}) {
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
data-slot="dialog-footer"
|
|
104
|
+
className={cn(
|
|
105
|
+
'flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:justify-end sm:gap-1.5',
|
|
106
|
+
className,
|
|
107
|
+
)}
|
|
108
|
+
{...props}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
{showCloseButton && (
|
|
112
|
+
<DialogPrimitive.Close asChild>
|
|
113
|
+
<Button variant="outline">Close</Button>
|
|
114
|
+
</DialogPrimitive.Close>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
121
|
+
return (
|
|
122
|
+
<DialogPrimitive.Title
|
|
123
|
+
data-slot="dialog-title"
|
|
124
|
+
className={cn(
|
|
125
|
+
'font-heading text-[15px] font-semibold leading-tight tracking-tight text-foreground',
|
|
126
|
+
className,
|
|
127
|
+
)}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function DialogDescription({
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
137
|
+
return (
|
|
138
|
+
<DialogPrimitive.Description
|
|
139
|
+
data-slot="dialog-description"
|
|
140
|
+
className={cn('text-[13px] leading-relaxed text-muted-foreground', className)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export {
|
|
147
|
+
Dialog,
|
|
148
|
+
DialogClose,
|
|
149
|
+
DialogContent,
|
|
150
|
+
DialogDescription,
|
|
151
|
+
DialogFooter,
|
|
152
|
+
DialogHeader,
|
|
153
|
+
DialogOverlay,
|
|
154
|
+
DialogPortal,
|
|
155
|
+
DialogTitle,
|
|
156
|
+
DialogTrigger,
|
|
157
|
+
};
|