返回 presentation-ai
steps-item-static.tsx
根目录 / src / components / notebook / presentation / editor / custom-elements / static / steps-item-static.tsx
1 import { NodeApi, PathApi } from "platejs";
2 import { SlateElement, type SlateElementProps } from "platejs/static";
3
4 import { type TStepsGroupElement } from "../../plugins/steps-plugin";
5 import { getDefaultColumnSize } from "../../utils";
6
7 const columnSizeToColumns: Record<string, number> = {
8 sm: 4,
9 md: 3,
10 lg: 2,
11 xl: 1,
12 };
13
14 export function StepsItemStatic(props: SlateElementProps) {
15 const path = props.editor.api.findPath(props.element) ?? [-1];
16 const parentPath = PathApi.parent(path);
17 const parent = NodeApi.get(props.editor, parentPath) as TStepsGroupElement;
18 const index = (path?.at(-1) as number) ?? 0;
19
20 const { variant = "default" } = parent ?? {};
21 const columnSize =
22 parent?.columnSize ?? getDefaultColumnSize(parent?.children.length ?? 0);
23
24 const columns = columnSizeToColumns[columnSize] ?? 3;
25
26 const isVertical = columns === 1;
27 const colIndex = isVertical ? index : index % columns;
28
29 const primaryColor =
30 "var(--presentation-smart-layout, var(--presentation-primary))";
31
32 if (!isVertical) {
33 if (variant === "default") {
34 const topMargin = Math.max(0, (columns - 1 - colIndex) * 2);
35 return (
36 <SlateElement {...props} className="my-0 flex h-full min-w-0 flex-col">
37 <div
38 className="flex flex-1 flex-col"
39 style={{ marginTop: `${topMargin}rem` }}
40 >
41 <div
42 className="mb-3 h-1.5 w-full shrink-0 rounded-full"
43 data-decor="true"
44 style={{ backgroundColor: primaryColor }}
45 />
46 <div className="flex-1">{props.children}</div>
47 </div>
48 </SlateElement>
49 );
50 }
51
52 if (variant === "arrow") {
53 const topMargin = Math.max(0, (columns - 1 - colIndex) * 2);
54 return (
55 <SlateElement {...props} className="my-0 flex h-full min-w-0 flex-col">
56 <div
57 className="flex flex-1 flex-col"
58 style={{ marginTop: `${topMargin}rem` }}
59 >
60 <div
61 className="mb-3 flex w-full shrink-0 items-center pr-4"
62 data-decor="true"
63 style={{ color: primaryColor }}
64 >
65 <div className="h-3 flex-1 bg-current" />
66 <svg
67 viewBox="0 0 16 24"
68 className="-ml-px h-6 w-4 shrink-0 fill-current"
69 >
70 <path d="M0 0l16 12-16 12z" />
71 </svg>
72 </div>
73 <div className="flex-1">{props.children}</div>
74 </div>
75 </SlateElement>
76 );
77 }
78
79 if (variant === "box") {
80 const topMargin = Math.max(0, (columns - 1 - colIndex) * 2);
81 return (
82 <SlateElement {...props} className="my-0 flex h-full min-w-0 flex-col">
83 <div
84 className="flex flex-1 flex-col"
85 style={{ marginTop: `${topMargin}rem` }}
86 >
87 <div
88 className="flex-1 rounded-lg border p-4"
89 style={{
90 borderLeftWidth: "6px",
91 borderColor: primaryColor,
92 }}
93 >
94 <div>{props.children}</div>
95 </div>
96 </div>
97 </SlateElement>
98 );
99 }
100 }
101
102 // Vertical layout
103 if (variant === "default") {
104 return (
105 <SlateElement {...props} className="my-0 min-w-0">
106 <div
107 className="py-2 pl-4"
108 style={{
109 marginLeft: `${colIndex * 1.5}rem`,
110 borderLeftWidth: "6px",
111 borderLeftStyle: "solid",
112 borderLeftColor: primaryColor,
113 }}
114 >
115 <div>{props.children}</div>
116 </div>
117 </SlateElement>
118 );
119 }
120
121 if (variant === "arrow") {
122 return (
123 <SlateElement {...props} className="my-0 min-w-0">
124 <div
125 className="flex gap-4"
126 style={{ marginLeft: `${colIndex * 1.5}rem` }}
127 >
128 <div
129 className="flex shrink-0 flex-col items-center"
130 data-decor="true"
131 style={{ color: primaryColor }}
132 >
133 <div className="w-3 flex-1 bg-current" />
134 <svg
135 viewBox="0 0 24 16"
136 className="-mt-px h-4 w-6 shrink-0 fill-current"
137 >
138 <path d="M0 0l12 16 12-16z" />
139 </svg>
140 </div>
141 <div className="min-w-0 pb-4">{props.children}</div>
142 </div>
143 </SlateElement>
144 );
145 }
146
147 if (variant === "box") {
148 return (
149 <SlateElement {...props} className="my-0 min-w-0">
150 <div
151 className="w-full rounded-lg border p-4"
152 style={{
153 marginLeft: `${colIndex * 1.5}rem`,
154 width: `calc(100% - ${colIndex * 1.5}rem)`,
155 borderLeftWidth: "6px",
156 borderLeftStyle: "solid",
157 borderColor: primaryColor,
158 }}
159 >
160 <div>{props.children}</div>
161 </div>
162 </SlateElement>
163 );
164 }
165
166 // Fallback
167 return (
168 <SlateElement {...props} className="my-0 min-w-0">
169 {props.children}
170 </SlateElement>
171 );
172 }
173
173 lines Plain Text