proto-plugin 0.1.0 → 0.1.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/AGENTS.md +308 -29
- package/README.md +55 -13
- package/package.json +1 -1
- package/scripts/lib/host-config.example.sh +1 -1
- package/scripts/publish-package.sh +41 -0
- package/scripts/verify-prototype-preview-states.mjs +57 -0
- package/src/components/platform-ui/controls-panel-select.tsx +4 -3
- package/src/components/platform-ui/prototype-tool-dialog.tsx +117 -0
- package/src/components/platform-ui/sidebar.tsx +34 -16
- package/src/components/prototype-gallery-client.tsx +77 -37
- package/src/components/prototypes/design-exploration-variant-preview-shell.tsx +43 -0
- package/src/components/prototypes/prototype-brief-field.tsx +33 -0
- package/src/components/prototypes/prototype-change-log-panel.tsx +4 -0
- package/src/components/prototypes/prototype-comment-storage-empty-state.tsx +41 -0
- package/src/components/prototypes/prototype-create-exploration-modal.tsx +41 -64
- package/src/components/prototypes/prototype-create-prototype-modal.tsx +102 -0
- package/src/components/prototypes/prototype-create-state-modal.tsx +31 -70
- package/src/components/prototypes/prototype-default-state-map-page.tsx +4 -4
- package/src/components/prototypes/prototype-design-brief-modal.tsx +10 -10
- package/src/components/prototypes/prototype-design-brief-panel.tsx +261 -231
- package/src/components/prototypes/prototype-floating-pill.module.scss +16 -9
- package/src/components/prototypes/prototype-mobbin-gallery.tsx +18 -2
- package/src/components/prototypes/prototype-review-sidebar.tsx +11 -28
- package/src/components/prototypes/prototype-spec-panel-content.tsx +5 -5
- package/src/components/prototypes/prototype-spec-panel-empty-state.tsx +53 -0
- package/src/components/prototypes/prototype-state-canvas-overlay.module.scss +20 -47
- package/src/components/prototypes/prototype-state-canvas-overlay.tsx +4 -42
- package/src/components/prototypes/prototype-variant-explorer.tsx +32 -78
- package/src/components/prototypes/prototype-vercel-preview-modal.tsx +4 -3
- package/src/components/prototypes/state-map-annotation-tooltip.module.scss +7 -7
- package/src/components/shell/prototype-component-library-empty-state.tsx +59 -0
- package/src/components/shell/prototype-gallery-nav.tsx +124 -0
- package/src/components/shell/prototype-gallery-shell.tsx +45 -13
- package/src/components/shell/prototype-link-source-modal.tsx +100 -0
- package/src/components/ui/button.tsx +3 -1
- package/src/components/ui/dialog.tsx +43 -4
- package/src/config/create-prototype-component-library-page.tsx +74 -0
- package/src/config/create-prototype-gallery-page.tsx +26 -23
- package/src/config/create-prototype-host-app.tsx +3 -15
- package/src/config/create-prototype-site-layout.tsx +14 -1
- package/src/config/create-prototype-state-map-page.tsx +44 -0
- package/src/config/prototype-site-layout-client.tsx +20 -6
- package/src/config/with-prototype.ts +21 -0
- package/src/index.ts +54 -10
- package/src/lib/copy-text-with-attachments.ts +35 -0
- package/src/lib/format-source-directory-name.ts +12 -0
- package/src/lib/platform-ui/sidebar-interactive-cursor.ts +19 -0
- package/src/lib/pr-split/build-pr-split-plan-prompt.ts +81 -0
- package/src/lib/pr-split/pr-split-highlight.ts +3 -0
- package/src/lib/prototype-comments/core/annotation-target.ts +12 -3
- package/src/lib/prototype-comments/core/comment-capture-blocked.ts +24 -0
- package/src/lib/prototype-comments/core/screenshot.ts +68 -31
- package/src/lib/prototype-comments/core/storage.ts +3 -6
- package/src/lib/prototype-comments/core/types.ts +2 -0
- package/src/lib/prototype-comments/hooks/useLayoutShift.ts +9 -2
- package/src/lib/prototype-comments/react/CommentCaptureToolbar.tsx +45 -10
- package/src/lib/prototype-comments/react/CommentProvider.tsx +19 -0
- package/src/lib/prototype-comments/ui/CommentModeToggleButton.tsx +34 -0
- package/src/lib/prototype-comments/ui/CommentsGrid.tsx +8 -16
- package/src/lib/prototype-comments/ui/CommentsSidebar.tsx +5 -19
- package/src/lib/prototype-comments/ui/capture-styles.module.scss +5 -1
- package/src/lib/prototype-comments/ui/comments-grid-card.module.scss +0 -7
- package/src/lib/prototypes/build-design-exploration-renderers.ts +44 -0
- package/src/lib/prototypes/comment-storage-setup-prompt.ts +124 -0
- package/src/lib/prototypes/create-prototype-prompt.ts +96 -0
- package/src/lib/prototypes/create-prototype-registry.ts +5 -0
- package/src/lib/prototypes/design-exploration-types.ts +261 -10
- package/src/lib/prototypes/link-source-prompt.ts +93 -0
- package/src/lib/prototypes/populate-component-library-prompt.ts +64 -0
- package/src/lib/prototypes/prototype-config-types.ts +2 -0
- package/src/lib/prototypes/prototype-layout-classes.ts +19 -0
- package/src/lib/prototypes/prototype-preview-state-registry.ts +5 -2
- package/src/lib/prototypes/prototype-review-context.tsx +4 -4
- package/src/lib/prototypes/prototype-state-canvas-constants.ts +1 -1
- package/src/lib/prototypes/prototype-state-canvas-types.ts +0 -2
- package/src/lib/prototypes/prototype-storage-status.ts +31 -0
- package/src/lib/prototypes/sort-prototypes-by-creation-date.ts +43 -0
- package/src/lib/prototypes/use-prototype-tool-theme.tsx +1 -1
- package/src/lib/prototypes/use-toolbar-hover-panel.ts +12 -1
- package/src/lib/prototypes/variant-set-lucide-icon.tsx +24 -0
- package/src/lib/tool-portal.ts +24 -0
- package/src/lib/use-copy-to-clipboard.ts +7 -13
- package/src/server/create-host-api-route.ts +7 -16
- package/src/server/create-prototype-api-routes.ts +0 -115
- package/src/server/prototype-storage-status-route.ts +29 -0
- package/src/server.ts +0 -8
- package/src/styles/globals.css +359 -71
- package/src/lib/prototypes/design-exploration-default-storage.ts +0 -68
- package/src/lib/prototypes/design-exploration-default.ts +0 -51
- package/src/lib/prototypes/use-design-exploration-default.ts +0 -114
- package/src/server/redis/prototype-design-exploration-default.ts +0 -32
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DialogTitle,
|
|
8
|
-
} from "@prototype/components/ui/dialog";
|
|
3
|
+
import { PrototypeToolDialog } from "@prototype/components/platform-ui/prototype-tool-dialog";
|
|
4
|
+
import { PrototypeBriefTextarea } from "@prototype/components/prototypes/prototype-brief-field";
|
|
5
|
+
import { Button } from "@prototype/components/ui/button";
|
|
6
|
+
import { Switch } from "@prototype/components/ui/switch";
|
|
9
7
|
import { buildCreateDesignExplorationCopyText } from "@prototype/lib/prototypes/design-exploration-types";
|
|
10
8
|
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
11
|
-
import { X } from "lucide-react";
|
|
12
9
|
import { useEffect, useState } from "react";
|
|
13
10
|
|
|
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
11
|
export type PrototypeCreateExplorationModalProps = {
|
|
21
12
|
open: boolean;
|
|
22
13
|
onOpenChange: (open: boolean) => void;
|
|
@@ -31,6 +22,7 @@ export function PrototypeCreateExplorationModal({
|
|
|
31
22
|
existingExplorations,
|
|
32
23
|
}: PrototypeCreateExplorationModalProps) {
|
|
33
24
|
const [brief, setBrief] = useState("");
|
|
25
|
+
const [includeMobbin, setIncludeMobbin] = useState(true);
|
|
34
26
|
const { copy, icon, isCopied } = useCopyToClipboard();
|
|
35
27
|
const canCopy = brief.trim().length > 0;
|
|
36
28
|
|
|
@@ -51,67 +43,52 @@ export function PrototypeCreateExplorationModal({
|
|
|
51
43
|
existingExplorations,
|
|
52
44
|
origin,
|
|
53
45
|
briefText: brief,
|
|
46
|
+
includeMobbin,
|
|
54
47
|
}),
|
|
55
48
|
);
|
|
56
49
|
};
|
|
57
50
|
|
|
58
51
|
return (
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
</
|
|
78
|
-
|
|
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. Give me a settings page with a profile picture, name, plan, and bio"
|
|
91
|
-
aria-label="Exploration 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
|
|
52
|
+
<PrototypeToolDialog
|
|
53
|
+
open={open}
|
|
54
|
+
onOpenChange={onOpenChange}
|
|
55
|
+
title="New exploration"
|
|
56
|
+
description="Describe what you're trying to build, and we'll give you a few different versions."
|
|
57
|
+
footerClassName="justify-between gap-4"
|
|
58
|
+
footer={
|
|
59
|
+
<>
|
|
60
|
+
<label className="flex cursor-pointer items-center gap-2">
|
|
61
|
+
<Switch
|
|
62
|
+
checked={includeMobbin}
|
|
63
|
+
onCheckedChange={setIncludeMobbin}
|
|
64
|
+
aria-label="Gather references from Mobbin"
|
|
65
|
+
className="data-[state=checked]:bg-foreground"
|
|
66
|
+
/>
|
|
67
|
+
<span className="text-sm text-muted-foreground">
|
|
68
|
+
Gather references from Mobbin
|
|
69
|
+
</span>
|
|
70
|
+
</label>
|
|
71
|
+
<Button
|
|
104
72
|
type="button"
|
|
73
|
+
variant="chrome"
|
|
74
|
+
size="sm"
|
|
75
|
+
className="h-8 gap-1.5"
|
|
105
76
|
disabled={!canCopy}
|
|
106
77
|
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
78
|
aria-label="Copy exploration brief and prompt"
|
|
109
79
|
>
|
|
110
|
-
{isCopied ? "Copied" : "Copy prompt"}
|
|
80
|
+
{isCopied ? "Copied prompt" : "Copy prompt"}
|
|
111
81
|
{icon}
|
|
112
|
-
</
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
82
|
+
</Button>
|
|
83
|
+
</>
|
|
84
|
+
}
|
|
85
|
+
>
|
|
86
|
+
<PrototypeBriefTextarea
|
|
87
|
+
value={brief}
|
|
88
|
+
onChange={(event) => setBrief(event.target.value)}
|
|
89
|
+
placeholder="e.g. Give me a settings page with a profile picture, name, plan, and bio"
|
|
90
|
+
aria-label="Exploration brief"
|
|
91
|
+
/>
|
|
92
|
+
</PrototypeToolDialog>
|
|
116
93
|
);
|
|
117
94
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { PrototypeToolDialog } from "@prototype/components/platform-ui/prototype-tool-dialog";
|
|
4
|
+
import { Button } from "@prototype/components/ui/button";
|
|
5
|
+
import { Input } from "@prototype/components/ui/input";
|
|
6
|
+
import { Label } from "@prototype/components/ui/label";
|
|
7
|
+
import {
|
|
8
|
+
PROTOTYPE_BRIEF_FIELD_BORDER_CLASS,
|
|
9
|
+
PrototypeBriefTextarea,
|
|
10
|
+
} from "@prototype/components/prototypes/prototype-brief-field";
|
|
11
|
+
import { buildCreatePrototypeCopyText } from "@prototype/lib/prototypes/create-prototype-prompt";
|
|
12
|
+
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
13
|
+
import { useEffect, useId, useState } from "react";
|
|
14
|
+
|
|
15
|
+
export type PrototypeCreatePrototypeModalProps = {
|
|
16
|
+
open: boolean;
|
|
17
|
+
onOpenChange: (open: boolean) => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function PrototypeCreatePrototypeModal({
|
|
21
|
+
open,
|
|
22
|
+
onOpenChange,
|
|
23
|
+
}: PrototypeCreatePrototypeModalProps) {
|
|
24
|
+
const titleFieldId = useId();
|
|
25
|
+
const descriptionFieldId = useId();
|
|
26
|
+
const [title, setTitle] = useState("");
|
|
27
|
+
const [description, setDescription] = useState("");
|
|
28
|
+
const { copy, icon, isCopied } = useCopyToClipboard();
|
|
29
|
+
const canCopy = title.trim().length > 0 && description.trim().length > 0;
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!open) {
|
|
33
|
+
setTitle("");
|
|
34
|
+
setDescription("");
|
|
35
|
+
}
|
|
36
|
+
}, [open]);
|
|
37
|
+
|
|
38
|
+
const handleCopy = () => {
|
|
39
|
+
if (!canCopy) return;
|
|
40
|
+
|
|
41
|
+
const origin =
|
|
42
|
+
typeof window !== "undefined" ? window.location.origin : undefined;
|
|
43
|
+
|
|
44
|
+
copy(
|
|
45
|
+
buildCreatePrototypeCopyText({
|
|
46
|
+
title,
|
|
47
|
+
description,
|
|
48
|
+
origin,
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<PrototypeToolDialog
|
|
55
|
+
open={open}
|
|
56
|
+
onOpenChange={onOpenChange}
|
|
57
|
+
title="New prototype"
|
|
58
|
+
description="Name the prototype and describe what you want to build, then copy the prompt into your agent to scaffold it."
|
|
59
|
+
bodyClassName="gap-4"
|
|
60
|
+
footerClassName="justify-end"
|
|
61
|
+
footer={
|
|
62
|
+
<Button
|
|
63
|
+
type="button"
|
|
64
|
+
variant="chrome"
|
|
65
|
+
size="sm"
|
|
66
|
+
className="h-8 gap-1.5"
|
|
67
|
+
disabled={!canCopy}
|
|
68
|
+
onClick={handleCopy}
|
|
69
|
+
aria-label="Copy prototype brief and prompt"
|
|
70
|
+
>
|
|
71
|
+
{isCopied ? "Copied prompt" : "Copy prompt"}
|
|
72
|
+
{icon}
|
|
73
|
+
</Button>
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
<div className="flex flex-col gap-1.5">
|
|
77
|
+
<Label htmlFor={titleFieldId} className="text-foreground">
|
|
78
|
+
Title
|
|
79
|
+
</Label>
|
|
80
|
+
<Input
|
|
81
|
+
id={titleFieldId}
|
|
82
|
+
value={title}
|
|
83
|
+
onChange={(event) => setTitle(event.target.value)}
|
|
84
|
+
placeholder="ex. Team Settings"
|
|
85
|
+
className={PROTOTYPE_BRIEF_FIELD_BORDER_CLASS}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
<div className="flex min-h-0 flex-1 flex-col gap-1.5">
|
|
89
|
+
<Label htmlFor={descriptionFieldId} className="text-foreground">
|
|
90
|
+
Description
|
|
91
|
+
</Label>
|
|
92
|
+
<PrototypeBriefTextarea
|
|
93
|
+
id={descriptionFieldId}
|
|
94
|
+
value={description}
|
|
95
|
+
onChange={(event) => setDescription(event.target.value)}
|
|
96
|
+
placeholder="ex. Replicate the team settings page from the source app — members list, invite flow, and role badges."
|
|
97
|
+
aria-label="Prototype description"
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
</PrototypeToolDialog>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
DialogContent,
|
|
7
|
-
DialogTitle,
|
|
8
|
-
} from "@prototype/components/ui/dialog";
|
|
3
|
+
import { PrototypeToolDialog } from "@prototype/components/platform-ui/prototype-tool-dialog";
|
|
4
|
+
import { PrototypeBriefTextarea } from "@prototype/components/prototypes/prototype-brief-field";
|
|
5
|
+
import { Button } from "@prototype/components/ui/button";
|
|
9
6
|
import { buildCreatePreviewStateCopyText } from "@prototype/lib/prototypes/prototype-preview-state-types";
|
|
10
7
|
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
11
|
-
import { X } from "lucide-react";
|
|
12
8
|
import { useEffect, useState } from "react";
|
|
13
9
|
|
|
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
10
|
export type PrototypeCreateStateModalProps = {
|
|
21
11
|
open: boolean;
|
|
22
12
|
onOpenChange: (open: boolean) => void;
|
|
@@ -56,62 +46,33 @@ export function PrototypeCreateStateModal({
|
|
|
56
46
|
};
|
|
57
47
|
|
|
58
48
|
return (
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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>
|
|
49
|
+
<PrototypeToolDialog
|
|
50
|
+
open={open}
|
|
51
|
+
onOpenChange={onOpenChange}
|
|
52
|
+
title="New state"
|
|
53
|
+
description="Describe a page state to add — loading, empty, error, or any other preview mode."
|
|
54
|
+
footerClassName="justify-end"
|
|
55
|
+
footer={
|
|
56
|
+
<Button
|
|
57
|
+
type="button"
|
|
58
|
+
variant="chrome"
|
|
59
|
+
size="sm"
|
|
60
|
+
className="h-8 gap-1.5"
|
|
61
|
+
disabled={!canCopy}
|
|
62
|
+
onClick={handleCopy}
|
|
63
|
+
aria-label="Copy state brief and prompt"
|
|
64
|
+
>
|
|
65
|
+
{isCopied ? "Copied prompt" : "Copy prompt"}
|
|
66
|
+
{icon}
|
|
67
|
+
</Button>
|
|
68
|
+
}
|
|
69
|
+
>
|
|
70
|
+
<PrototypeBriefTextarea
|
|
71
|
+
value={brief}
|
|
72
|
+
onChange={(event) => setBrief(event.target.value)}
|
|
73
|
+
placeholder="e.g. Add an empty state when the user has no API keys yet"
|
|
74
|
+
aria-label="State brief"
|
|
75
|
+
/>
|
|
76
|
+
</PrototypeToolDialog>
|
|
116
77
|
);
|
|
117
78
|
}
|
|
@@ -42,7 +42,7 @@ export function PrototypeDefaultStateMapPage({
|
|
|
42
42
|
<div>
|
|
43
43
|
<p className={styles.headerTitle}>State map</p>
|
|
44
44
|
<p className={styles.headerHint}>
|
|
45
|
-
|
|
45
|
+
Preview states appear here once this prototype defines a state map.
|
|
46
46
|
</p>
|
|
47
47
|
</div>
|
|
48
48
|
<Link
|
|
@@ -56,9 +56,9 @@ export function PrototypeDefaultStateMapPage({
|
|
|
56
56
|
|
|
57
57
|
<div className="flex flex-1 items-center justify-center px-6">
|
|
58
58
|
<EmptyState className="max-w-md text-center">
|
|
59
|
-
No states
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
No preview states yet. When this prototype adds a `*-preview-states.ts`
|
|
60
|
+
registry, wire a state map page per AGENTS.md — until then this map stays
|
|
61
|
+
empty.
|
|
62
62
|
</EmptyState>
|
|
63
63
|
</div>
|
|
64
64
|
</div>
|
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
DialogContent,
|
|
9
9
|
DialogTitle,
|
|
10
10
|
} from "@prototype/components/ui/dialog";
|
|
11
|
+
import { PROTOTYPE_TOOL_MODAL_CLOSE_CLASS } from "@prototype/components/platform-ui/prototype-tool-dialog";
|
|
11
12
|
import useCopyToClipboard from "@prototype/lib/use-copy-to-clipboard";
|
|
12
13
|
import { buildBriefOverviewCopyText } from "@prototype/lib/prototypes/design-exploration-types";
|
|
13
14
|
import type {
|
|
15
|
+
DesignExplorationBaselineOption,
|
|
14
16
|
DesignExplorationBrief,
|
|
15
17
|
DesignExplorationContext,
|
|
16
18
|
DesignExplorationMobbin,
|
|
17
|
-
DesignExplorationRationale,
|
|
18
19
|
DesignExplorationVariantOption,
|
|
19
20
|
DesignExplorationVariantsSection,
|
|
20
21
|
} from "@prototype/lib/prototypes/design-exploration-types";
|
|
@@ -22,8 +23,7 @@ import { usePersistedLocalString } from "@prototype/lib/prototypes/use-persisted
|
|
|
22
23
|
import type { ReactNode } from "react";
|
|
23
24
|
import { X } from "lucide-react";
|
|
24
25
|
|
|
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";
|
|
26
|
+
const MODAL_CHROME_BUTTON_CLASS = PROTOTYPE_TOOL_MODAL_CLOSE_CLASS;
|
|
27
27
|
|
|
28
28
|
type PrototypeDesignBriefModalProps<TVariant extends string> = {
|
|
29
29
|
open: boolean;
|
|
@@ -38,10 +38,10 @@ type PrototypeDesignBriefModalProps<TVariant extends string> = {
|
|
|
38
38
|
variant: TVariant;
|
|
39
39
|
onVariantChange: (variant: TVariant) => void;
|
|
40
40
|
options: DesignExplorationVariantOption<TVariant>[];
|
|
41
|
-
rationale: Record<TVariant, DesignExplorationRationale>;
|
|
42
41
|
renderers: Record<TVariant, () => ReactNode>;
|
|
42
|
+
baseline: DesignExplorationBaselineOption<TVariant>;
|
|
43
43
|
defaultVariantValue?: TVariant;
|
|
44
|
-
|
|
44
|
+
briefConfigFilePath?: string;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
export function PrototypeDesignBriefModal<TVariant extends string>({
|
|
@@ -57,10 +57,10 @@ export function PrototypeDesignBriefModal<TVariant extends string>({
|
|
|
57
57
|
variant,
|
|
58
58
|
onVariantChange,
|
|
59
59
|
options,
|
|
60
|
-
rationale,
|
|
61
60
|
renderers,
|
|
61
|
+
baseline,
|
|
62
62
|
defaultVariantValue,
|
|
63
|
-
|
|
63
|
+
briefConfigFilePath,
|
|
64
64
|
}: PrototypeDesignBriefModalProps<TVariant>) {
|
|
65
65
|
const { copy: copyOverview, icon: copyIcon } = useCopyToClipboard();
|
|
66
66
|
const { value: title } = usePersistedLocalString(
|
|
@@ -79,9 +79,9 @@ export function PrototypeDesignBriefModal<TVariant extends string>({
|
|
|
79
79
|
return (
|
|
80
80
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
81
81
|
<DialogContent
|
|
82
|
+
portalScope="tool"
|
|
82
83
|
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
|
>
|
|
84
|
-
<div className="tool-dialog-accent" aria-hidden />
|
|
85
85
|
<div className="absolute top-4 right-4 z-10 flex items-center gap-0.5">
|
|
86
86
|
<PrototypeComponent id={`${componentIdPrefix}.overview-copy-brief`}>
|
|
87
87
|
<button
|
|
@@ -116,10 +116,10 @@ export function PrototypeDesignBriefModal<TVariant extends string>({
|
|
|
116
116
|
variant={variant}
|
|
117
117
|
onVariantChange={onVariantChange}
|
|
118
118
|
options={options}
|
|
119
|
-
rationale={rationale}
|
|
120
119
|
renderers={renderers}
|
|
120
|
+
baseline={baseline}
|
|
121
121
|
defaultVariantValue={defaultVariantValue}
|
|
122
|
-
|
|
122
|
+
briefConfigFilePath={briefConfigFilePath}
|
|
123
123
|
className="overflow-y-auto overscroll-contain"
|
|
124
124
|
/>
|
|
125
125
|
</DialogContent>
|