Skip to content

Commit 13bdc09

Browse files
authored
feat: generate from image option with no slices (#1727)
1 parent a0761ff commit 13bdc09

5 files changed

Lines changed: 119 additions & 87 deletions

File tree

packages/manager/src/managers/customTypes/CustomTypesManager.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ import {
4949
readdir,
5050
} from "node:fs/promises";
5151
import { query as queryClaude } from "@anthropic-ai/claude-agent-sdk";
52-
import { APPLICATION_MODE } from "../../constants/APPLICATION_MODE";
5352

5453
type SliceMachineManagerReadCustomTypeLibraryReturnType = {
5554
ids: string[];
@@ -872,9 +871,6 @@ FINAL REMINDERS:
872871
let newSliceAbsPath: string | undefined;
873872

874873
for await (const query of queries) {
875-
if (process.env.SM_ENV !== APPLICATION_MODE.Production) {
876-
console.info(JSON.stringify(query, null, 2));
877-
}
878874
switch (query.type) {
879875
case "result":
880876
if (query.subtype === "success") {

packages/slice-machine/src/features/customTypes/customTypesBuilder/CreateSliceFromImageModal/CreateSliceFromImageModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ export function CreateSliceFromImageModal(
510510

511511
return (
512512
<Dialog open={open} onOpenChange={(open) => !open && closeModal()}>
513-
<DialogHeader title="Generate with AI" />
513+
<DialogHeader title="Generate slices with AI" />
514514
<DialogContent gap={0}>
515515
<DialogDescription hidden>
516516
Upload images to generate slices with AI
Lines changed: 114 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1+
import {
2+
DropdownMenu,
3+
DropdownMenuContent,
4+
DropdownMenuItem,
5+
DropdownMenuTrigger,
6+
} from "@prismicio/editor-ui";
17
import { Video } from "cloudinary-react";
28
import React from "react";
39
import { Box, Button, Heading, Text } from "theme-ui";
410

511
import { telemetry } from "@/apiClient";
12+
import { getSliceCreationOptions } from "@/features/customTypes/customTypesBuilder/sliceCreationOptions";
613

714
interface Props {
815
title: string;
916
onCreateNew: () => void;
17+
onCreateFromImage: () => void;
1018
buttonText: string;
1119
documentationComponent: React.ReactNode;
1220
videoPublicIdUrl: string;
@@ -15,111 +23,135 @@ interface Props {
1523
const EmptyState: React.FunctionComponent<Props> = ({
1624
title,
1725
onCreateNew,
26+
onCreateFromImage,
1827
buttonText,
1928
documentationComponent,
2029
videoPublicIdUrl,
2130
...restProps
22-
}) => (
23-
<Box
24-
sx={{
25-
display: "flex",
26-
width: "80%",
27-
flexWrap: "wrap",
28-
justifyContent: "center",
29-
}}
30-
{...restProps}
31-
>
32-
<Box
33-
sx={(theme) => ({
34-
display: "flex",
35-
flex: 1,
36-
alignItems: "center",
37-
minWidth: "400px",
38-
maxWidth: "70%",
39-
border: `1px solid ${theme.colors?.grey02 as string}`,
40-
})}
41-
>
42-
<Video
43-
cloudName="dmtf1daqp"
44-
controls
45-
loop
46-
style={{
47-
maxWidth: "100%",
48-
objectFit: "contain",
49-
}}
50-
publicId={videoPublicIdUrl}
51-
onPlay={() => {
52-
void telemetry.track({
53-
event: "open-video-tutorials",
54-
video: videoPublicIdUrl,
55-
});
56-
}}
57-
/>
58-
</Box>
31+
}) => {
32+
const sliceCreationOptions = getSliceCreationOptions({
33+
menuType: "Dropdown",
34+
});
5935

36+
return (
6037
<Box
61-
sx={(theme) => ({
62-
bg: "white",
38+
sx={{
6339
display: "flex",
64-
flexDirection: "column",
65-
border: `1px solid ${theme.colors?.grey02 as string}`,
66-
flex: 1,
67-
minWidth: "400px",
68-
maxWidth: "70%",
69-
})}
40+
width: "80%",
41+
flexWrap: "wrap",
42+
justifyContent: "center",
43+
}}
44+
{...restProps}
7045
>
7146
<Box
7247
sx={(theme) => ({
7348
display: "flex",
74-
flexDirection: "column",
75-
p: 4,
76-
borderBottom: `1px solid ${theme.colors?.grey02 as string}`,
49+
flex: 1,
50+
alignItems: "center",
51+
minWidth: "400px",
52+
maxWidth: "70%",
53+
border: `1px solid ${theme.colors?.grey02 as string}`,
7754
})}
7855
>
79-
<Heading
80-
as="h3"
81-
variant={"heading"}
82-
sx={{ fontSize: "16px", lineHeight: "24px", mb: 2 }}
83-
>
84-
{title}
85-
</Heading>
86-
<Text variant="xs" sx={{ lineHeight: "24px", fontSize: "13px" }}>
87-
{documentationComponent}
88-
</Text>
56+
<Video
57+
cloudName="dmtf1daqp"
58+
controls
59+
loop
60+
style={{
61+
maxWidth: "100%",
62+
objectFit: "contain",
63+
}}
64+
publicId={videoPublicIdUrl}
65+
onPlay={() => {
66+
void telemetry.track({
67+
event: "open-video-tutorials",
68+
video: videoPublicIdUrl,
69+
});
70+
}}
71+
/>
8972
</Box>
73+
9074
<Box
91-
sx={{
75+
sx={(theme) => ({
76+
bg: "white",
9277
display: "flex",
93-
p: 4,
94-
alignItems: "center",
95-
}}
78+
flexDirection: "column",
79+
border: `1px solid ${theme.colors?.grey02 as string}`,
80+
flex: 1,
81+
minWidth: "400px",
82+
maxWidth: "70%",
83+
})}
9684
>
97-
<Button
98-
onClick={onCreateNew}
99-
data-testid="empty-state-main-button"
100-
sx={{
85+
<Box
86+
sx={(theme) => ({
10187
display: "flex",
102-
justifyContent: "center",
103-
alignItems: "center",
104-
flexShrink: 0,
105-
mr: 4,
106-
}}
88+
flexDirection: "column",
89+
p: 4,
90+
borderBottom: `1px solid ${theme.colors?.grey02 as string}`,
91+
})}
10792
>
108-
{buttonText}
109-
</Button>
110-
<Text
93+
<Heading
94+
as="h3"
95+
variant={"heading"}
96+
sx={{ fontSize: "16px", lineHeight: "24px", mb: 2 }}
97+
>
98+
{title}
99+
</Heading>
100+
<Text variant="xs" sx={{ lineHeight: "24px", fontSize: "13px" }}>
101+
{documentationComponent}
102+
</Text>
103+
</Box>
104+
<Box
111105
sx={{
112-
fontSize: "12px",
113-
color: "grey04",
114-
maxWidth: "280px",
106+
display: "flex",
107+
p: 4,
108+
alignItems: "center",
115109
}}
116110
>
117-
It will be stored locally and you will be able to push it to your
118-
repository
119-
</Text>
111+
<DropdownMenu>
112+
<DropdownMenuTrigger>
113+
<Button
114+
data-testid="empty-state-main-button"
115+
sx={{ flexShrink: 0, mr: 4 }}
116+
>
117+
{buttonText}
118+
</Button>
119+
</DropdownMenuTrigger>
120+
<DropdownMenuContent align="end">
121+
<DropdownMenuItem
122+
renderStartIcon={() =>
123+
sliceCreationOptions.fromImage.BackgroundIcon
124+
}
125+
onSelect={onCreateFromImage}
126+
description={sliceCreationOptions.fromImage.description}
127+
>
128+
{sliceCreationOptions.fromImage.title}
129+
</DropdownMenuItem>
130+
<DropdownMenuItem
131+
renderStartIcon={() =>
132+
sliceCreationOptions.fromScratch.BackgroundIcon
133+
}
134+
onSelect={onCreateNew}
135+
description={sliceCreationOptions.fromScratch.description}
136+
>
137+
{sliceCreationOptions.fromScratch.title}
138+
</DropdownMenuItem>
139+
</DropdownMenuContent>
140+
</DropdownMenu>
141+
<Text
142+
sx={{
143+
fontSize: "12px",
144+
color: "grey04",
145+
maxWidth: "280px",
146+
}}
147+
>
148+
It will be stored locally and you will be able to push it to your
149+
repository
150+
</Text>
151+
</Box>
120152
</Box>
121153
</Box>
122-
</Box>
123-
);
154+
);
155+
};
124156

125157
export default EmptyState;

packages/slice-machine/src/pages/slices.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ const SlicesIndex: React.FunctionComponent = () => {
171171
onCreateNew={() => {
172172
setIsCreateSliceModalOpen(true);
173173
}}
174+
onCreateFromImage={() => {
175+
void openCreateSliceFromImageModal();
176+
}}
174177
buttonText={"Create one"}
175178
videoPublicIdUrl={VIDEO_WHAT_ARE_SLICES}
176179
documentationComponent={

playwright/tests/slices/slicesList.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ test("I can create a slice from the empty state", async ({
220220
await slicesListPage.goto();
221221
await expect(slicesListPage.blankSlate).toBeVisible();
222222
await slicesListPage.blankSlateCreateAction.click();
223+
await slicesListPage.addSliceDropdownCreateNewAction.click();
223224

224225
const sliceName = "Slice" + generateRandomId();
225226
procedures.unmock("getState");

0 commit comments

Comments
 (0)