proto-plugin 0.1.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/AGENTS.md +350 -0
- package/README.md +279 -0
- package/components.json +18 -0
- package/package.json +73 -0
- package/scripts/download-mobbin-reference-images.mjs +112 -0
- package/scripts/lib/host-config.example.sh +48 -0
- package/scripts/lib/host-config.sh +25 -0
- package/scripts/lib/resolve-host-root.mjs +18 -0
- package/scripts/lib/source-path.sh +49 -0
- package/scripts/link-source-db.sh +128 -0
- package/scripts/link-source.sh +40 -0
- package/scripts/publish-package.sh +147 -0
- package/scripts/share-prototype.sh +279 -0
- package/scripts/sync-from-source.sh +74 -0
- package/scripts/verify-prototype-component-ids.mjs +151 -0
- package/scripts/verify-prototype-preview-states.mjs +135 -0
- package/src/app.ts +4 -0
- package/src/components/platform-ui/code-block.tsx +21 -0
- package/src/components/platform-ui/controls-panel-options.tsx +71 -0
- package/src/components/platform-ui/controls-panel-select.tsx +438 -0
- package/src/components/platform-ui/empty-state.tsx +15 -0
- package/src/components/platform-ui/icon-button.tsx +18 -0
- package/src/components/platform-ui/panel-select.tsx +123 -0
- package/src/components/platform-ui/panel.tsx +97 -0
- package/src/components/platform-ui/review-dropdown-menu.tsx +35 -0
- package/src/components/platform-ui/sidebar.tsx +293 -0
- package/src/components/platform-ui/toolbar-icon-button.tsx +34 -0
- package/src/components/platform-ui/toolbar.tsx +37 -0
- package/src/components/prototype-gallery-client.tsx +57 -0
- package/src/components/prototype-provider.tsx +20 -0
- package/src/components/prototypes/mini-pill-label.tsx +37 -0
- package/src/components/prototypes/prototype-change-log-panel.tsx +207 -0
- package/src/components/prototypes/prototype-comment-provider.tsx +61 -0
- package/src/components/prototypes/prototype-comment-toolbar.tsx +65 -0
- package/src/components/prototypes/prototype-control.tsx +31 -0
- package/src/components/prototypes/prototype-controls.tsx +553 -0
- package/src/components/prototypes/prototype-create-exploration-modal.tsx +117 -0
- package/src/components/prototypes/prototype-create-state-modal.tsx +117 -0
- package/src/components/prototypes/prototype-default-state-map-page.tsx +66 -0
- package/src/components/prototypes/prototype-design-brief-modal.tsx +128 -0
- package/src/components/prototypes/prototype-design-brief-panel.tsx +525 -0
- package/src/components/prototypes/prototype-design-context-panel.tsx +65 -0
- package/src/components/prototypes/prototype-floating-pill.module.scss +1341 -0
- package/src/components/prototypes/prototype-mobbin-gallery.tsx +330 -0
- package/src/components/prototypes/prototype-reference-docs.tsx +222 -0
- package/src/components/prototypes/prototype-review-chrome.module.scss +630 -0
- package/src/components/prototypes/prototype-review-chrome.tsx +1241 -0
- package/src/components/prototypes/prototype-review-dropdown-menu-item.tsx +1 -0
- package/src/components/prototypes/prototype-review-dropdown-menu-separator.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-menu-item.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-menu-separator.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-select.tsx +4 -0
- package/src/components/prototypes/prototype-review-sidebar.tsx +167 -0
- package/src/components/prototypes/prototype-share-link-restore.tsx +75 -0
- package/src/components/prototypes/prototype-share-mode.tsx +206 -0
- package/src/components/prototypes/prototype-spec-panel-content.tsx +538 -0
- package/src/components/prototypes/prototype-state-canvas-overlay.module.scss +336 -0
- package/src/components/prototypes/prototype-state-canvas-overlay.tsx +1023 -0
- package/src/components/prototypes/prototype-state-canvas.tsx +38 -0
- package/src/components/prototypes/prototype-state-screenshot-preview.tsx +47 -0
- package/src/components/prototypes/prototype-target.tsx +120 -0
- package/src/components/prototypes/prototype-tweak-highlight.tsx +132 -0
- package/src/components/prototypes/prototype-tweaks.tsx +48 -0
- package/src/components/prototypes/prototype-variant-explorer.tsx +347 -0
- package/src/components/prototypes/prototype-variant-rationale-panel.tsx +49 -0
- package/src/components/prototypes/prototype-variant-tabs.tsx +207 -0
- package/src/components/prototypes/prototype-vercel-preview-modal.tsx +120 -0
- package/src/components/prototypes/state-map-annotation-tooltip.module.scss +89 -0
- package/src/components/prototypes/state-map-annotation-tooltip.tsx +137 -0
- package/src/components/prototypes/state-map-wireframe-highlight.module.scss +25 -0
- package/src/components/prototypes/state-map-wireframe-highlight.tsx +82 -0
- package/src/components/shell/prototype-gallery-shell.tsx +79 -0
- package/src/components/shell/prototype-screenshot-capture.tsx +45 -0
- package/src/components/shell/prototype-shell.module.scss +194 -0
- package/src/components/shell/prototype-shell.tsx +160 -0
- package/src/components/shell/prototype-state-screenshot-capture.tsx +68 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/dialog.module.scss +81 -0
- package/src/components/ui/dialog.tsx +127 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/option-select.tsx +81 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/slider.tsx +28 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/toggle-group.tsx +80 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/config/create-prototype-gallery-page.tsx +65 -0
- package/src/config/create-prototype-host-app.tsx +121 -0
- package/src/config/create-prototype-page.tsx +41 -0
- package/src/config/create-prototype-site-layout.tsx +28 -0
- package/src/config/define-prototype-config.ts +7 -0
- package/src/config/prototype-icon.tsx +25 -0
- package/src/config/prototype-site-layout-client.tsx +35 -0
- package/src/config/with-prototype.ts +20 -0
- package/src/index.ts +303 -0
- package/src/lib/pr-split/build-pr-agent-prompt.ts +68 -0
- package/src/lib/pr-split/build-pr-split-prototype-url.ts +12 -0
- package/src/lib/pr-split/pr-split-highlight.ts +6 -0
- package/src/lib/pr-split/pr-split-types.ts +58 -0
- package/src/lib/pr-split/resolve-source-preview-url.ts +45 -0
- package/src/lib/pr-split/use-pr-vercel-previews.ts +69 -0
- package/src/lib/prototype-comments/core/annotation-channel.ts +41 -0
- package/src/lib/prototype-comments/core/annotation-status.ts +60 -0
- package/src/lib/prototype-comments/core/annotation-target.ts +567 -0
- package/src/lib/prototype-comments/core/capture-theme.ts +41 -0
- package/src/lib/prototype-comments/core/capture.ts +11 -0
- package/src/lib/prototype-comments/core/comment-capture-blocked.ts +47 -0
- package/src/lib/prototype-comments/core/comment-threads.ts +52 -0
- package/src/lib/prototype-comments/core/element-identification.ts +615 -0
- package/src/lib/prototype-comments/core/export.ts +35 -0
- package/src/lib/prototype-comments/core/freeze-animations.ts +266 -0
- package/src/lib/prototype-comments/core/identify-element.ts +76 -0
- package/src/lib/prototype-comments/core/normalize-viewport.ts +35 -0
- package/src/lib/prototype-comments/core/react-detection.ts +704 -0
- package/src/lib/prototype-comments/core/restore.ts +7 -0
- package/src/lib/prototype-comments/core/screenshot.ts +428 -0
- package/src/lib/prototype-comments/core/source-location.ts +906 -0
- package/src/lib/prototype-comments/core/storage.ts +80 -0
- package/src/lib/prototype-comments/core/types.ts +79 -0
- package/src/lib/prototype-comments/core/validation.ts +17 -0
- package/src/lib/prototype-comments/hooks/useLayoutShift.ts +61 -0
- package/src/lib/prototype-comments/index.ts +58 -0
- package/src/lib/prototype-comments/react/CommentCaptureToolbar.tsx +1398 -0
- package/src/lib/prototype-comments/react/CommentProvider.tsx +298 -0
- package/src/lib/prototype-comments/scss.d.ts +10 -0
- package/src/lib/prototype-comments/ui/CommentAnnotationOverlay.tsx +253 -0
- package/src/lib/prototype-comments/ui/CommentDetailPage.tsx +56 -0
- package/src/lib/prototype-comments/ui/CommentHeaderCount.tsx +28 -0
- package/src/lib/prototype-comments/ui/CommentThread.tsx +331 -0
- package/src/lib/prototype-comments/ui/CommentsGrid.tsx +780 -0
- package/src/lib/prototype-comments/ui/CommentsListPage.tsx +25 -0
- package/src/lib/prototype-comments/ui/CommentsSidebar.tsx +77 -0
- package/src/lib/prototype-comments/ui/annotation-marker/index.tsx +200 -0
- package/src/lib/prototype-comments/ui/annotation-marker/styles.module.scss +194 -0
- package/src/lib/prototype-comments/ui/annotation-popup/index.tsx +335 -0
- package/src/lib/prototype-comments/ui/annotation-popup/styles.module.scss +469 -0
- package/src/lib/prototype-comments/ui/capture-styles.module.scss +2225 -0
- package/src/lib/prototype-comments/ui/comment-highlight.ts +48 -0
- package/src/lib/prototype-comments/ui/comment-thread.module.scss +203 -0
- package/src/lib/prototype-comments/ui/comments-grid-card.module.scss +253 -0
- package/src/lib/prototype-comments/ui/comments-sidebar.module.scss +123 -0
- package/src/lib/prototype-comments/ui/icon-transitions.module.scss +51 -0
- package/src/lib/prototype-comments/ui/icons.tsx +1086 -0
- package/src/lib/prototype-comments/ui/is-comment-detail-path.ts +7 -0
- package/src/lib/prototypes/capture-prototype-viewport.ts +32 -0
- package/src/lib/prototypes/changelog-meta-context.tsx +162 -0
- package/src/lib/prototypes/changelog-meta-storage.ts +62 -0
- package/src/lib/prototypes/changelog-meta.ts +95 -0
- package/src/lib/prototypes/create-prototype-registry.ts +74 -0
- package/src/lib/prototypes/create-state-screenshot-thumbnail.ts +46 -0
- package/src/lib/prototypes/design-exploration-default-storage.ts +68 -0
- package/src/lib/prototypes/design-exploration-default.ts +51 -0
- package/src/lib/prototypes/design-exploration-types.ts +203 -0
- package/src/lib/prototypes/prototype-comment-registry.tsx +145 -0
- package/src/lib/prototypes/prototype-comment-review-bridge.tsx +40 -0
- package/src/lib/prototypes/prototype-comment-review-state.ts +57 -0
- package/src/lib/prototypes/prototype-component-registry.ts +40 -0
- package/src/lib/prototypes/prototype-config-types.ts +34 -0
- package/src/lib/prototypes/prototype-preview-state-registry.ts +443 -0
- package/src/lib/prototypes/prototype-preview-state-types.ts +89 -0
- package/src/lib/prototypes/prototype-review-context.tsx +905 -0
- package/src/lib/prototypes/prototype-review-url.ts +134 -0
- package/src/lib/prototypes/prototype-share-link.ts +175 -0
- package/src/lib/prototypes/prototype-state-canvas-constants.ts +118 -0
- package/src/lib/prototypes/prototype-state-canvas-types.ts +159 -0
- package/src/lib/prototypes/prototype-state-screenshot.ts +39 -0
- package/src/lib/prototypes/prototype-tweak-registry.ts +96 -0
- package/src/lib/prototypes/prototype-tweak-types.ts +31 -0
- package/src/lib/prototypes/reference-docs.ts +137 -0
- package/src/lib/prototypes/screenshot-manifest.ts +33 -0
- package/src/lib/prototypes/screenshot-src.ts +7 -0
- package/src/lib/prototypes/share-command.ts +8 -0
- package/src/lib/prototypes/state-map-annotation.ts +70 -0
- package/src/lib/prototypes/use-design-exploration-default.ts +114 -0
- package/src/lib/prototypes/use-persisted-local-state.ts +140 -0
- package/src/lib/prototypes/use-prototype-comments.ts +63 -0
- package/src/lib/prototypes/use-prototype-mobile-viewport-frame.ts +46 -0
- package/src/lib/prototypes/use-prototype-state-screenshot-src.ts +71 -0
- package/src/lib/prototypes/use-prototype-tool-theme.tsx +115 -0
- package/src/lib/prototypes/use-prototype-viewport-frame.ts +34 -0
- package/src/lib/prototypes/use-register-prototype-reference-docs.ts +16 -0
- package/src/lib/prototypes/use-snap-corner-position.ts +417 -0
- package/src/lib/prototypes/use-toolbar-hover-panel.ts +98 -0
- package/src/lib/prototypes/variant-set-lucide-icon.tsx +55 -0
- package/src/lib/tool-portal.ts +33 -0
- package/src/lib/use-copy-to-clipboard.ts +81 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/vercel-preview/parse-vercel-github-comment.ts +81 -0
- package/src/server/create-host-api-route.ts +100 -0
- package/src/server/create-prototype-api-routes.ts +428 -0
- package/src/server/gallery/create-gallery-api.ts +56 -0
- package/src/server/gallery/folders-route.ts +156 -0
- package/src/server/gallery/gallery-env.ts +39 -0
- package/src/server/gallery/gallery-route.ts +150 -0
- package/src/server/gallery/gallery-types.ts +15 -0
- package/src/server/gallery/image-route.ts +59 -0
- package/src/server/gallery/item-route.ts +92 -0
- package/src/server/pr-vercel-preview-route.ts +162 -0
- package/src/server/redis/client.ts +55 -0
- package/src/server/redis/prototype-changelog-meta.ts +31 -0
- package/src/server/redis/prototype-comments.ts +92 -0
- package/src/server/redis/prototype-design-exploration-default.ts +32 -0
- package/src/server.ts +51 -0
- package/src/styles/globals.css +624 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogClose,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogTitle,
|
|
8
|
+
} from "@prototype/components/ui/dialog";
|
|
9
|
+
import { buildCreatePreviewStateCopyText } from "@prototype/lib/prototypes/prototype-preview-state-types";
|
|
10
|
+
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
11
|
+
import { X } from "lucide-react";
|
|
12
|
+
import { useEffect, useState } from "react";
|
|
13
|
+
|
|
14
|
+
const MODAL_CHROME_BUTTON_CLASS =
|
|
15
|
+
"text-muted-foreground hover:text-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-sm border-0 bg-transparent p-0 opacity-70 transition-opacity duration-200 ease hover:opacity-100 outline-none focus:outline-hidden focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-40 disabled:hover:opacity-40 disabled:hover:text-muted-foreground motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
16
|
+
|
|
17
|
+
const BRIEF_TEXTAREA_CLASS =
|
|
18
|
+
"field-sizing-content min-h-[min(50vh,20rem)] w-full resize-y border-0 bg-transparent px-0 py-0 text-sm leading-relaxed text-foreground shadow-none outline-none placeholder:text-muted-foreground focus-visible:ring-0";
|
|
19
|
+
|
|
20
|
+
export type PrototypeCreateStateModalProps = {
|
|
21
|
+
open: boolean;
|
|
22
|
+
onOpenChange: (open: boolean) => void;
|
|
23
|
+
slug: string;
|
|
24
|
+
existingStates: Array<{ id: string; label: string }>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function PrototypeCreateStateModal({
|
|
28
|
+
open,
|
|
29
|
+
onOpenChange,
|
|
30
|
+
slug,
|
|
31
|
+
existingStates,
|
|
32
|
+
}: PrototypeCreateStateModalProps) {
|
|
33
|
+
const [brief, setBrief] = useState("");
|
|
34
|
+
const { copy, icon, isCopied } = useCopyToClipboard();
|
|
35
|
+
const canCopy = brief.trim().length > 0;
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!open) {
|
|
39
|
+
setBrief("");
|
|
40
|
+
}
|
|
41
|
+
}, [open]);
|
|
42
|
+
|
|
43
|
+
const handleCopy = () => {
|
|
44
|
+
if (!canCopy) return;
|
|
45
|
+
|
|
46
|
+
const origin =
|
|
47
|
+
typeof window !== "undefined" ? window.location.origin : undefined;
|
|
48
|
+
copy(
|
|
49
|
+
buildCreatePreviewStateCopyText({
|
|
50
|
+
slug,
|
|
51
|
+
existingStates,
|
|
52
|
+
origin,
|
|
53
|
+
briefText: brief,
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
60
|
+
<DialogContent
|
|
61
|
+
showCloseButton={false}
|
|
62
|
+
className="tool-dialog-surface flex max-h-[min(92svh,calc(100%-2rem))] w-[min(42rem,calc(100vw-2rem))] max-w-[min(42rem,calc(100vw-2rem))] flex-col gap-0 overflow-hidden border-0 p-0 sm:max-w-[min(42rem,calc(100vw-2rem))]"
|
|
63
|
+
>
|
|
64
|
+
<div className="flex items-start justify-between gap-3 px-5 py-4">
|
|
65
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
66
|
+
<DialogTitle className="text-base font-medium text-foreground">
|
|
67
|
+
New state
|
|
68
|
+
</DialogTitle>
|
|
69
|
+
<p className="text-sm text-muted-foreground">
|
|
70
|
+
Describe a page state to add — loading, empty, error, or any other
|
|
71
|
+
preview mode.
|
|
72
|
+
</p>
|
|
73
|
+
</div>
|
|
74
|
+
<DialogClose className={MODAL_CHROME_BUTTON_CLASS}>
|
|
75
|
+
<X />
|
|
76
|
+
<span className="sr-only">Close</span>
|
|
77
|
+
</DialogClose>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div
|
|
81
|
+
className="h-px w-full shrink-0 bg-border"
|
|
82
|
+
role="separator"
|
|
83
|
+
aria-hidden
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto px-5 py-4">
|
|
87
|
+
<textarea
|
|
88
|
+
value={brief}
|
|
89
|
+
onChange={(event) => setBrief(event.target.value)}
|
|
90
|
+
placeholder="e.g. Add an empty state when the user has no API keys yet"
|
|
91
|
+
aria-label="State brief"
|
|
92
|
+
className={BRIEF_TEXTAREA_CLASS}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div
|
|
97
|
+
className="h-px w-full shrink-0 bg-border"
|
|
98
|
+
role="separator"
|
|
99
|
+
aria-hidden
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
<div className="flex items-center justify-end gap-2 px-5 py-4">
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
disabled={!canCopy}
|
|
106
|
+
onClick={handleCopy}
|
|
107
|
+
className="inline-flex h-9 items-center gap-2 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors duration-200 ease hover:bg-primary-dark disabled:pointer-events-none disabled:opacity-50"
|
|
108
|
+
aria-label="Copy state brief and prompt"
|
|
109
|
+
>
|
|
110
|
+
{isCopied ? "Copied" : "Copy prompt"}
|
|
111
|
+
{icon}
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</DialogContent>
|
|
115
|
+
</Dialog>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { EmptyState } from "@prototype/components/platform-ui/empty-state";
|
|
4
|
+
import { PrototypeStateCanvasRegistrar } from "@prototype/components/prototypes/prototype-state-canvas";
|
|
5
|
+
import {
|
|
6
|
+
getDefaultPrototypeStateMapPath,
|
|
7
|
+
parseStateMapReturnTo,
|
|
8
|
+
} from "@prototype/lib/prototypes/prototype-state-canvas-types";
|
|
9
|
+
import Link from "next/link";
|
|
10
|
+
import { useSearchParams } from "next/navigation";
|
|
11
|
+
import { useMemo } from "react";
|
|
12
|
+
import { X } from "lucide-react";
|
|
13
|
+
|
|
14
|
+
import styles from "./prototype-state-canvas-overlay.module.scss";
|
|
15
|
+
|
|
16
|
+
type PrototypeDefaultStateMapPageProps = {
|
|
17
|
+
slug: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function PrototypeDefaultStateMapPage({
|
|
21
|
+
slug,
|
|
22
|
+
}: PrototypeDefaultStateMapPageProps) {
|
|
23
|
+
const searchParams = useSearchParams();
|
|
24
|
+
const pagePath = getDefaultPrototypeStateMapPath(slug);
|
|
25
|
+
const prototypePath = `/prototypes/${slug}`;
|
|
26
|
+
|
|
27
|
+
const backHref = useMemo(() => {
|
|
28
|
+
const returnTo = parseStateMapReturnTo(searchParams);
|
|
29
|
+
if (returnTo) return returnTo;
|
|
30
|
+
return prototypePath;
|
|
31
|
+
}, [prototypePath, searchParams]);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
className={styles.page}
|
|
36
|
+
data-prototype-state-canvas
|
|
37
|
+
data-prototype-default-state-map
|
|
38
|
+
>
|
|
39
|
+
<PrototypeStateCanvasRegistrar pagePath={pagePath} />
|
|
40
|
+
|
|
41
|
+
<div className={styles.header}>
|
|
42
|
+
<div>
|
|
43
|
+
<p className={styles.headerTitle}>State map</p>
|
|
44
|
+
<p className={styles.headerHint}>
|
|
45
|
+
Map prototype preview states once this prototype defines them.
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
48
|
+
<Link
|
|
49
|
+
href={backHref}
|
|
50
|
+
className={styles.closeButton}
|
|
51
|
+
aria-label="Back to prototype"
|
|
52
|
+
>
|
|
53
|
+
<X size={16} strokeWidth={2} />
|
|
54
|
+
</Link>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div className="flex flex-1 items-center justify-center px-6">
|
|
58
|
+
<EmptyState className="max-w-md text-center">
|
|
59
|
+
No states mapped yet. Add a state canvas config and register this route
|
|
60
|
+
in `prototype.config.ts`, or follow the example-feature reference in
|
|
61
|
+
AGENTS.md.
|
|
62
|
+
</EmptyState>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { PrototypeComponent } from "@prototype/components/prototypes/prototype-target";
|
|
4
|
+
import { PrototypeDesignBriefPanel } from "@prototype/components/prototypes/prototype-design-brief-panel";
|
|
5
|
+
import {
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogClose,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
} from "@prototype/components/ui/dialog";
|
|
11
|
+
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
12
|
+
import { buildBriefOverviewCopyText } from "@prototype/lib/prototypes/design-exploration-types";
|
|
13
|
+
import type {
|
|
14
|
+
DesignExplorationBrief,
|
|
15
|
+
DesignExplorationContext,
|
|
16
|
+
DesignExplorationMobbin,
|
|
17
|
+
DesignExplorationRationale,
|
|
18
|
+
DesignExplorationVariantOption,
|
|
19
|
+
DesignExplorationVariantsSection,
|
|
20
|
+
} from "@prototype/lib/prototypes/design-exploration-types";
|
|
21
|
+
import { usePersistedLocalString } from "@prototype/lib/prototypes/use-persisted-local-state";
|
|
22
|
+
import type { ReactNode } from "react";
|
|
23
|
+
import { X } from "lucide-react";
|
|
24
|
+
|
|
25
|
+
const MODAL_CHROME_BUTTON_CLASS =
|
|
26
|
+
"text-muted-foreground hover:text-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-sm border-0 bg-transparent p-0 opacity-70 transition-opacity hover:opacity-100 outline-none focus:outline-hidden focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-40 disabled:hover:opacity-40 disabled:hover:text-muted-foreground motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
27
|
+
|
|
28
|
+
type PrototypeDesignBriefModalProps<TVariant extends string> = {
|
|
29
|
+
open: boolean;
|
|
30
|
+
onOpenChange: (open: boolean) => void;
|
|
31
|
+
componentIdPrefix: string;
|
|
32
|
+
galleryId: string;
|
|
33
|
+
storageKeyPrefix: string;
|
|
34
|
+
brief: DesignExplorationBrief;
|
|
35
|
+
context?: DesignExplorationContext;
|
|
36
|
+
mobbin?: DesignExplorationMobbin;
|
|
37
|
+
variantsSection?: DesignExplorationVariantsSection;
|
|
38
|
+
variant: TVariant;
|
|
39
|
+
onVariantChange: (variant: TVariant) => void;
|
|
40
|
+
options: DesignExplorationVariantOption<TVariant>[];
|
|
41
|
+
rationale: Record<TVariant, DesignExplorationRationale>;
|
|
42
|
+
renderers: Record<TVariant, () => ReactNode>;
|
|
43
|
+
defaultVariantValue?: TVariant;
|
|
44
|
+
onSetDefaultVariant?: (value: TVariant) => void;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export function PrototypeDesignBriefModal<TVariant extends string>({
|
|
48
|
+
open,
|
|
49
|
+
onOpenChange,
|
|
50
|
+
componentIdPrefix,
|
|
51
|
+
galleryId,
|
|
52
|
+
storageKeyPrefix,
|
|
53
|
+
brief,
|
|
54
|
+
context,
|
|
55
|
+
mobbin,
|
|
56
|
+
variantsSection,
|
|
57
|
+
variant,
|
|
58
|
+
onVariantChange,
|
|
59
|
+
options,
|
|
60
|
+
rationale,
|
|
61
|
+
renderers,
|
|
62
|
+
defaultVariantValue,
|
|
63
|
+
onSetDefaultVariant,
|
|
64
|
+
}: PrototypeDesignBriefModalProps<TVariant>) {
|
|
65
|
+
const { copy: copyOverview, icon: copyIcon } = useCopyToClipboard();
|
|
66
|
+
const { value: title } = usePersistedLocalString(
|
|
67
|
+
`${storageKeyPrefix}-overview-title`,
|
|
68
|
+
brief.titleDefault,
|
|
69
|
+
);
|
|
70
|
+
const { value: description } = usePersistedLocalString(
|
|
71
|
+
`${storageKeyPrefix}-overview-description`,
|
|
72
|
+
brief.descriptionDefault,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const effectiveTitle = title.trim() || brief.titleDefault;
|
|
76
|
+
const effectiveDescription =
|
|
77
|
+
description.trim() || brief.descriptionDefault;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
81
|
+
<DialogContent
|
|
82
|
+
className="tool-dialog-surface flex h-[min(92svh,calc(100%-2rem))] max-h-[min(92svh,calc(100%-2rem))] w-[min(96rem,calc(100vw-2rem))] max-w-[min(96rem,calc(100vw-2rem))] flex-col gap-0 overflow-hidden border-0 p-0 sm:max-w-[min(96rem,calc(100vw-2rem))]"
|
|
83
|
+
>
|
|
84
|
+
<div className="tool-dialog-accent" aria-hidden />
|
|
85
|
+
<div className="absolute top-4 right-4 z-10 flex items-center gap-0.5">
|
|
86
|
+
<PrototypeComponent id={`${componentIdPrefix}.overview-copy-brief`}>
|
|
87
|
+
<button
|
|
88
|
+
type="button"
|
|
89
|
+
className={MODAL_CHROME_BUTTON_CLASS}
|
|
90
|
+
onClick={() =>
|
|
91
|
+
copyOverview(
|
|
92
|
+
buildBriefOverviewCopyText(effectiveTitle, effectiveDescription),
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
aria-label="Copy overview"
|
|
96
|
+
>
|
|
97
|
+
{copyIcon}
|
|
98
|
+
</button>
|
|
99
|
+
</PrototypeComponent>
|
|
100
|
+
<DialogClose className={MODAL_CHROME_BUTTON_CLASS}>
|
|
101
|
+
<X />
|
|
102
|
+
<span className="sr-only">Close</span>
|
|
103
|
+
</DialogClose>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<DialogTitle className="sr-only">{effectiveTitle}</DialogTitle>
|
|
107
|
+
|
|
108
|
+
<PrototypeDesignBriefPanel
|
|
109
|
+
componentIdPrefix={componentIdPrefix}
|
|
110
|
+
galleryId={galleryId}
|
|
111
|
+
storageKeyPrefix={storageKeyPrefix}
|
|
112
|
+
brief={brief}
|
|
113
|
+
context={context}
|
|
114
|
+
mobbin={mobbin}
|
|
115
|
+
variantsSection={variantsSection}
|
|
116
|
+
variant={variant}
|
|
117
|
+
onVariantChange={onVariantChange}
|
|
118
|
+
options={options}
|
|
119
|
+
rationale={rationale}
|
|
120
|
+
renderers={renderers}
|
|
121
|
+
defaultVariantValue={defaultVariantValue}
|
|
122
|
+
onSetDefaultVariant={onSetDefaultVariant}
|
|
123
|
+
className="overflow-y-auto overscroll-contain"
|
|
124
|
+
/>
|
|
125
|
+
</DialogContent>
|
|
126
|
+
</Dialog>
|
|
127
|
+
);
|
|
128
|
+
}
|