zerocodejs 1.0.1-beta.0 → 1.0.1-beta.10

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 (68) hide show
  1. package/README.ja.md +164 -0
  2. package/README.md +98 -93
  3. package/dist/components/ZeroCodeEditor.vue.d.ts.map +1 -1
  4. package/dist/core/composables/useZeroCodeRenderer.d.ts.map +1 -1
  5. package/dist/core/utils/edit-panel-fields.d.ts +17 -0
  6. package/dist/core/utils/edit-panel-fields.d.ts.map +1 -0
  7. package/dist/core/utils/template-processor.d.ts +6 -1
  8. package/dist/core/utils/template-processor.d.ts.map +1 -1
  9. package/dist/features/editor/components/EditPanel.vue.d.ts +1 -0
  10. package/dist/features/editor/components/EditPanel.vue.d.ts.map +1 -1
  11. package/dist/features/editor/composables/useEditMode.d.ts +4 -16
  12. package/dist/features/editor/composables/useEditMode.d.ts.map +1 -1
  13. package/dist/features/parts-manager/components/PartsManagerPanel.vue.d.ts.map +1 -1
  14. package/dist/features/parts-manager/composables/usePartsManager.d.ts +1 -0
  15. package/dist/features/parts-manager/composables/usePartsManager.d.ts.map +1 -1
  16. package/dist/features/preview/PreviewArea.vue.d.ts.map +1 -1
  17. package/dist/i18n/index.d.ts +18 -0
  18. package/dist/i18n/index.d.ts.map +1 -1
  19. package/dist/i18n/locales/en.d.ts +9 -0
  20. package/dist/i18n/locales/en.d.ts.map +1 -1
  21. package/dist/i18n/locales/ja.d.ts +9 -0
  22. package/dist/i18n/locales/ja.d.ts.map +1 -1
  23. package/dist/zerocode.es.js +13733 -14317
  24. package/dist/zerocode.umd.js +57 -62
  25. package/dist/zerocodejs.css +1 -1
  26. package/package.json +6 -5
  27. package/dist/__tests__/fixtures/sample-data.d.ts +0 -23
  28. package/dist/__tests__/fixtures/sample-data.d.ts.map +0 -1
  29. package/dist/__tests__/fixtures/sample-templates.d.ts +0 -25
  30. package/dist/__tests__/fixtures/sample-templates.d.ts.map +0 -1
  31. package/dist/core/utils/component-initializer.test.d.ts +0 -2
  32. package/dist/core/utils/component-initializer.test.d.ts.map +0 -1
  33. package/dist/core/utils/field-extractor.test.d.ts +0 -2
  34. package/dist/core/utils/field-extractor.test.d.ts.map +0 -1
  35. package/dist/core/utils/image-utils.test.d.ts +0 -2
  36. package/dist/core/utils/image-utils.test.d.ts.map +0 -1
  37. package/dist/core/utils/path-utils.test.d.ts +0 -2
  38. package/dist/core/utils/path-utils.test.d.ts.map +0 -1
  39. package/dist/core/utils/storage.test.d.ts +0 -2
  40. package/dist/core/utils/storage.test.d.ts.map +0 -1
  41. package/dist/core/utils/template-processor.test.d.ts +0 -2
  42. package/dist/core/utils/template-processor.test.d.ts.map +0 -1
  43. package/dist/core/utils/template-utils.test.d.ts +0 -2
  44. package/dist/core/utils/template-utils.test.d.ts.map +0 -1
  45. package/dist/core/utils/validation.test.d.ts +0 -2
  46. package/dist/core/utils/validation.test.d.ts.map +0 -1
  47. package/dist/css/common.css +0 -677
  48. package/dist/css/docs.css +0 -396
  49. package/dist/css/index.css +0 -1039
  50. package/dist/css/page.css +0 -290
  51. package/dist/css/sample.css +0 -26
  52. package/dist/css/site-common.css +0 -218
  53. package/dist/footer.html +0 -10
  54. package/dist/header.html +0 -10
  55. package/dist/images/customer-avatar.jpg +0 -0
  56. package/dist/images/default-avatar.jpg +0 -0
  57. package/dist/images/default.jpg +0 -0
  58. package/dist/images/hero-bg.jpg +0 -0
  59. package/dist/images/kv_image.jpg +0 -0
  60. package/dist/images/page-specific-hero.jpg +0 -0
  61. package/dist/images/sample-1.jpg +0 -0
  62. package/dist/images/sample-2.jpg +0 -0
  63. package/dist/images/sample-3.jpg +0 -0
  64. package/dist/images/zcode_top_01.png +0 -0
  65. package/dist/js/accordion.js +0 -24
  66. package/dist/js/common.js +0 -1093
  67. package/dist/zerocode.es.js.map +0 -1
  68. package/dist/zerocode.umd.js.map +0 -1
