@screenbook/ui 0.1.0 → 1.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/astro.config.mjs +2 -0
  3. package/dist/client/_astro/MockFormEditor.0L29BkPy.js +9 -0
  4. package/dist/client/_astro/MockFormEditor.OiYzJAtR.css +1 -0
  5. package/dist/client/_astro/{_baseUniq.BGai4mcc.js → _baseUniq.D9ouiLRJ.js} +1 -1
  6. package/dist/client/_astro/_id_.BqQf-JH6.css +1 -0
  7. package/dist/client/_astro/{arc.DUp0dfXj.js → arc.CLU0JlVT.js} +1 -1
  8. package/dist/client/_astro/{architectureDiagram-VXUJARFQ.De_Gt-YC.js → architectureDiagram-VXUJARFQ.BF0V2v9-.js} +1 -1
  9. package/dist/client/_astro/{blockDiagram-VD42YOAC.BBt_VNhR.js → blockDiagram-VD42YOAC.6LO7yu7m.js} +1 -1
  10. package/dist/client/_astro/{c4Diagram-YG6GDRKO.DfgUlHvt.js → c4Diagram-YG6GDRKO.BqntXNsZ.js} +1 -1
  11. package/dist/client/_astro/channel._8es88oH.js +1 -0
  12. package/dist/client/_astro/{chunk-4BX2VUAB.BL0ar6du.js → chunk-4BX2VUAB.b97OIY94.js} +1 -1
  13. package/dist/client/_astro/{chunk-55IACEB6.CI6SkZkY.js → chunk-55IACEB6.Cf9hglsl.js} +1 -1
  14. package/dist/client/_astro/{chunk-B4BG7PRW.Z25N80K6.js → chunk-B4BG7PRW.vDfM6vb1.js} +1 -1
  15. package/dist/client/_astro/{chunk-DI55MBZ5.BqjPVmi1.js → chunk-DI55MBZ5.8pHdnkw9.js} +1 -1
  16. package/dist/client/_astro/{chunk-FMBD7UC4.bZ9DWnFm.js → chunk-FMBD7UC4.l_Ue7ZYJ.js} +1 -1
  17. package/dist/client/_astro/{chunk-QN33PNHL.BkzuUgWB.js → chunk-QN33PNHL.CyBZ7SCx.js} +1 -1
  18. package/dist/client/_astro/{chunk-QZHKN3VN.C__d68N_.js → chunk-QZHKN3VN.BC5tI2Vw.js} +1 -1
  19. package/dist/client/_astro/{chunk-TZMSLE5B.BIpu8bMn.js → chunk-TZMSLE5B.DxkkbOL4.js} +1 -1
  20. package/dist/client/_astro/classDiagram-2ON5EDUG.DMv55r4w.js +1 -0
  21. package/dist/client/_astro/classDiagram-v2-WZHVMYZB.DMv55r4w.js +1 -0
  22. package/dist/client/_astro/client.9unXo8s5.js +33 -0
  23. package/dist/client/_astro/clone.COAvtnt5.js +1 -0
  24. package/dist/client/_astro/{cose-bilkent-S5V4N54A.D48yfMll.js → cose-bilkent-S5V4N54A.DlRxGhCG.js} +1 -1
  25. package/dist/client/_astro/coverage.DLKSOM4m.css +1 -0
  26. package/dist/client/_astro/{dagre-6UL2VRFP.LKVH7b30.js → dagre-6UL2VRFP.tCLd0f1c.js} +1 -1
  27. package/dist/client/_astro/{diagram-PSM6KHXK.AHgUjH56.js → diagram-PSM6KHXK.CJA_rnN3.js} +1 -1
  28. package/dist/client/_astro/{diagram-QEK2KX5R.DvS33xWZ.js → diagram-QEK2KX5R.BoqLvsuS.js} +1 -1
  29. package/dist/client/_astro/{diagram-S2PKOQOG.BWisaYrQ.js → diagram-S2PKOQOG.T8h5wODN.js} +1 -1
  30. package/dist/client/_astro/{erDiagram-Q2GNP2WA.B7oID6oT.js → erDiagram-Q2GNP2WA.B4hpr69H.js} +1 -1
  31. package/dist/client/_astro/{flowDiagram-NV44I4VS.Bb1qJLxr.js → flowDiagram-NV44I4VS.CV4Oenkb.js} +1 -1
  32. package/dist/client/_astro/{ganttDiagram-JELNMOA3.3vGHETyo.js → ganttDiagram-JELNMOA3.DdpXJeX3.js} +1 -1
  33. package/dist/client/_astro/{gitGraphDiagram-NY62KEGX.Co2SKcif.js → gitGraphDiagram-NY62KEGX.BeY3JZYI.js} +1 -1
  34. package/dist/client/_astro/{graph.B5fevUwB.js → graph.CO6LxWoK.js} +1 -1
  35. package/dist/client/_astro/graph.astro_astro_type_script_index_0_lang.BxaPom9e.js +1 -0
  36. package/dist/client/_astro/{impact.astro_astro_type_script_index_0_lang.D4cAR9AL.js → impact.astro_astro_type_script_index_0_lang.VjeLQGe6.js} +1 -1
  37. package/dist/client/_astro/index.WFquGv8Z.js +9 -0
  38. package/dist/client/_astro/{infoDiagram-WHAUD3N6.B6ULtps1.js → infoDiagram-WHAUD3N6.D2_J_fR6.js} +1 -1
  39. package/dist/client/_astro/{journeyDiagram-XKPGCS4Q.BSOCzWmw.js → journeyDiagram-XKPGCS4Q.7c4ngVDw.js} +1 -1
  40. package/dist/client/_astro/{kanban-definition-3W4ZIXB7.D8KKGc1o.js → kanban-definition-3W4ZIXB7.D_eWex6x.js} +1 -1
  41. package/dist/client/_astro/{layout.8vv24qEg.js → layout.Cn9EjNLq.js} +1 -1
  42. package/dist/client/_astro/{linear.B6O9ymuK.js → linear.BlE_mLsy.js} +1 -1
  43. package/dist/client/_astro/{mermaid.core.CReXU7YN.js → mermaid.core.CgCLOZ6t.js} +5 -5
  44. package/dist/client/_astro/{min.CdGMGVU0.js → min.OtQS-qlD.js} +1 -1
  45. package/dist/client/_astro/{mindmap-definition-VGOIOE7T.G14HgtDw.js → mindmap-definition-VGOIOE7T.CjNYt18e.js} +1 -1
  46. package/dist/client/_astro/{pieDiagram-ADFJNKIX.bC2VkyoW.js → pieDiagram-ADFJNKIX.D18DPyo6.js} +1 -1
  47. package/dist/client/_astro/{quadrantDiagram-AYHSOK5B.BlLaQQxO.js → quadrantDiagram-AYHSOK5B.Cma08fPv.js} +1 -1
  48. package/dist/client/_astro/{requirementDiagram-UZGBJVZJ.DHRnMofO.js → requirementDiagram-UZGBJVZJ.BlhVOrX0.js} +1 -1
  49. package/dist/client/_astro/{sankeyDiagram-TZEHDZUN.BMuaJBmt.js → sankeyDiagram-TZEHDZUN.HRsqw4ej.js} +1 -1
  50. package/dist/client/_astro/{sequenceDiagram-WL72ISMW.CnU62wqy.js → sequenceDiagram-WL72ISMW.3cZYkaSP.js} +1 -1
  51. package/dist/client/_astro/{stateDiagram-FKZM4ZOC.CewI55YO.js → stateDiagram-FKZM4ZOC.DdlRd9N7.js} +1 -1
  52. package/dist/client/_astro/stateDiagram-v2-4FDKWEC3.DCPDjwi7.js +1 -0
  53. package/dist/client/_astro/{timeline-definition-IT6M3QCI.D1PLRwss.js → timeline-definition-IT6M3QCI.BshW8mMW.js} +1 -1
  54. package/dist/client/_astro/{treemap-KMMF4GRG.D3VNVvXF.js → treemap-KMMF4GRG.BxXN_YfK.js} +1 -1
  55. package/dist/client/_astro/{xychartDiagram-PRI3JC2R.CQex0-ul.js → xychartDiagram-PRI3JC2R.Mg5_s08f.js} +1 -1
  56. package/dist/server/entry.mjs +15 -11
  57. package/dist/server/manifest_smcahUO6.mjs +101 -0
  58. package/dist/server/pages/api/save-mock.astro.mjs +142 -0
  59. package/dist/server/pages/coverage.astro.mjs +1 -1
  60. package/dist/server/pages/editor.astro.mjs +30 -0
  61. package/dist/server/pages/graph.astro.mjs +18 -3
  62. package/dist/server/pages/impact.astro.mjs +1 -1
  63. package/dist/server/pages/index.astro.mjs +1 -1
  64. package/dist/server/pages/screen/_id_.astro.mjs +126 -3
  65. package/dist/server/renderers.mjs +200 -1
  66. package/package.json +8 -2
  67. package/src/components/MockFormEditor.tsx +1280 -0
  68. package/src/components/MockPreview.astro +811 -0
  69. package/src/pages/api/save-mock.ts +182 -0
  70. package/src/pages/editor.astro +33 -0
  71. package/src/pages/graph.astro +35 -1
  72. package/src/pages/screen/[id].astro +9 -0
  73. package/src/styles/mock-editor.css +1351 -0
  74. package/tsconfig.json +1 -0
  75. package/dist/client/_astro/channel.CNyr52v1.js +0 -1
  76. package/dist/client/_astro/classDiagram-2ON5EDUG.CxT3aW-h.js +0 -1
  77. package/dist/client/_astro/classDiagram-v2-WZHVMYZB.CxT3aW-h.js +0 -1
  78. package/dist/client/_astro/clone.U_lSZ6fe.js +0 -1
  79. package/dist/client/_astro/coverage.BnE2oGo8.css +0 -1
  80. package/dist/client/_astro/graph.astro_astro_type_script_index_0_lang.B0fEnVdy.js +0 -1
  81. package/dist/client/_astro/stateDiagram-v2-4FDKWEC3.7xUQqoNr.js +0 -1
  82. package/dist/server/manifest_CicDtuHD.mjs +0 -101
  83. /package/dist/server/chunks/{loadScreens_JhK3F9tC.mjs → loadScreens_CkCqdbH2.mjs} +0 -0
@@ -0,0 +1,811 @@
1
+ ---
2
+ import type { ScreenMock, MockElement, MockSection } from "@screenbook/core"
3
+
4
+ interface Props {
5
+ mock: ScreenMock
6
+ screenId: string
7
+ }
8
+
9
+ const { mock, screenId } = Astro.props
10
+
11
+ // Helper to get element variant color for buttons
12
+ function getButtonStyle(variant?: string): string {
13
+ switch (variant) {
14
+ case "primary":
15
+ return "background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%); color: white;"
16
+ case "danger":
17
+ return "background: #ef4444; color: white;"
18
+ default:
19
+ return "background: #3d4660; color: #94a3b8;"
20
+ }
21
+ }
22
+
23
+ // Helper to get text variant styles
24
+ function getTextStyle(variant?: string): string {
25
+ switch (variant) {
26
+ case "heading":
27
+ return "font-size: 16px; font-weight: 700; color: #e2e8f0;"
28
+ case "subheading":
29
+ return "font-size: 14px; font-weight: 600; color: #cbd5e1;"
30
+ case "caption":
31
+ return "font-size: 11px; color: #64748b;"
32
+ default:
33
+ return "font-size: 13px; color: #94a3b8;"
34
+ }
35
+ }
36
+
37
+ // Calculate aspect ratio padding for image placeholders
38
+ function getAspectRatioPadding(ratio?: string): string {
39
+ if (!ratio) return "56.25%" // 16:9 default
40
+ const [w, h] = ratio.split(":").map(Number)
41
+ if (!w || !h) return "56.25%"
42
+ return `${(h / w) * 100}%`
43
+ }
44
+ ---
45
+
46
+ <div class="mock-preview">
47
+ <div class="mock-header">
48
+ <div class="mock-header-left">
49
+ <svg
50
+ class="mock-icon"
51
+ fill="none"
52
+ viewBox="0 0 24 24"
53
+ stroke="currentColor"
54
+ stroke-width="2"
55
+ >
56
+ <path
57
+ stroke-linecap="round"
58
+ stroke-linejoin="round"
59
+ d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3"
60
+ ></path>
61
+ </svg>
62
+ <span>Wireframe Mock</span>
63
+ </div>
64
+ <a href={`/editor?screen=${screenId}`} class="edit-mock-link">
65
+ <svg
66
+ fill="none"
67
+ viewBox="0 0 24 24"
68
+ stroke="currentColor"
69
+ stroke-width="2"
70
+ >
71
+ <path
72
+ stroke-linecap="round"
73
+ stroke-linejoin="round"
74
+ d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
75
+ ></path>
76
+ </svg>
77
+ Edit Mock
78
+ </a>
79
+ </div>
80
+
81
+ <div class="mock-frame">
82
+ {
83
+ mock.sections.map((section) => (
84
+ <div class="mock-section">
85
+ {section.title && <div class="section-title">{section.title}</div>}
86
+ <div
87
+ class={`section-elements ${section.layout === "horizontal" ? "horizontal" : "vertical"}`}
88
+ >
89
+ {section.elements.map((element) => {
90
+ if (element.type === "button") {
91
+ const buttonContent = (
92
+ <div
93
+ class={`mock-button ${element.navigateTo ? "has-navigation" : ""}`}
94
+ style={getButtonStyle(element.variant)}
95
+ >
96
+ <span class="button-label">{element.label}</span>
97
+ {element.navigateTo && (
98
+ <span class="button-navigate">
99
+ → {element.navigateTo}
100
+ </span>
101
+ )}
102
+ </div>
103
+ )
104
+ return element.navigateTo ? (
105
+ <a
106
+ href={`/screen/${element.navigateTo}`}
107
+ class="element-link"
108
+ >
109
+ {buttonContent}
110
+ </a>
111
+ ) : (
112
+ buttonContent
113
+ )
114
+ }
115
+
116
+ if (element.type === "input") {
117
+ return (
118
+ <div class="mock-input">
119
+ <span class="input-label">{element.label}</span>
120
+ <span class="input-placeholder">
121
+ {element.placeholder || "Enter value..."}
122
+ </span>
123
+ </div>
124
+ )
125
+ }
126
+
127
+ if (element.type === "link") {
128
+ const linkContent = (
129
+ <div
130
+ class={`mock-link-card ${element.navigateTo ? "has-navigation" : ""}`}
131
+ >
132
+ <span class="link-label">{element.label}</span>
133
+ {element.navigateTo && (
134
+ <span class="link-navigate">→ {element.navigateTo}</span>
135
+ )}
136
+ </div>
137
+ )
138
+ return element.navigateTo ? (
139
+ <a
140
+ href={`/screen/${element.navigateTo}`}
141
+ class="element-link"
142
+ >
143
+ {linkContent}
144
+ </a>
145
+ ) : (
146
+ <div class="mock-link">{element.label}</div>
147
+ )
148
+ }
149
+
150
+ if (element.type === "text") {
151
+ return (
152
+ <div class="mock-text" style={getTextStyle(element.variant)}>
153
+ {element.label}
154
+ </div>
155
+ )
156
+ }
157
+
158
+ if (element.type === "image") {
159
+ return (
160
+ <div
161
+ class="mock-image"
162
+ style={`padding-bottom: ${getAspectRatioPadding(element.aspectRatio)}`}
163
+ >
164
+ <div class="image-placeholder">
165
+ <svg
166
+ fill="none"
167
+ viewBox="0 0 24 24"
168
+ stroke="currentColor"
169
+ stroke-width="1.5"
170
+ >
171
+ <path
172
+ stroke-linecap="round"
173
+ stroke-linejoin="round"
174
+ d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
175
+ />
176
+ </svg>
177
+ <span>{element.label}</span>
178
+ </div>
179
+ </div>
180
+ )
181
+ }
182
+
183
+ if (element.type === "list") {
184
+ const itemCount = element.itemCount || 3
185
+ const listContent = (
186
+ <div
187
+ class={`mock-list ${element.itemNavigateTo ? "has-navigation" : ""}`}
188
+ >
189
+ <div class="list-header">{element.label}</div>
190
+ {Array.from({ length: itemCount }).map((_, i) => (
191
+ <div
192
+ class="list-item"
193
+ style={
194
+ i < itemCount - 1
195
+ ? "border-bottom: 1px solid #1e2433;"
196
+ : ""
197
+ }
198
+ >
199
+ Item {i + 1}
200
+ </div>
201
+ ))}
202
+ {element.itemNavigateTo && (
203
+ <div class="list-footer">→ {element.itemNavigateTo}</div>
204
+ )}
205
+ </div>
206
+ )
207
+ return element.itemNavigateTo ? (
208
+ <a
209
+ href={`/screen/${element.itemNavigateTo}`}
210
+ class="element-link"
211
+ >
212
+ {listContent}
213
+ </a>
214
+ ) : (
215
+ listContent
216
+ )
217
+ }
218
+
219
+ if (element.type === "table") {
220
+ const columns = element.columns || [
221
+ "Column 1",
222
+ "Column 2",
223
+ "Column 3",
224
+ ]
225
+ const rowCount = element.rowCount || 3
226
+ const tableContent = (
227
+ <div
228
+ class={`mock-table ${element.rowNavigateTo ? "has-navigation" : ""}`}
229
+ >
230
+ <div class="table-header">{element.label}</div>
231
+ <div class="table-content">
232
+ <div class="table-row table-header-row">
233
+ {columns.map((col) => (
234
+ <div class="table-cell">{col}</div>
235
+ ))}
236
+ </div>
237
+ {Array.from({ length: rowCount }).map((_, i) => (
238
+ <div class="table-row">
239
+ {columns.map((_, j) => (
240
+ <div class="table-cell">
241
+ Data {i + 1}-{j + 1}
242
+ </div>
243
+ ))}
244
+ </div>
245
+ ))}
246
+ </div>
247
+ {element.rowNavigateTo && (
248
+ <div class="table-footer">→ {element.rowNavigateTo}</div>
249
+ )}
250
+ </div>
251
+ )
252
+ return element.rowNavigateTo ? (
253
+ <a
254
+ href={`/screen/${element.rowNavigateTo}`}
255
+ class="element-link"
256
+ >
257
+ {tableContent}
258
+ </a>
259
+ ) : (
260
+ tableContent
261
+ )
262
+ }
263
+
264
+ return null
265
+ })}
266
+ </div>
267
+ {/* Child sections */}
268
+ {section.children && section.children.length > 0 && (
269
+ <div class="child-sections">
270
+ {section.children.map((childSection) => (
271
+ <div class="mock-section child-section">
272
+ {childSection.title && (
273
+ <div class="section-title child-section-title">
274
+ {childSection.title}
275
+ </div>
276
+ )}
277
+ <div
278
+ class={`section-elements ${childSection.layout === "horizontal" ? "horizontal" : "vertical"}`}
279
+ >
280
+ {childSection.elements.map((element) => {
281
+ if (element.type === "button") {
282
+ const buttonContent = (
283
+ <div
284
+ class={`mock-button ${element.navigateTo ? "has-navigation" : ""}`}
285
+ style={getButtonStyle(element.variant)}
286
+ >
287
+ <span class="button-label">{element.label}</span>
288
+ {element.navigateTo && (
289
+ <span class="button-navigate">
290
+ → {element.navigateTo}
291
+ </span>
292
+ )}
293
+ </div>
294
+ )
295
+ return element.navigateTo ? (
296
+ <a
297
+ href={`/screen/${element.navigateTo}`}
298
+ class="element-link"
299
+ >
300
+ {buttonContent}
301
+ </a>
302
+ ) : (
303
+ buttonContent
304
+ )
305
+ }
306
+ if (element.type === "input") {
307
+ return (
308
+ <div class="mock-input">
309
+ <span class="input-label">{element.label}</span>
310
+ <span class="input-placeholder">
311
+ {element.placeholder || "Enter value..."}
312
+ </span>
313
+ </div>
314
+ )
315
+ }
316
+ if (element.type === "link") {
317
+ const linkContent = (
318
+ <div
319
+ class={`mock-link-card ${element.navigateTo ? "has-navigation" : ""}`}
320
+ >
321
+ <span class="link-label">{element.label}</span>
322
+ {element.navigateTo && (
323
+ <span class="link-navigate">
324
+ → {element.navigateTo}
325
+ </span>
326
+ )}
327
+ </div>
328
+ )
329
+ return element.navigateTo ? (
330
+ <a
331
+ href={`/screen/${element.navigateTo}`}
332
+ class="element-link"
333
+ >
334
+ {linkContent}
335
+ </a>
336
+ ) : (
337
+ <div class="mock-link">{element.label}</div>
338
+ )
339
+ }
340
+ if (element.type === "text") {
341
+ return (
342
+ <div
343
+ class="mock-text"
344
+ style={getTextStyle(element.variant)}
345
+ >
346
+ {element.label}
347
+ </div>
348
+ )
349
+ }
350
+ if (element.type === "image") {
351
+ return (
352
+ <div
353
+ class="mock-image"
354
+ style={`padding-bottom: ${getAspectRatioPadding(element.aspectRatio)}`}
355
+ >
356
+ <div class="image-placeholder">
357
+ <svg
358
+ fill="none"
359
+ viewBox="0 0 24 24"
360
+ stroke="currentColor"
361
+ stroke-width="1.5"
362
+ >
363
+ <path
364
+ stroke-linecap="round"
365
+ stroke-linejoin="round"
366
+ d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
367
+ />
368
+ </svg>
369
+ <span>{element.label}</span>
370
+ </div>
371
+ </div>
372
+ )
373
+ }
374
+ if (element.type === "list") {
375
+ const itemCount = element.itemCount || 3
376
+ const listContent = (
377
+ <div
378
+ class={`mock-list ${element.itemNavigateTo ? "has-navigation" : ""}`}
379
+ >
380
+ <div class="list-header">{element.label}</div>
381
+ {Array.from({ length: itemCount }).map((_, i) => (
382
+ <div
383
+ class="list-item"
384
+ style={
385
+ i < itemCount - 1
386
+ ? "border-bottom: 1px solid #1e2433;"
387
+ : ""
388
+ }
389
+ >
390
+ Item {i + 1}
391
+ </div>
392
+ ))}
393
+ {element.itemNavigateTo && (
394
+ <div class="list-footer">
395
+ → {element.itemNavigateTo}
396
+ </div>
397
+ )}
398
+ </div>
399
+ )
400
+ return element.itemNavigateTo ? (
401
+ <a
402
+ href={`/screen/${element.itemNavigateTo}`}
403
+ class="element-link"
404
+ >
405
+ {listContent}
406
+ </a>
407
+ ) : (
408
+ listContent
409
+ )
410
+ }
411
+ if (element.type === "table") {
412
+ const columns = element.columns || [
413
+ "Column 1",
414
+ "Column 2",
415
+ "Column 3",
416
+ ]
417
+ const rowCount = element.rowCount || 3
418
+ const tableContent = (
419
+ <div
420
+ class={`mock-table ${element.rowNavigateTo ? "has-navigation" : ""}`}
421
+ >
422
+ <div class="table-header">{element.label}</div>
423
+ <div class="table-content">
424
+ <div class="table-row table-header-row">
425
+ {columns.map((col) => (
426
+ <div class="table-cell">{col}</div>
427
+ ))}
428
+ </div>
429
+ {Array.from({ length: rowCount }).map((_, i) => (
430
+ <div class="table-row">
431
+ {columns.map((_, j) => (
432
+ <div class="table-cell">
433
+ Data {i + 1}-{j + 1}
434
+ </div>
435
+ ))}
436
+ </div>
437
+ ))}
438
+ </div>
439
+ {element.rowNavigateTo && (
440
+ <div class="table-footer">
441
+ → {element.rowNavigateTo}
442
+ </div>
443
+ )}
444
+ </div>
445
+ )
446
+ return element.rowNavigateTo ? (
447
+ <a
448
+ href={`/screen/${element.rowNavigateTo}`}
449
+ class="element-link"
450
+ >
451
+ {tableContent}
452
+ </a>
453
+ ) : (
454
+ tableContent
455
+ )
456
+ }
457
+ return null
458
+ })}
459
+ </div>
460
+ </div>
461
+ ))}
462
+ </div>
463
+ )}
464
+ </div>
465
+ ))
466
+ }
467
+ </div>
468
+ </div>
469
+
470
+ <style>
471
+ .mock-preview {
472
+ background: #1e2433;
473
+ border-radius: 12px;
474
+ overflow: hidden;
475
+ border: 1px solid #2d3548;
476
+ }
477
+
478
+ .mock-header {
479
+ display: flex;
480
+ align-items: center;
481
+ justify-content: space-between;
482
+ padding: 12px 16px;
483
+ background: #1a1f2e;
484
+ border-bottom: 1px solid #2d3548;
485
+ }
486
+
487
+ .mock-header-left {
488
+ display: flex;
489
+ align-items: center;
490
+ gap: 8px;
491
+ color: #94a3b8;
492
+ font-size: 14px;
493
+ }
494
+
495
+ .mock-icon {
496
+ width: 18px;
497
+ height: 18px;
498
+ }
499
+
500
+ .edit-mock-link {
501
+ display: flex;
502
+ align-items: center;
503
+ gap: 6px;
504
+ padding: 6px 12px;
505
+ background: #2d3548;
506
+ color: #94a3b8;
507
+ border-radius: 6px;
508
+ font-size: 12px;
509
+ text-decoration: none;
510
+ transition: all 0.2s;
511
+ }
512
+
513
+ .edit-mock-link:hover {
514
+ background: #3d4660;
515
+ color: #14b8a6;
516
+ }
517
+
518
+ .edit-mock-link svg {
519
+ width: 14px;
520
+ height: 14px;
521
+ }
522
+
523
+ .mock-frame {
524
+ padding: 20px;
525
+ background: #0f1219;
526
+ max-width: 400px;
527
+ margin: 20px auto;
528
+ border-radius: 8px;
529
+ border: 1px solid #2d3548;
530
+ }
531
+
532
+ .mock-section {
533
+ margin-bottom: 16px;
534
+ }
535
+
536
+ .mock-section:last-child {
537
+ margin-bottom: 0;
538
+ }
539
+
540
+ .section-title {
541
+ font-size: 11px;
542
+ font-weight: 600;
543
+ color: #64748b;
544
+ text-transform: uppercase;
545
+ letter-spacing: 0.05em;
546
+ margin-bottom: 8px;
547
+ }
548
+
549
+ .child-sections {
550
+ margin-top: 12px;
551
+ padding-left: 16px;
552
+ border-left: 2px solid #2d3548;
553
+ }
554
+
555
+ .child-section {
556
+ background: rgba(20, 184, 166, 0.03);
557
+ padding: 12px;
558
+ border-radius: 6px;
559
+ margin-bottom: 12px;
560
+ }
561
+
562
+ .child-section:last-child {
563
+ margin-bottom: 0;
564
+ }
565
+
566
+ .child-section-title {
567
+ color: #5eead4;
568
+ }
569
+
570
+ .section-elements {
571
+ display: flex;
572
+ gap: 8px;
573
+ }
574
+
575
+ .section-elements.vertical {
576
+ flex-direction: column;
577
+ }
578
+
579
+ .section-elements.horizontal {
580
+ flex-direction: row;
581
+ flex-wrap: wrap;
582
+ }
583
+
584
+ .section-elements.horizontal > * {
585
+ flex: 1;
586
+ min-width: 80px;
587
+ }
588
+
589
+ .element-link {
590
+ text-decoration: none;
591
+ display: block;
592
+ border-radius: 6px;
593
+ transition: all 0.2s;
594
+ }
595
+
596
+ .element-link:hover .mock-button,
597
+ .element-link:hover .mock-link-card,
598
+ .element-link:hover .mock-list,
599
+ .element-link:hover .mock-table {
600
+ transform: translateY(-2px);
601
+ box-shadow: 0 4px 12px rgba(20, 184, 166, 0.2);
602
+ }
603
+
604
+ .mock-button {
605
+ padding: 10px 16px;
606
+ border-radius: 6px;
607
+ font-size: 13px;
608
+ font-weight: 500;
609
+ text-align: center;
610
+ cursor: default;
611
+ transition: all 0.2s;
612
+ }
613
+
614
+ .mock-button.has-navigation {
615
+ cursor: pointer;
616
+ display: flex;
617
+ flex-direction: column;
618
+ gap: 4px;
619
+ align-items: center;
620
+ }
621
+
622
+ .button-label {
623
+ display: block;
624
+ }
625
+
626
+ .button-navigate {
627
+ font-size: 10px;
628
+ opacity: 0.8;
629
+ }
630
+
631
+ .mock-input {
632
+ display: flex;
633
+ flex-direction: column;
634
+ gap: 4px;
635
+ padding: 10px 12px;
636
+ background: #1e2433;
637
+ border: 1px solid #3d4660;
638
+ border-radius: 6px;
639
+ }
640
+
641
+ .input-label {
642
+ font-size: 11px;
643
+ color: #64748b;
644
+ font-weight: 500;
645
+ }
646
+
647
+ .input-placeholder {
648
+ font-size: 13px;
649
+ color: #475569;
650
+ }
651
+
652
+ .mock-link {
653
+ color: #14b8a6;
654
+ font-size: 13px;
655
+ text-decoration: underline;
656
+ cursor: default;
657
+ }
658
+
659
+ .mock-link-card {
660
+ padding: 10px 12px;
661
+ background: rgba(20, 184, 166, 0.1);
662
+ border: 1px solid rgba(20, 184, 166, 0.3);
663
+ border-radius: 6px;
664
+ transition: all 0.2s;
665
+ }
666
+
667
+ .mock-link-card.has-navigation {
668
+ cursor: pointer;
669
+ }
670
+
671
+ .link-label {
672
+ color: #14b8a6;
673
+ font-size: 13px;
674
+ text-decoration: underline;
675
+ display: block;
676
+ }
677
+
678
+ .link-navigate {
679
+ font-size: 10px;
680
+ color: #5eead4;
681
+ opacity: 0.8;
682
+ display: block;
683
+ margin-top: 4px;
684
+ }
685
+
686
+ .mock-text {
687
+ padding: 4px 0;
688
+ }
689
+
690
+ .mock-image {
691
+ position: relative;
692
+ background: #1e2433;
693
+ border: 2px dashed #3d4660;
694
+ border-radius: 6px;
695
+ overflow: hidden;
696
+ }
697
+
698
+ .image-placeholder {
699
+ position: absolute;
700
+ top: 0;
701
+ left: 0;
702
+ right: 0;
703
+ bottom: 0;
704
+ display: flex;
705
+ flex-direction: column;
706
+ align-items: center;
707
+ justify-content: center;
708
+ gap: 8px;
709
+ color: #475569;
710
+ }
711
+
712
+ .image-placeholder svg {
713
+ width: 32px;
714
+ height: 32px;
715
+ }
716
+
717
+ .image-placeholder span {
718
+ font-size: 12px;
719
+ }
720
+
721
+ .mock-list {
722
+ background: #1e2433;
723
+ border: 1px solid #3d4660;
724
+ border-radius: 6px;
725
+ overflow: hidden;
726
+ }
727
+
728
+ .list-header {
729
+ padding: 10px 12px;
730
+ background: #2d3548;
731
+ font-size: 12px;
732
+ font-weight: 600;
733
+ color: #94a3b8;
734
+ }
735
+
736
+ .list-item {
737
+ padding: 10px 12px;
738
+ font-size: 13px;
739
+ color: #94a3b8;
740
+ }
741
+
742
+ .list-footer {
743
+ padding: 8px 12px;
744
+ background: rgba(20, 184, 166, 0.1);
745
+ font-size: 10px;
746
+ color: #14b8a6;
747
+ border-top: 1px solid #3d4660;
748
+ }
749
+
750
+ .mock-list.has-navigation {
751
+ cursor: pointer;
752
+ }
753
+
754
+ .mock-table {
755
+ background: #1e2433;
756
+ border: 1px solid #3d4660;
757
+ border-radius: 6px;
758
+ overflow: hidden;
759
+ }
760
+
761
+ .table-header {
762
+ padding: 10px 12px;
763
+ background: #2d3548;
764
+ font-size: 12px;
765
+ font-weight: 600;
766
+ color: #94a3b8;
767
+ }
768
+
769
+ .table-content {
770
+ overflow-x: auto;
771
+ }
772
+
773
+ .table-row {
774
+ display: flex;
775
+ border-bottom: 1px solid #2d3548;
776
+ }
777
+
778
+ .table-row:last-child {
779
+ border-bottom: none;
780
+ }
781
+
782
+ .table-header-row {
783
+ background: #252d3d;
784
+ }
785
+
786
+ .table-header-row .table-cell {
787
+ font-weight: 600;
788
+ font-size: 11px;
789
+ color: #64748b;
790
+ }
791
+
792
+ .table-cell {
793
+ flex: 1;
794
+ padding: 8px 12px;
795
+ font-size: 12px;
796
+ color: #94a3b8;
797
+ min-width: 80px;
798
+ }
799
+
800
+ .table-footer {
801
+ padding: 8px 12px;
802
+ background: rgba(20, 184, 166, 0.1);
803
+ font-size: 10px;
804
+ color: #14b8a6;
805
+ border-top: 1px solid #3d4660;
806
+ }
807
+
808
+ .mock-table.has-navigation {
809
+ cursor: pointer;
810
+ }
811
+ </style>