package/dist/js/common.js DELETED
@@ -1,1093 +0,0 @@
1
- /**
2
- * ZeroCode.js - 共通JavaScript
3
- * サンプルデータとセッションストレージ管理
4
- */
5
-
6
- // セッションストレージのキー
7
- const STORAGE_KEYS = {
8
- PAGE: 'zcode-page',
9
- CSS_COMMON: 'zcode-css-common',
10
- CSS_INDIVIDUAL: 'zcode-css-individual',
11
- CSS_SPECIAL: 'zcode-css-special',
12
- PARTS_COMMON: 'zcode-parts-common',
13
- PARTS_INDIVIDUAL: 'zcode-parts-individual',
14
- PARTS_SPECIAL: 'zcode-parts-special',
15
- IMAGES_COMMON: 'zcode-images-common',
16
- IMAGES_INDIVIDUAL: 'zcode-images-individual',
17
- IMAGES_SPECIAL: 'zcode-images-special'
18
- };
19
-
20
- // サンプルデータ(index.htmlから抽出)
21
- const SAMPLE_DATA = {
22
- cssCommon: '',
23
- cssIndividual: '',
24
- cssSpecial: `
25
- .banner {
26
- width: 100%;
27
- margin: 0 auto;
28
- padding: 20px;
29
- border: 1px solid var(--c-color-gray-2);
30
- border-radius: var(--c-radius);
31
- background: var(--c-color-white);
32
- box-shadow: var(--c-shadow);
33
- }
34
-
35
- .banner img {
36
- width: 100%;
37
- height: auto;
38
- display: block;
39
- }
40
-
41
- .banner__text {
42
- margin-top: 12px;
43
- color: var(--c-color-gray);
44
- font-size: 14px;
45
- line-height: 1.75;
46
- text-align: center;
47
- }
48
- `,
49
- page: [
50
- {
51
- id: 'kv-1',
52
- part_id: 'zcode-part-layout-kv',
53
- hero_image: 'img-sample-1',
54
- hero_image_alt: '店舗キービジュアル'
55
- },
56
- {
57
- id: 'section-message-1',
58
- part_id: 'zcode-part-layout-section',
59
- title: 'メッセージ',
60
- subtitle: 'Message',
61
- show_subtitle: true,
62
- slots: {
63
- contents: [
64
- {
65
- id: 'message-1',
66
- part_id: 'zcode-part-message',
67
- text: '<p>私たちは、地域に根ざしたサービスで、お客様の体験をより良くします。</p><p>店舗ごとの強みや最新情報を、わかりやすく発信します。</p>'
68
- }
69
- ]
70
- }
71
- },
72
- {
73
- id: 'section-features-1',
74
- part_id: 'zcode-part-layout-section',
75
- title: 'サービスの特徴',
76
- subtitle: 'Features',
77
- show_subtitle: true,
78
- slots: {
79
- contents: [
80
- {
81
- id: 'numbered-1',
82
- part_id: 'zcode-part-numbered',
83
- slots: {
84
- items: [
85
- {
86
- id: 'feature-1',
87
- part_id: 'zcode-part-numbered-item',
88
- title: '品揃えが豊富',
89
- text: '<p>定番から最新トレンドまで、幅広いラインナップをご用意しています。季節に合わせた商品の入れ替えも迅速で、常に新鮮な選択肢をお届けします。お客様の様々なニーズにお応えできるよう、多様なカテゴリーから厳選したアイテムを取り揃えています。</p>'
90
- },
91
- {
92
- id: 'feature-2',
93
- part_id: 'zcode-part-numbered-item',
94
- title: '充実のサポート',
95
- text: '<p>はじめての方でも、スタッフが丁寧にご案内します。お客様一人ひとりに寄り添ったサービスを心がけており、ご質問やご相談にも迅速に対応いたします。専門知識を持ったスタッフが、最適なソリューションをご提案させていただきます。</p>'
96
- },
97
- {
98
- id: 'feature-3',
99
- part_id: 'zcode-part-numbered-item',
100
- title: 'アクセス良好',
101
- text: '<p>駅から近く、来店しやすい立地です。主要な交通機関から徒歩圏内にあり、お車でのご来店も可能です。駐車場も完備しており、お買い物やご相談の際にも安心してお越しいただけます。周辺には商業施設も充実しており、お立ち寄りの際にも便利です。</p>'
102
- }
103
- ]
104
- }
105
- }
106
- ]
107
- }
108
- },
109
- {
110
- id: 'section-events-1',
111
- part_id: 'zcode-part-layout-section',
112
- title: 'イベント情報',
113
- subtitle: 'Events',
114
- show_subtitle: true,
115
- slots: {
116
- contents: [
117
- {
118
- id: 'event-1',
119
- part_id: 'zcode-part-event',
120
- slots: {
121
- items: [
122
- {
123
- id: 'event-item-1',
124
- part_id: 'zcode-part-event-item',
125
- date: '2026.01.15',
126
- title: 'シーズンキャンペーン',
127
- text: '<p>期間限定の特典をご用意しています。この機会にぜひご利用ください。新規のお客様には特別な割引も適用され、お得にお買い物をお楽しみいただけます。キャンペーン期間中は、通常のサービスに加えて追加の特典もご用意しております。詳細については、店舗スタッフまでお気軽にお問い合わせください。</p>',
128
- tags: true,
129
- slots: {
130
- tags: [
131
- {
132
- id: 'tag-1',
133
- part_id: 'zcode-part-tag',
134
- text: 'フェア'
135
- }
136
- ]
137
- }
138
- },
139
- {
140
- id: 'event-item-2',
141
- part_id: 'zcode-part-event-item',
142
- date: '2026.02.01',
143
- title: 'ご相談会',
144
- text: '<p>ご希望やお悩みをヒアリングして最適な提案をします。専門スタッフがお客様の状況を詳しくお聞きし、一人ひとりに合わせたプランをご提案いたします。事前予約制となっており、ゆっくりとご相談いただけます。お気軽にご参加ください。当日はお飲み物もご用意しておりますので、リラックスしてお話しいただけます。</p>',
145
- tags: true,
146
- slots: {
147
- tags: [
148
- {
149
- id: 'tag-2',
150
- part_id: 'zcode-part-tag',
151
- text: '相談会'
152
- }
153
- ]
154
- }
155
- }
156
- ]
157
- }
158
- }
159
- ]
160
- }
161
- },
162
- {
163
- id: 'section-info-1',
164
- part_id: 'zcode-part-layout-section',
165
- title: '店舗情報',
166
- subtitle: 'Store Information',
167
- show_subtitle: true,
168
- slots: {
169
- contents: [
170
- {
171
- id: 'info-1',
172
- part_id: 'zcode-part-info',
173
- slots: {
174
- items: [
175
- {
176
- id: 'info-item-1',
177
- part_id: 'zcode-part-info-item',
178
- label: '住所',
179
- value: '東京都〇〇区〇〇 1-2-3'
180
- },
181
- {
182
- id: 'info-item-2',
183
- part_id: 'zcode-part-info-item',
184
- label: '営業時間',
185
- value: '10:00〜19:00'
186
- },
187
- {
188
- id: 'info-item-3',
189
- part_id: 'zcode-part-info-item',
190
- label: '定休日',
191
- value: '水曜'
192
- },
193
- {
194
- id: 'info-item-4',
195
- part_id: 'zcode-part-info-item',
196
- label: '電話',
197
- value: '03-0000-0000'
198
- },
199
- {
200
- id: 'info-item-5',
201
- part_id: 'zcode-part-info-item',
202
- label: 'アクセス',
203
- value: '〇〇駅 徒歩5分'
204
- }
205
- ]
206
- }
207
- }
208
- ]
209
- }
210
- },
211
- {
212
- id: 'section-faq-1',
213
- part_id: 'zcode-part-layout-section',
214
- title: 'よくある質問',
215
- subtitle: 'FAQ',
216
- show_subtitle: true,
217
- slots: {
218
- contents: [
219
- {
220
- id: 'faq-1',
221
- part_id: 'zcode-part-faq',
222
- slots: {
223
- items: [
224
- {
225
- id: 'faq-item-1',
226
- part_id: 'zcode-part-faq-item',
227
- question: '予約は必要ですか?',
228
- answer:
229
- '<p>基本的には予約なしでもご利用いただけますが、混雑状況によってはお待ちいただく場合があります。確実にご案内するため、事前予約をおすすめします。</p>'
230
- },
231
- {
232
- id: 'faq-item-2',
233
- part_id: 'zcode-part-faq-item',
234
- question: '支払い方法は何がありますか?',
235
- answer:
236
- '<p>現金・主要クレジットカード・各種QR決済に対応しています。法人のお客様向けに請求書払いのご相談も可能です。</p>'
237
- },
238
- {
239
- id: 'faq-item-3',
240
- part_id: 'zcode-part-faq-item',
241
- question: '当日の持ち物はありますか?',
242
- answer:
243
- '<p>特別な持ち物は不要です。必要に応じて、本人確認書類やご希望内容が分かるメモがあるとスムーズです。</p>'
244
- }
245
- ]
246
- }
247
- }
248
- ]
249
- }
250
- }
251
- ],
252
- typesCommon: [
253
- {
254
- id: 'zcode-common-heading',
255
- type: 'heading',
256
- description: '見出し',
257
- parts: [
258
- {
259
- id: 'zcode-part-heading-h1',
260
- title: 'heading_h1',
261
- description: '見出し(H1)',
262
- body: `<div class="c-heading c-heading--h1">
263
- <h1 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h1>
264
- </div>`
265
- },
266
- {
267
- id: 'zcode-part-heading-h2',
268
- title: 'heading_h2',
269
- description: '見出し(H2)',
270
- body: `<div class="c-heading c-heading--h2">
271
- <h2 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h2>
272
- </div>`
273
- },
274
- {
275
- id: 'zcode-part-heading-h3',
276
- title: 'heading_h3',
277
- description: '見出し(H3)',
278
- body: `<div class="c-heading c-heading--h3">
279
- <h3 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h3>
280
- </div>`
281
- },
282
- {
283
- id: 'zcode-part-heading-h4',
284
- title: 'heading_h4',
285
- description: '見出し(H4)',
286
- body: `<div class="c-heading c-heading--h4">
287
- <h4 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h4>
288
- </div>`
289
- },
290
- {
291
- id: 'zcode-part-heading-h5',
292
- title: 'heading_h5',
293
- description: '見出し(H5)',
294
- body: `<div class="c-heading c-heading--h5">
295
- <h5 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h5>
296
- </div>`
297
- },
298
- {
299
- id: 'zcode-part-heading-h6',
300
- title: 'heading_h6',
301
- description: '見出し(H6)',
302
- body: `<div class="c-heading c-heading--h6">
303
- <h6 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h6>
304
- </div>`
305
- }
306
- ]
307
- },
308
- {
309
- id: 'zcode-common-text',
310
- type: 'text',
311
- description: '文章',
312
- parts: [
313
- {
314
- id: 'zcode-part-text',
315
- title: 'text',
316
- description: '文章(リッチテキスト)',
317
- body: `<div class="c-text">{$text:本文を入力してください:rich}</div>`
318
- }
319
- ]
320
- },
321
- {
322
- id: 'zcode-common-box',
323
- type: 'box',
324
- description: 'ボックス',
325
- parts: [
326
- {
327
- id: 'zcode-part-box',
328
- title: 'box',
329
- description: 'ボックス(見出し+文章)',
330
- body: `<div class="c-box c-box--tone-($tone.style:neutral|primary|accent)">
331
- <div class="c-box__inner">
332
- <div class="c-box__heading">{$heading.content:ボックス見出し}</div>
333
- <div class="c-box__body">{$text.content:ボックス本文:rich}</div>
334
- </div>
335
- </div>`
336
- }
337
- ]
338
- },
339
- {
340
- id: 'zcode-common-media',
341
- type: 'media',
342
- description: 'メディア(画像+コンテンツ)',
343
- parts: [
344
- {
345
- id: 'zcode-part-media',
346
- title: 'media',
347
- description: '画像とコンテンツの横並び',
348
- body: `<div class="c-media c-media--dir-($dir.layout:normal|reverse) c-media--valign-($valign.layout:top|center|bottom)">
349
- <div class="c-media__image">
350
- <img class="c-media__img" src="{$image.image:img-default:image}" alt="{$alt.image:画像の説明}">
351
- </div>
352
- <div class="c-media__content">
353
- <div class="c-media__heading">{$heading.content:見出し}</div>
354
- <div class="c-media__text">{$text.content:本文:rich}</div>
355
- <div class="c-media__actions">
356
- <a class="c-button c-button--style-($style.action:primary|secondary|text)" href="{$href.action:#}">{$label.action:詳しく見る}</a>
357
- </div>
358
- </div>
359
- </div>`
360
- }
361
- ]
362
- },
363
- {
364
- id: 'zcode-common-image',
365
- type: 'image',
366
- description: '画像',
367
- parts: [
368
- {
369
- id: 'zcode-part-image',
370
- title: 'image',
371
- description: '画像',
372
- body: `<div class="c-image c-image--align-($align.layout:left|center|right)">
373
- <div class="c-image__media">
374
- <img class="c-image__img" src="{$image.image:img-default:image}" alt="{$alt.image:画像の説明}">
375
- </div>
376
- <div class="c-image__caption">{$caption.caption:キャプション}</div>
377
- </div>`
378
- }
379
- ]
380
- },
381
- {
382
- id: 'zcode-common-table',
383
- type: 'table',
384
- description: '表組',
385
- parts: [
386
- {
387
- id: 'zcode-part-table',
388
- title: 'table',
389
- description: '表(ヘッダー/行はスロット)',
390
- slots: {
391
- header_cells: { allowedParts: ['zcode-part-table-header-cell'] },
392
- rows: { allowedParts: ['zcode-part-table-row'] }
393
- },
394
- body: `<div class="c-table c-table--style-($style.style:plain|striped|bordered)" role="table">
395
- <div class="c-table__caption">{$caption.info:表の説明}</div>
396
- <div class="c-table__header" role="rowgroup">
397
- <div class="c-table__row" role="row" z-slot="header_cells"></div>
398
- </div>
399
- <div class="c-table__body" role="rowgroup" z-slot="rows"></div>
400
- </div>`
401
- },
402
- {
403
- id: 'zcode-part-table-header-cell',
404
- title: 'table_header_cell',
405
- description: 'ヘッダーセル',
406
- slotOnly: true,
407
- body: `<div class="c-table__cell c-table__cell--head c-table__cell--align-($align.layout:left|center|right)" role="columnheader">{$text.content:見出し}</div>`
408
- },
409
- {
410
- id: 'zcode-part-table-row',
411
- title: 'table_row',
412
- description: '行',
413
- slotOnly: true,
414
- slots: {
415
- cells: { allowedParts: ['zcode-part-table-cell'] }
416
- },
417
- body: `<div class="c-table__row" role="row" z-slot="cells"></div>`
418
- },
419
- {
420
- id: 'zcode-part-table-cell',
421
- title: 'table_cell',
422
- description: 'セル',
423
- slotOnly: true,
424
- body: `<div class="c-table__cell c-table__cell--align-($align.layout:left|center|right)" role="cell">{$text.content:セル}</div>`
425
- }
426
- ]
427
- },
428
- {
429
- id: 'zcode-common-actions',
430
- type: 'actions',
431
- description: 'リンク/ボタン',
432
- parts: [
433
- {
434
- id: 'zcode-part-button',
435
- title: 'button',
436
- description: 'ボタン',
437
- body: `<div class="c-actions c-actions--align-($align.style:left|center|right)">
438
- <a class="c-button c-button--style-($style.style:primary|secondary|text)" href="{$href.action:#}">{$label.action:ボタン}</a>
439
- </div>`
440
- },
441
- {
442
- id: 'zcode-part-link',
443
- title: 'link',
444
- description: 'テキストリンク',
445
- body: `<a class="c-link" href="{$href:#}">{$text:リンク}</a>`
446
- }
447
- ]
448
- }
449
- ],
450
- typesIndividual: [
451
- {
452
- id: 'zcode-individual-layout',
453
- type: 'layout',
454
- description: 'レイアウト(店舗ページ向け)',
455
- parts: [
456
- {
457
- id: 'zcode-part-layout-kv',
458
- title: 'layout_store_kv',
459
- description: 'キービジュアルセクション(店舗)',
460
- body: `<div class="kv">
461
- <div class="kv__image">
462
- <img class="kv__img" src="{$hero_image.image:img-sample-1:image}" alt="{$hero_image_alt.image:キービジュアル}">
463
- </div>
464
- </div>`
465
- },
466
- {
467
- id: 'zcode-part-layout-section',
468
- title: 'layout_section',
469
- description: '共通セクション(見出し + コンテンツ)',
470
- slots: {
471
- contents: {
472
- allowedParts: [
473
- 'zcode-part-message',
474
- 'zcode-part-numbered',
475
- 'zcode-part-event',
476
- 'zcode-part-info',
477
- 'zcode-part-faq'
478
- ]
479
- }
480
- },
481
- body: `<div class="section">
482
- <div class="section__head">
483
- <div class="section__title" role="heading" aria-level="2">{$title.header:セクションタイトル}</div>
484
- <div class="section__subtitle" z-if="show_subtitle">{$subtitle.header:Subtitle}</div>
485
- </div>
486
- <div class="section__contents">
487
- <div class="section__items" z-slot="contents"></div>
488
- </div>
489
- </div>`
490
- }
491
- ]
492
- },
493
- {
494
- id: 'zcode-individual-message',
495
- type: 'message',
496
- description: 'メッセージ',
497
- parts: [
498
- {
499
- id: 'zcode-part-message',
500
- slotOnly: true,
501
- body: `<div class="message__text">{$text:メッセージ文:rich}</div>`
502
- }
503
- ]
504
- },
505
- {
506
- id: 'zcode-individual-numbered',
507
- type: 'numbered',
508
- description: '数字付きアイテム',
509
- parts: [
510
- {
511
- id: 'zcode-part-numbered',
512
- title: 'numbered',
513
- description: '数字付きアイテムリスト',
514
- slotOnly: true,
515
- slots: {
516
- items: { allowedParts: ['zcode-part-numbered-item'] }
517
- },
518
- body: `<div class="numbered">
519
- <div class="numbered__items" z-slot="items"></div>
520
- </div>`
521
- },
522
- {
523
- id: 'zcode-part-numbered-item',
524
- title: 'numbered_item',
525
- description: '数字付きアイテム',
526
- slotOnly: true,
527
- body: `<div class="numbered-item">
528
- <div class="numbered-item__number"></div>
529
- <div class="numbered-item__title" role="heading" aria-level="3">{$title.content:タイトル}</div>
530
- <div class="numbered-item__text">{$text.content:説明:rich}</div>
531
- </div>`
532
- }
533
- ]
534
- },
535
- {
536
- id: 'zcode-individual-event',
537
- type: 'event',
538
- description: 'イベント',
539
- parts: [
540
- {
541
- id: 'zcode-part-event',
542
- title: 'event',
543
- description: 'イベントリスト',
544
- slotOnly: true,
545
- slots: {
546
- items: { allowedParts: ['zcode-part-event-item'] }
547
- },
548
- body: `<div class="event">
549
- <div class="event__items" z-slot="items"></div>
550
- </div>`
551
- },
552
- {
553
- id: 'zcode-part-event-item',
554
- title: 'event_item',
555
- description: 'イベントアイテム(タグ付き)',
556
- slotOnly: true,
557
- slots: {
558
- tags: { allowedParts: ['zcode-part-tag'] }
559
- },
560
- body: `<div class="event-item" role="listitem">
561
- <div class="event-item__meta">
562
- <div class="event-item__date" z-if="show_date">{$date.meta:2026.01.01}</div>
563
- <div class="event-item__tags" z-if="show_tags" z-slot="tags"></div>
564
- </div>
565
- <div class="event-item__title" role="heading" aria-level="3">{$title.content:タイトル}</div>
566
- <div class="event-item__text">{$text.content:説明:rich}</div>
567
- <div class="event-item__actions" z-if="show_href">
568
- <a class="c-link" href="{$href.action:#}">{$label.action:詳細}</a>
569
- </div>
570
- </div>`
571
- },
572
- {
573
- id: 'zcode-part-tag',
574
- title: 'tag',
575
- description: 'タグ',
576
- slotOnly: true,
577
- body: `<div class="tag">{$text:タグ}</div>`
578
- }
579
- ]
580
- },
581
- {
582
- id: 'zcode-individual-info',
583
- type: 'info',
584
- description: '情報リスト',
585
- parts: [
586
- {
587
- id: 'zcode-part-info',
588
- title: 'info',
589
- description: '情報リスト',
590
- slotOnly: true,
591
- slots: {
592
- items: { allowedParts: ['zcode-part-info-item'] }
593
- },
594
- body: `<div class="info">
595
- <div class="info__items" z-slot="items"></div>
596
- </div>`
597
- },
598
- {
599
- id: 'zcode-part-info-item',
600
- title: 'info_item',
601
- description: '情報行アイテム',
602
- slotOnly: true,
603
- body: `<div class="info-item" role="listitem">
604
- <div class="info-item__label">{$label.info:ラベル}</div>
605
- <div class="info-item__value">{$value.info:値}</div>
606
- </div>`
607
- }
608
- ]
609
- },
610
- {
611
- id: 'zcode-individual-faq',
612
- type: 'faq',
613
- description: 'よくある質問',
614
- parts: [
615
- {
616
- id: 'zcode-part-faq',
617
- title: 'faq',
618
- description: 'よくある質問(アコーディオン)',
619
- slotOnly: true,
620
- slots: {
621
- items: { allowedParts: ['zcode-part-faq-item'] }
622
- },
623
- body: `<div class="faq">
624
- <div class="faq__items" z-slot="items"></div>
625
- </div>`
626
- },
627
- {
628
- id: 'zcode-part-faq-item',
629
- title: 'faq_item',
630
- description: 'FAQアイテム(Q&A)',
631
- slotOnly: true,
632
- body: `<div class="faq-item js_toggleArea s_close" role="listitem">
633
- <button class="faq-item__q js_toggleBtn" type="button" aria-expanded="false">
634
- {$question.content:質問}
635
- </button>
636
- <div class="faq-item__a js_toggleContents" style="display:none">
637
- {$answer.content:回答:rich}
638
- </div>
639
- </div>`
640
- }
641
- ]
642
- }
643
- ],
644
- imagesCommon: [
645
- {
646
- id: 'img-default',
647
- name: 'Default',
648
- url: './images/default.jpg',
649
- mimeType: 'image/jpeg',
650
- needsUpload: false
651
- },
652
- {
653
- id: 'img-hero-bg',
654
- name: 'Hero BG',
655
- url: './images/hero-bg.jpg',
656
- mimeType: 'image/jpeg',
657
- needsUpload: false
658
- },
659
- {
660
- id: 'img-sample-2',
661
- name: 'Sample 2',
662
- url: './images/sample-2.jpg',
663
- mimeType: 'image/jpeg',
664
- needsUpload: false
665
- },
666
- {
667
- id: 'img-sample-3',
668
- name: 'Sample 3',
669
- url: './images/sample-3.jpg',
670
- mimeType: 'image/jpeg',
671
- needsUpload: false
672
- },
673
- {
674
- id: 'img-page-specific-hero',
675
- name: 'Page Specific Hero',
676
- url: './images/page-specific-hero.jpg',
677
- mimeType: 'image/jpeg',
678
- needsUpload: false
679
- },
680
- {
681
- id: 'img-customer-avatar',
682
- name: 'Customer Avatar',
683
- url: './images/customer-avatar.jpg',
684
- mimeType: 'image/jpeg',
685
- needsUpload: false
686
- },
687
- {
688
- id: 'img-default-avatar',
689
- name: 'Default Avatar',
690
- url: './images/default-avatar.jpg',
691
- mimeType: 'image/jpeg',
692
- needsUpload: false
693
- }
694
- ],
695
- typesSpecial: [
696
- {
697
- id: 'zcode-special-banner',
698
- type: 'banner',
699
- description: 'バナー(特別ページ向け)',
700
- parts: [
701
- {
702
- id: 'zcode-part-special-banner',
703
- title: 'special_banner',
704
- description: '特別バナー(店舗ごとなど)',
705
- body: `<div class="banner">
706
- <img src="{$banner_image.image:img-special-banner:image}" alt="{$banner_alt.image:バナー}">
707
- <div class="banner__text">{$banner_text.content:バナーテキスト}</div>
708
- </div>`
709
- }
710
- ]
711
- }
712
- ],
713
- imagesIndividual: [
714
- {
715
- id: 'img-sample-1',
716
- name: 'Sample 1',
717
- url: './images/kv_image.jpg',
718
- mimeType: 'image/jpeg',
719
- needsUpload: false
720
- }
721
- ],
722
- imagesSpecial: [
723
- {
724
- id: 'img-special-banner',
725
- name: 'Special Banner',
726
- url: './images/zcode_top_01.png',
727
- mimeType: 'image/png',
728
- needsUpload: false
729
- }
730
- ]
731
- };
732
-
733
- // インスタンスIDを取得または生成
734
- function getInstanceId(component) {
735
- // id属性を優先
736
- if (component.id) {
737
- return component.id;
738
- }
739
-
740
- // data-instance-id属性があれば使用
741
- const dataInstanceId = component.getAttribute('data-instance-id');
742
- if (dataInstanceId) {
743
- return dataInstanceId;
744
- }
745
-
746
- // 自動生成して属性に設定
747
- const instanceId = `zcode-instance-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
748
- component.setAttribute('data-instance-id', instanceId);
749
- return instanceId;
750
- }
751
-
752
- // ストレージキーを生成
753
- function getStorageKey(instanceId, key) {
754
- return `zcode-${instanceId}-${key}`;
755
- }
756
-
757
- // セッションストレージ管理ユーティリティ
758
- const StorageManager = {
759
- normalizeImageUrl(url) {
760
- if (typeof url !== 'string') return url;
761
- if (url.startsWith('/images/')) {
762
- return `./images/${url.slice('/images/'.length)}`;
763
- }
764
- return url;
765
- },
766
-
767
- normalizeImages(images) {
768
- if (!Array.isArray(images)) return images;
769
- return images.map((img) => {
770
- if (!img || typeof img !== 'object') return img;
771
- if (typeof img.url !== 'string') return img;
772
- const normalized = this.normalizeImageUrl(img.url);
773
- if (normalized === img.url) return img;
774
- return { ...img, url: normalized };
775
- });
776
- },
777
-
778
- // データをローカルストレージに保存(インスタンスID対応)
779
- save(instanceId, key, data) {
780
- try {
781
- const storageKey = getStorageKey(instanceId, key);
782
- localStorage.setItem(storageKey, JSON.stringify(data));
783
- return true;
784
- } catch (e) {
785
- console.error(`Failed to save ${key}:`, e);
786
- return false;
787
- }
788
- },
789
-
790
- // ローカルストレージからデータを取得(インスタンスID対応)
791
- load(instanceId, key, defaultValue = null) {
792
- try {
793
- const storageKey = getStorageKey(instanceId, key);
794
- const item = localStorage.getItem(storageKey);
795
- return item ? JSON.parse(item) : defaultValue;
796
- } catch (e) {
797
- console.error(`Failed to load ${key}:`, e);
798
- return defaultValue;
799
- }
800
- },
801
-
802
- // ローカルストレージからデータを削除(インスタンスID対応)
803
- remove(instanceId, key) {
804
- try {
805
- const storageKey = getStorageKey(instanceId, key);
806
- localStorage.removeItem(storageKey);
807
- return true;
808
- } catch (e) {
809
- console.error(`Failed to remove ${key}:`, e);
810
- return false;
811
- }
812
- },
813
-
814
- // すべてのデータをクリア(インスタンスID対応)
815
- clear(instanceId) {
816
- const keys = [
817
- 'page',
818
- 'css-common',
819
- 'css-individual',
820
- 'css-special',
821
- 'parts-common',
822
- 'parts-individual',
823
- 'parts-special',
824
- 'images-common',
825
- 'images-individual',
826
- 'images-special'
827
- ];
828
- keys.forEach((key) => {
829
- this.remove(instanceId, key);
830
- });
831
- },
832
-
833
- // サンプルデータをセッションストレージに保存(インスタンスID対応)
834
- saveSampleData(instanceIdOrComponentId) {
835
- // コンポーネントIDが渡された場合はインスタンスIDを取得
836
- let instanceId = instanceIdOrComponentId;
837
- if (instanceIdOrComponentId) {
838
- const component = document.getElementById(instanceIdOrComponentId);
839
- if (component) {
840
- instanceId = getInstanceId(component);
841
- } else {
842
- // コンポーネントが見つからない場合は、そのままインスタンスIDとして使用
843
- instanceId = instanceIdOrComponentId;
844
- }
845
- } else {
846
- // インスタンスIDが指定されていない場合はデフォルトを使用
847
- instanceId = 'default';
848
- }
849
-
850
- this.save(instanceId, 'page', SAMPLE_DATA.page);
851
- this.save(instanceId, 'css-common', SAMPLE_DATA.cssCommon || '');
852
- this.save(instanceId, 'css-individual', SAMPLE_DATA.cssIndividual || '');
853
- this.save(instanceId, 'css-special', SAMPLE_DATA.cssSpecial || '');
854
- this.save(instanceId, 'parts-common', SAMPLE_DATA.typesCommon);
855
- this.save(instanceId, 'parts-individual', SAMPLE_DATA.typesIndividual);
856
- this.save(instanceId, 'parts-special', SAMPLE_DATA.typesSpecial || []);
857
- this.save(instanceId, 'images-common', SAMPLE_DATA.imagesCommon);
858
- this.save(instanceId, 'images-individual', SAMPLE_DATA.imagesIndividual);
859
- this.save(instanceId, 'images-special', SAMPLE_DATA.imagesSpecial || []);
860
- return true;
861
- },
862
-
863
- // セッションストレージからデータを読み込み(インスタンスID対応)
864
- loadData(instanceIdOrComponentId) {
865
- // コンポーネントIDが渡された場合はインスタンスIDを取得
866
- let instanceId = instanceIdOrComponentId;
867
- if (instanceIdOrComponentId) {
868
- const component = document.getElementById(instanceIdOrComponentId);
869
- if (component) {
870
- instanceId = getInstanceId(component);
871
- } else {
872
- // コンポーネントが見つからない場合は、そのままインスタンスIDとして使用
873
- instanceId = instanceIdOrComponentId;
874
- }
875
- } else {
876
- // インスタンスIDが指定されていない場合はデフォルトを使用
877
- instanceId = 'default';
878
- }
879
-
880
- const data = {
881
- page: this.load(instanceId, 'page', []),
882
- cssCommon: this.load(instanceId, 'css-common', ''),
883
- cssIndividual: this.load(instanceId, 'css-individual', ''),
884
- cssSpecial: this.load(instanceId, 'css-special', ''),
885
- typesCommon: this.load(instanceId, 'parts-common', []),
886
- typesIndividual: this.load(instanceId, 'parts-individual', []),
887
- typesSpecial: this.load(instanceId, 'parts-special', []),
888
- imagesCommon: this.load(instanceId, 'images-common', []),
889
- imagesIndividual: this.load(instanceId, 'images-individual', []),
890
- imagesSpecial: this.load(instanceId, 'images-special', [])
891
- };
892
-
893
- const normalizedCommon = this.normalizeImages(data.imagesCommon);
894
- const normalizedIndividual = this.normalizeImages(data.imagesIndividual);
895
- const normalizedSpecial = this.normalizeImages(data.imagesSpecial);
896
-
897
- const changed =
898
- JSON.stringify(normalizedCommon) !== JSON.stringify(data.imagesCommon) ||
899
- JSON.stringify(normalizedIndividual) !== JSON.stringify(data.imagesIndividual) ||
900
- JSON.stringify(normalizedSpecial) !== JSON.stringify(data.imagesSpecial);
901
-
902
- if (changed) {
903
- data.imagesCommon = normalizedCommon;
904
- data.imagesIndividual = normalizedIndividual;
905
- data.imagesSpecial = normalizedSpecial;
906
- this.save(instanceId, 'images-common', data.imagesCommon);
907
- this.save(instanceId, 'images-individual', data.imagesIndividual);
908
- this.save(instanceId, 'images-special', data.imagesSpecial || []);
909
- }
910
-
911
- return data;
912
- },
913
-
914
- // Webコンポーネントにデータを適用(インスタンスID対応)
915
- applyToComponent(componentId) {
916
- const component = document.getElementById(componentId);
917
- if (!component) {
918
- console.error(`Component not found: ${componentId}`);
919
- return false;
920
- }
921
-
922
- const instanceId = getInstanceId(component);
923
- const data = this.loadData(instanceId);
924
-
925
- component.setAttribute('page', JSON.stringify(data.page));
926
- if (data.cssCommon) {
927
- component.setAttribute('css-common', data.cssCommon);
928
- }
929
- if (data.cssIndividual) {
930
- component.setAttribute('css-individual', data.cssIndividual);
931
- }
932
- if (data.cssSpecial) {
933
- component.setAttribute('css-special', data.cssSpecial);
934
- }
935
- component.setAttribute('parts-common', JSON.stringify(data.typesCommon));
936
- component.setAttribute('parts-individual', JSON.stringify(data.typesIndividual));
937
- component.setAttribute('parts-special', JSON.stringify(data.typesSpecial || []));
938
- component.setAttribute('images-common', JSON.stringify(data.imagesCommon));
939
- component.setAttribute('images-individual', JSON.stringify(data.imagesIndividual));
940
- component.setAttribute('images-special', JSON.stringify(data.imagesSpecial || []));
941
-
942
- return true;
943
- }
944
- };
945
-
946
- // 保存/リセットイベントリスナーを設定
947
- function setupSaveResetListeners() {
948
- // zcode-cmsとzcode-editorの両方に対応
949
- const components = document.querySelectorAll('zcode-cms, zcode-editor');
950
-
951
- components.forEach((component) => {
952
- // インスタンスIDを取得
953
- const instanceId = getInstanceId(component);
954
-
955
- // 保存リクエスト
956
- component.addEventListener('save-request', (e) => {
957
- const { source } = e.detail;
958
- const targets = Array.isArray(e.detail.targets)
959
- ? e.detail.targets
960
- : typeof e.detail.target === 'string'
961
- ? [e.detail.target]
962
- : [];
963
- const requestId =
964
- typeof e.detail.requestId === 'string'
965
- ? e.detail.requestId
966
- : `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;
967
-
968
- console.debug('[ZeroCodeCommon] save-request received:', { source, targets, requestId });
969
-
970
- if (targets.length === 0) {
971
- console.warn('[ZeroCode] No targets specified');
972
- return;
973
- }
974
-
975
- // ⚠️ 注意: これは補助的な検証です
976
- // 完全なセキュリティ保証のためには、サーバー側での検証が必須です
977
- if (
978
- source === 'cms' &&
979
- (targets.includes('parts-common') || targets.includes('parts-individual'))
980
- ) {
981
- console.warn('[ZeroCode] CMSからはパーツデータの保存はできません');
982
- return;
983
- }
984
-
985
- const data = component.getData();
986
-
987
- if (!data) {
988
- console.warn('[ZeroCode] No data available to save');
989
- return;
990
- }
991
-
992
- let allSaved = true;
993
- for (const target of targets) {
994
- let key;
995
- let dataToSave;
996
- let ok = true;
997
- let errors = [];
998
-
999
- switch (target) {
1000
- case 'page':
1001
- key = 'page';
1002
- dataToSave = data.page;
1003
- break;
1004
- case 'parts-common-css':
1005
- key = 'parts-common-css';
1006
- dataToSave = typeof data.css?.common === 'string' ? data.css.common : '';
1007
- break;
1008
- case 'parts-individual-css':
1009
- key = 'parts-individual-css';
1010
- dataToSave = typeof data.css?.individual === 'string' ? data.css.individual : '';
1011
- break;
1012
- case 'parts-special-css':
1013
- key = 'parts-special-css';
1014
- dataToSave = typeof data.css?.special === 'string' ? data.css.special : '';
1015
- break;
1016
- case 'parts-common':
1017
- key = 'parts-common';
1018
- dataToSave = data.parts?.common || [];
1019
- break;
1020
- case 'parts-individual':
1021
- key = 'parts-individual';
1022
- dataToSave = data.parts?.individual || [];
1023
- break;
1024
- case 'images-common':
1025
- key = 'images-common';
1026
- dataToSave = data.images?.common || [];
1027
- break;
1028
- case 'images-individual':
1029
- key = 'images-individual';
1030
- dataToSave = data.images?.individual || [];
1031
- break;
1032
- case 'images-special':
1033
- key = 'images-special';
1034
- dataToSave = data.images?.special || [];
1035
- break;
1036
- default:
1037
- console.warn(`[ZeroCode] Unknown save target: ${target}`);
1038
- allSaved = false;
1039
- ok = false;
1040
- errors = [{ message: `Unknown save target: ${target}`, code: 'UNKNOWN_TARGET' }];
1041
- continue;
1042
- }
1043
-
1044
- if (!StorageManager.save(instanceId, key, dataToSave)) {
1045
- console.error(`[ZeroCode] Failed to save ${target}`);
1046
- allSaved = false;
1047
- ok = false;
1048
- errors = [{ message: `Failed to save ${target}`, code: 'SAVE_FAILED' }];
1049
- }
1050
-
1051
- // 保存結果を通知(呼び出し側のバックエンド検証でも同じイベント形式を推奨)
1052
- console.debug('[ZeroCodeCommon] dispatching save-result:', { requestId, target, ok, errors });
1053
- const resultEvent = new CustomEvent('save-result', {
1054
- detail: {
1055
- requestId,
1056
- target,
1057
- ok,
1058
- errors
1059
- },
1060
- bubbles: true,
1061
- composed: true
1062
- });
1063
- component.dispatchEvent(resultEvent);
1064
- }
1065
-
1066
- if (allSaved) {
1067
- const savedEvent = new CustomEvent('zcode-saved', {
1068
- detail: { targets, instanceId },
1069
- bubbles: true,
1070
- composed: true
1071
- });
1072
- component.dispatchEvent(savedEvent);
1073
- }
1074
- });
1075
- });
1076
- }
1077
-
1078
- // DOMContentLoaded時にイベントリスナーを設定
1079
- if (document.readyState === 'loading') {
1080
- document.addEventListener('DOMContentLoaded', setupSaveResetListeners);
1081
- } else {
1082
- setupSaveResetListeners();
1083
- }
1084
-
1085
- // グローバルに公開
1086
- window.ZeroCodeCommon = {
1087
- STORAGE_KEYS,
1088
- SAMPLE_DATA,
1089
- StorageManager,
1090
- setupSaveResetListeners,
1091
- getInstanceId,
1092
- getStorageKey
1093
- };