@growgroup/visual-editor 0.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.
- package/LICENSE +21 -0
- package/NOTICE +52 -0
- package/README.md +143 -0
- package/dist/editor.css +2 -0
- package/package.json +94 -0
- package/src/components/DeckSlideRender.tsx +21 -0
- package/src/components/SaveNote.tsx +21 -0
- package/src/components/auth/AuthProvider.tsx +44 -0
- package/src/components/ui/accordion.tsx +57 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +76 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/context-menu.tsx +200 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/scrubbable-label.tsx +95 -0
- package/src/components/ui/select.tsx +159 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/slider.tsx +28 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/viewer/useDeck.ts +58 -0
- package/src/editor/EditorContext.tsx +632 -0
- package/src/editor/EditorToolbar.tsx +446 -0
- package/src/editor/FrontendVisualEditor.tsx +2595 -0
- package/src/editor/autosave.ts +34 -0
- package/src/editor/components/AiPromptPopover.tsx +378 -0
- package/src/editor/components/BreakpointGuides.tsx +323 -0
- package/src/editor/components/BreakpointSelector.tsx +180 -0
- package/src/editor/components/ComponentPropertyEditor.tsx +426 -0
- package/src/editor/components/CssEditorDialog.tsx +168 -0
- package/src/editor/components/EditorCanvas.tsx +987 -0
- package/src/editor/components/EditorContextMenu.tsx +515 -0
- package/src/editor/components/EditorFooter.tsx +81 -0
- package/src/editor/components/EditorHeader.tsx +524 -0
- package/src/editor/components/EditorLayerPanel.tsx +1197 -0
- package/src/editor/components/EditorPropertyPanel.tsx +2996 -0
- package/src/editor/components/EditorSidebar.tsx +226 -0
- package/src/editor/components/FigmaColorPicker.tsx +1577 -0
- package/src/editor/components/HtmlEditorDialog.tsx +71 -0
- package/src/editor/components/HtmlImportDialog.tsx +346 -0
- package/src/editor/components/JsEditorDialog.tsx +175 -0
- package/src/editor/components/LayerTreeItem.tsx +494 -0
- package/src/editor/components/MasterComponentEditor.tsx +846 -0
- package/src/editor/components/MediaLibraryDialog.tsx +447 -0
- package/src/editor/components/PageSettingsDialog.tsx +776 -0
- package/src/editor/components/VariablePicker.tsx +355 -0
- package/src/editor/components/VariablesDialog.tsx +564 -0
- package/src/editor/components/VariantEditor.tsx +687 -0
- package/src/editor/components/VariantMatrix.tsx +507 -0
- package/src/editor/components/component-panel/CategoryAccordion.tsx +139 -0
- package/src/editor/components/component-panel/ComponentGrid.tsx +51 -0
- package/src/editor/components/component-panel/ComponentItem.tsx +368 -0
- package/src/editor/components/component-panel/ComponentPanel.tsx +275 -0
- package/src/editor/components/component-panel/ComponentSearch.tsx +82 -0
- package/src/editor/components/component-panel/VariantList.tsx +260 -0
- package/src/editor/components/component-panel/index.ts +12 -0
- package/src/editor/components/index.ts +48 -0
- package/src/editor/components/multi-page/CanvasZoomControls.tsx +71 -0
- package/src/editor/components/multi-page/InfiniteCanvas.tsx +95 -0
- package/src/editor/components/multi-page/MultiPageCanvasView.tsx +1404 -0
- package/src/editor/components/multi-page/PageFrameOverlay.tsx +76 -0
- package/src/editor/components/multi-page/PageLabel.tsx +34 -0
- package/src/editor/components/multi-page/PageLivePreview.tsx +242 -0
- package/src/editor/components/multi-page/PageThumbnail.tsx +59 -0
- package/src/editor/components/multi-page/index.ts +7 -0
- package/src/editor/components/ppt/PptChrome.tsx +2508 -0
- package/src/editor/components/ppt/PptComments.tsx +589 -0
- package/src/editor/components/ppt/PptDesignProposals.tsx +275 -0
- package/src/editor/components/ppt/PptFormatPane.tsx +320 -0
- package/src/editor/components/ppt/PptNotes.tsx +246 -0
- package/src/editor/components/property-panel/AlignmentPanel.tsx +110 -0
- package/src/editor/components/property-panel/AutoLayoutPanel.tsx +615 -0
- package/src/editor/components/property-panel/BorderSection.tsx +104 -0
- package/src/editor/components/property-panel/CompactNumberInput.tsx +237 -0
- package/src/editor/components/property-panel/CompactSizeInput.tsx +148 -0
- package/src/editor/components/property-panel/EffectSection.tsx +157 -0
- package/src/editor/components/property-panel/FillSection.tsx +69 -0
- package/src/editor/components/property-panel/GoogleFontPicker.tsx +192 -0
- package/src/editor/components/property-panel/ImageSection.tsx +206 -0
- package/src/editor/components/property-panel/ImgSrcSection.tsx +125 -0
- package/src/editor/components/property-panel/InstanceOverrideSection.tsx +413 -0
- package/src/editor/components/property-panel/LayoutSection.tsx +105 -0
- package/src/editor/components/property-panel/LinkSection.tsx +103 -0
- package/src/editor/components/property-panel/PropertyVariablePicker.tsx +311 -0
- package/src/editor/components/property-panel/ScalePanel.tsx +212 -0
- package/src/editor/components/property-panel/TypographySection.tsx +230 -0
- package/src/editor/components/property-panel/UnitAwareNumberInput.tsx +238 -0
- package/src/editor/components/property-panel/VariableAwareColorInput.tsx +477 -0
- package/src/editor/components/property-panel/VariableAwareInput.tsx +606 -0
- package/src/editor/components/property-panel/VariableAwareSizeInput.tsx +588 -0
- package/src/editor/components/property-panel/VariableAwareUnitInput.tsx +546 -0
- package/src/editor/components/property-panel/index.ts +24 -0
- package/src/editor/components/property-panel/unit-utils.ts +261 -0
- package/src/editor/components/shell/EditorTopBar.tsx +392 -0
- package/src/editor/components/shell/LeftPanel.tsx +47 -0
- package/src/editor/components/shell/PagesPanel.tsx +118 -0
- package/src/editor/components/variables-panel/ColorValueCell.tsx +165 -0
- package/src/editor/components/variables-panel/TextValueCell.tsx +116 -0
- package/src/editor/components/variables-panel/VariablesPanel.tsx +518 -0
- package/src/editor/components/variables-panel/index.ts +7 -0
- package/src/editor/constants.ts +468 -0
- package/src/editor/contexts/EditorArtboardContext.tsx +229 -0
- package/src/editor/contexts/EditorComponentsContext.tsx +1320 -0
- package/src/editor/contexts/EditorDocumentContext.tsx +113 -0
- package/src/editor/contexts/EditorHistoryContext.tsx +516 -0
- package/src/editor/contexts/EditorRefsContext.tsx +204 -0
- package/src/editor/contexts/EditorSelectionContext.tsx +54 -0
- package/src/editor/contexts/EditorToolContext.tsx +58 -0
- package/src/editor/contexts/EditorUIStateContext.tsx +122 -0
- package/src/editor/contexts/EditorVariablesContext.tsx +397 -0
- package/src/editor/contexts/EditorViewContext.tsx +101 -0
- package/src/editor/contexts/MultiPageCanvasContext.tsx +498 -0
- package/src/editor/contexts/index.ts +17 -0
- package/src/editor/editor-skin.css +122 -0
- package/src/editor/hooks/index.ts +38 -0
- package/src/editor/hooks/useAiReplace.ts +397 -0
- package/src/editor/hooks/useAltMeasure.ts +67 -0
- package/src/editor/hooks/useBrowserZoomPrevention.ts +121 -0
- package/src/editor/hooks/useCanvasControls.ts +1222 -0
- package/src/editor/hooks/useComponentEditMode.ts +658 -0
- package/src/editor/hooks/useComponentInstances.ts +515 -0
- package/src/editor/hooks/useContextMenuHandler.ts +157 -0
- package/src/editor/hooks/useCoordinateTransform.ts +207 -0
- package/src/editor/hooks/useDragResize.ts +1317 -0
- package/src/editor/hooks/useDrawingMode.ts +472 -0
- package/src/editor/hooks/useEditorColors.ts +144 -0
- package/src/editor/hooks/useEditorMessages.ts +108 -0
- package/src/editor/hooks/useElementActions.ts +1754 -0
- package/src/editor/hooks/useElementSelection.ts +1573 -0
- package/src/editor/hooks/useFocusManagement.ts +249 -0
- package/src/editor/hooks/useGoogleFonts.ts +305 -0
- package/src/editor/hooks/useIframeInitializer.ts +584 -0
- package/src/editor/hooks/useIframeSetup.ts +360 -0
- package/src/editor/hooks/useImageUpload.ts +270 -0
- package/src/editor/hooks/useInfiniteCanvas.ts +301 -0
- package/src/editor/hooks/useKeyboardShortcuts.ts +205 -0
- package/src/editor/hooks/useMarqueeSelection.ts +388 -0
- package/src/editor/hooks/useMediaLibrary.ts +129 -0
- package/src/editor/hooks/usePageSettingsManager.ts +739 -0
- package/src/editor/hooks/useResizablePanel.ts +163 -0
- package/src/editor/hooks/useRichPaste.ts +255 -0
- package/src/editor/hooks/useTouchGestures.ts +197 -0
- package/src/editor/index.ts +27 -0
- package/src/editor/types/page-settings.ts +513 -0
- package/src/editor/types.ts +382 -0
- package/src/editor/utils/align-elements.ts +169 -0
- package/src/editor/utils/api-json.ts +21 -0
- package/src/editor/utils/aspect-lock.ts +50 -0
- package/src/editor/utils/component-renderer.ts +702 -0
- package/src/editor/utils/component-sync.ts +845 -0
- package/src/editor/utils/crop-mode.ts +265 -0
- package/src/editor/utils/dom-utils.ts +2238 -0
- package/src/editor/utils/element-effects.ts +218 -0
- package/src/editor/utils/eyedropper.ts +35 -0
- package/src/editor/utils/figma-export.ts +560 -0
- package/src/editor/utils/figma-kiwi-decoder.ts +722 -0
- package/src/editor/utils/figma-kiwi-encoder.ts +583 -0
- package/src/editor/utils/figma-paste.ts +2262 -0
- package/src/editor/utils/flex-reorder.ts +231 -0
- package/src/editor/utils/flex-utils.ts +1230 -0
- package/src/editor/utils/geometry.ts +232 -0
- package/src/editor/utils/grid-layout.ts +210 -0
- package/src/editor/utils/html-utils.ts +470 -0
- package/src/editor/utils/index.ts +11 -0
- package/src/editor/utils/ink-style.ts +57 -0
- package/src/editor/utils/inline-format.ts +236 -0
- package/src/editor/utils/measure-distance.ts +120 -0
- package/src/editor/utils/override-apply.ts +526 -0
- package/src/editor/utils/override-detection.ts +613 -0
- package/src/editor/utils/paste-processors.ts +609 -0
- package/src/editor/utils/paste-sanitizer.ts +244 -0
- package/src/editor/utils/restore-flow.ts +188 -0
- package/src/editor/utils/shape-library.ts +171 -0
- package/src/editor/utils/slide-root.ts +29 -0
- package/src/editor/utils/smart-guides.ts +218 -0
- package/src/editor/utils/style-utils.ts +685 -0
- package/src/editor/utils/table-edit.ts +151 -0
- package/src/editor/utils/tailwind-mappings.ts +778 -0
- package/src/editor/utils/tailwind-utils.ts +804 -0
- package/src/editor/utils/text-highlight.ts +216 -0
- package/src/editor/utils/theme-to-variables.ts +341 -0
- package/src/editor/utils/variant-resolver.ts +456 -0
- package/src/editor/utils/viewport-utils.ts +295 -0
- package/src/hooks/useEditorHistory.ts +195 -0
- package/src/hooks/useEditorShortcuts.ts +260 -0
- package/src/index.ts +40 -0
- package/src/io.ts +134 -0
- package/src/lib/agent/slide-agent/types.ts +547 -0
- package/src/lib/agent/website-agent/types.ts +805 -0
- package/src/lib/api/auth-fetch.ts +58 -0
- package/src/lib/deck.ts +69 -0
- package/src/lib/export.ts +47 -0
- package/src/lib/firebase/config.ts +29 -0
- package/src/lib/firebase/css-variables.ts +378 -0
- package/src/lib/firebase/editor-components.ts +677 -0
- package/src/lib/firebase/storage.ts +469 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/editor.css +52 -0
- package/src/styles/skin.css +122 -0
- package/src/types/css-variables.ts +645 -0
- package/src/types/editor-components.ts +944 -0
- package/src/types/editor.ts +420 -0
- package/src/types/page-master.ts +197 -0
- package/src/types/page.ts +419 -0
- package/src/types/slide.ts +402 -0
- package/src/types/website-theme.ts +788 -0
- package/src/types/website.ts +374 -0
- package/src/vendor/firebase-firestore.ts +13 -0
- package/src/vendor/firebase-functions.ts +17 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Types - Figma-like visual editor type definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Tool types available in the editor
|
|
6
|
+
export type EditorTool =
|
|
7
|
+
| 'select' // V - Selection tool
|
|
8
|
+
| 'move' // H - Hand/pan tool
|
|
9
|
+
| 'frame' // F - Frame tool
|
|
10
|
+
| 'rectangle' // R - Rectangle shape
|
|
11
|
+
| 'ellipse' // O - Ellipse/circle shape
|
|
12
|
+
| 'line' // L - Line
|
|
13
|
+
| 'arrow' // Shift+L - Arrow line
|
|
14
|
+
| 'pen' // P - Pen tool (bezier curves)
|
|
15
|
+
| 'pencil' // Shift+P - Freehand drawing
|
|
16
|
+
| 'text' // T - Text tool
|
|
17
|
+
| 'scale' // K - Scale tool
|
|
18
|
+
| 'eraser' // E - Eraser (ペン/鉛筆ストロークを消す)
|
|
19
|
+
| 'shape'; // 図形ギャラリーで選んだ図形(ドラッグでサイズ指定)
|
|
20
|
+
|
|
21
|
+
// Shape types that can be drawn
|
|
22
|
+
export type ShapeType = 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'text' | 'pen' | 'pencil' | 'frame';
|
|
23
|
+
|
|
24
|
+
// History state for undo/redo
|
|
25
|
+
export interface HistoryState {
|
|
26
|
+
html: string;
|
|
27
|
+
selectedElementId: string | null;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Editor history structure
|
|
32
|
+
export interface EditorHistory {
|
|
33
|
+
past: HistoryState[];
|
|
34
|
+
present: HistoryState;
|
|
35
|
+
future: HistoryState[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Point for drawing operations
|
|
39
|
+
export interface PathPoint {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
pressure?: number; // For pressure-sensitive drawing
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Serialized element for clipboard operations
|
|
46
|
+
export interface SerializedElement {
|
|
47
|
+
tagName: string;
|
|
48
|
+
id: string;
|
|
49
|
+
className: string;
|
|
50
|
+
style: string;
|
|
51
|
+
innerHTML: string;
|
|
52
|
+
attributes: Record<string, string>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Clipboard data structure
|
|
56
|
+
export interface ClipboardData {
|
|
57
|
+
elements: SerializedElement[];
|
|
58
|
+
offset: { x: number; y: number };
|
|
59
|
+
/**
|
|
60
|
+
* OSクリップボードへの書き込みが成功したか。
|
|
61
|
+
* 成功していれば paste イベント側がOSクリップボード(スライド跨ぎ可)を正とし、
|
|
62
|
+
* 失敗環境でのみ内部クリップボードへフォールバックする。
|
|
63
|
+
* これが無いと「昔の内部コピー」と「新しいOSコピー」の区別が付かない
|
|
64
|
+
*/
|
|
65
|
+
osWritten?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Bounding box for grouping
|
|
69
|
+
export interface BoundingBox {
|
|
70
|
+
left: number;
|
|
71
|
+
top: number;
|
|
72
|
+
width: number;
|
|
73
|
+
height: number;
|
|
74
|
+
right: number;
|
|
75
|
+
bottom: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Drawing state during shape creation
|
|
79
|
+
export interface DrawingState {
|
|
80
|
+
isDrawing: boolean;
|
|
81
|
+
startX: number;
|
|
82
|
+
startY: number;
|
|
83
|
+
currentX: number;
|
|
84
|
+
currentY: number;
|
|
85
|
+
previewElement: HTMLElement | null;
|
|
86
|
+
points: PathPoint[]; // For pen/pencil tools
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Shortcut action types
|
|
90
|
+
export type ShortcutAction =
|
|
91
|
+
// Tool switching
|
|
92
|
+
| 'select'
|
|
93
|
+
| 'move'
|
|
94
|
+
| 'rectangle'
|
|
95
|
+
| 'ellipse'
|
|
96
|
+
| 'line'
|
|
97
|
+
| 'arrow'
|
|
98
|
+
| 'eraser'
|
|
99
|
+
| 'pen'
|
|
100
|
+
| 'pencil'
|
|
101
|
+
| 'text'
|
|
102
|
+
| 'frame'
|
|
103
|
+
| 'scale'
|
|
104
|
+
// Edit operations
|
|
105
|
+
| 'undo'
|
|
106
|
+
| 'redo'
|
|
107
|
+
| 'copy'
|
|
108
|
+
| 'cut'
|
|
109
|
+
| 'paste'
|
|
110
|
+
| 'duplicate'
|
|
111
|
+
| 'delete'
|
|
112
|
+
// Style operations
|
|
113
|
+
| 'copyStyle'
|
|
114
|
+
| 'pasteStyle'
|
|
115
|
+
// Grouping
|
|
116
|
+
| 'group'
|
|
117
|
+
| 'ungroup'
|
|
118
|
+
// Selection
|
|
119
|
+
| 'selectAll'
|
|
120
|
+
| 'deselect'
|
|
121
|
+
// 兄弟要素の巡回選択(Tab / Shift+Tab)
|
|
122
|
+
| 'selectNextSibling'
|
|
123
|
+
| 'selectPrevSibling'
|
|
124
|
+
// Clipboard (external)
|
|
125
|
+
| 'copyToFigma'
|
|
126
|
+
// Zoom(実処理はエディタ側のズームAPIに委譲する)
|
|
127
|
+
| 'zoomFit'
|
|
128
|
+
| 'zoomActual'
|
|
129
|
+
| 'zoomSelection'
|
|
130
|
+
// Movement
|
|
131
|
+
| 'moveUp'
|
|
132
|
+
| 'moveDown'
|
|
133
|
+
| 'moveLeft'
|
|
134
|
+
| 'moveRight'
|
|
135
|
+
| 'moveUpLarge'
|
|
136
|
+
| 'moveDownLarge'
|
|
137
|
+
| 'moveLeftLarge'
|
|
138
|
+
| 'moveRightLarge'
|
|
139
|
+
// Resize (Figmaと同じ: Cmd+矢印=1px / Cmd+Shift+矢印=10px。→↓で広がり←↑で縮む)
|
|
140
|
+
| 'resizeGrowX'
|
|
141
|
+
| 'resizeShrinkX'
|
|
142
|
+
| 'resizeGrowY'
|
|
143
|
+
| 'resizeShrinkY'
|
|
144
|
+
| 'resizeGrowXLarge'
|
|
145
|
+
| 'resizeShrinkXLarge'
|
|
146
|
+
| 'resizeGrowYLarge'
|
|
147
|
+
| 'resizeShrinkYLarge'
|
|
148
|
+
// Layer ordering
|
|
149
|
+
| 'bringForward'
|
|
150
|
+
| 'sendBackward'
|
|
151
|
+
| 'bringToFront'
|
|
152
|
+
| 'sendToBack';
|
|
153
|
+
|
|
154
|
+
// Shortcut callbacks interface
|
|
155
|
+
export type ShortcutCallbacks = Partial<Record<ShortcutAction, () => void>>;
|
|
156
|
+
|
|
157
|
+
// Editor toolbar props
|
|
158
|
+
export interface EditorToolbarProps {
|
|
159
|
+
activeTool: EditorTool;
|
|
160
|
+
onToolChange: (tool: EditorTool) => void;
|
|
161
|
+
onUndo: () => void;
|
|
162
|
+
onRedo: () => void;
|
|
163
|
+
canUndo: boolean;
|
|
164
|
+
canRedo: boolean;
|
|
165
|
+
selectedCount: number;
|
|
166
|
+
onGroup?: () => void;
|
|
167
|
+
onUngroup?: () => void;
|
|
168
|
+
onDelete?: () => void;
|
|
169
|
+
onDuplicate?: () => void;
|
|
170
|
+
onBringForward?: () => void;
|
|
171
|
+
onSendBackward?: () => void;
|
|
172
|
+
onBringToFront?: () => void;
|
|
173
|
+
onSendToBack?: () => void;
|
|
174
|
+
onImageUpload?: () => void;
|
|
175
|
+
onAiRegenerate?: () => void;
|
|
176
|
+
/** CSS変数管理ダイアログを開くコールバック */
|
|
177
|
+
onOpenVariables?: () => void;
|
|
178
|
+
/** CSS変数が定義されているかどうか */
|
|
179
|
+
hasVariables?: boolean;
|
|
180
|
+
/** コンポーネントパネルを開くコールバック */
|
|
181
|
+
onOpenComponents?: () => void;
|
|
182
|
+
/** コンポーネントが定義されているかどうか */
|
|
183
|
+
hasComponents?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Tool configuration
|
|
187
|
+
export interface ToolConfig {
|
|
188
|
+
id: EditorTool;
|
|
189
|
+
label: string;
|
|
190
|
+
shortcut: string;
|
|
191
|
+
icon: string; // Lucide icon name
|
|
192
|
+
group: 'selection' | 'shapes' | 'drawing' | 'text' | 'frame';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Default tool configurations
|
|
196
|
+
export const TOOL_CONFIGS: ToolConfig[] = [
|
|
197
|
+
{ id: 'select', label: '選択・移動', shortcut: 'V', icon: 'MousePointer2', group: 'selection' },
|
|
198
|
+
{ id: 'scale', label: '拡大縮小', shortcut: 'K', icon: 'Scaling', group: 'selection' },
|
|
199
|
+
{ id: 'move', label: 'ハンド(パン)', shortcut: 'H', icon: 'Hand', group: 'selection' },
|
|
200
|
+
{ id: 'frame', label: 'フレーム', shortcut: 'F', icon: 'Frame', group: 'frame' },
|
|
201
|
+
{ id: 'rectangle', label: '長方形', shortcut: 'R', icon: 'Square', group: 'shapes' },
|
|
202
|
+
{ id: 'ellipse', label: '楕円', shortcut: 'O', icon: 'Circle', group: 'shapes' },
|
|
203
|
+
{ id: 'line', label: '直線', shortcut: 'L', icon: 'Minus', group: 'shapes' },
|
|
204
|
+
{ id: 'arrow', label: '矢印', shortcut: '⇧L', icon: 'ArrowRight', group: 'shapes' },
|
|
205
|
+
{ id: 'pen', label: 'ペン', shortcut: 'P', icon: 'Pen', group: 'drawing' },
|
|
206
|
+
{ id: 'pencil', label: 'フリーハンド', shortcut: '⇧P', icon: 'Pencil', group: 'drawing' },
|
|
207
|
+
{ id: 'text', label: 'テキスト', shortcut: 'T', icon: 'Type', group: 'text' },
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* キーボードショートカットの唯一のキーマップ。
|
|
212
|
+
*
|
|
213
|
+
* [移植時の修正] 以前はここ以外に
|
|
214
|
+
* - FrontendVisualEditor の window capture ハンドラ
|
|
215
|
+
* - useKeyboardShortcuts(iframeDoc) の独自 if 羅列
|
|
216
|
+
* という2系統の判定が併存していて、同じキーが二重発火したり
|
|
217
|
+
* (Cmd+D で複製が2個できる)、フォーカス位置で効くキーが入れ替わったりしていた。
|
|
218
|
+
* ツールキー・Cmd+A・Cmd+G・ズームまで全部この表に載せ、
|
|
219
|
+
* ディスパッチャ(useEditorShortcuts)1本だけがこの表を読む構成にしている。
|
|
220
|
+
*/
|
|
221
|
+
export const KEYBOARD_SHORTCUTS: Record<string, ShortcutAction> = {
|
|
222
|
+
// Tool switching (single keys)
|
|
223
|
+
'v': 'select',
|
|
224
|
+
'k': 'scale', // 追加
|
|
225
|
+
'h': 'move',
|
|
226
|
+
'r': 'rectangle',
|
|
227
|
+
'o': 'ellipse',
|
|
228
|
+
'l': 'line',
|
|
229
|
+
'shift+l': 'arrow',
|
|
230
|
+
'p': 'pen',
|
|
231
|
+
'e': 'eraser',
|
|
232
|
+
'shift+p': 'pencil',
|
|
233
|
+
't': 'text',
|
|
234
|
+
'f': 'frame',
|
|
235
|
+
|
|
236
|
+
// Edit operations (Cmd/Ctrl + key)
|
|
237
|
+
'meta+z': 'undo',
|
|
238
|
+
'ctrl+z': 'undo',
|
|
239
|
+
'meta+shift+z': 'redo',
|
|
240
|
+
'ctrl+shift+z': 'redo',
|
|
241
|
+
'meta+y': 'redo',
|
|
242
|
+
'ctrl+y': 'redo',
|
|
243
|
+
'meta+c': 'copy',
|
|
244
|
+
'ctrl+c': 'copy',
|
|
245
|
+
'meta+x': 'cut',
|
|
246
|
+
'ctrl+x': 'cut',
|
|
247
|
+
'meta+v': 'paste',
|
|
248
|
+
'ctrl+v': 'paste',
|
|
249
|
+
'meta+d': 'duplicate',
|
|
250
|
+
'ctrl+d': 'duplicate',
|
|
251
|
+
'delete': 'delete',
|
|
252
|
+
'backspace': 'delete',
|
|
253
|
+
|
|
254
|
+
// Style operations
|
|
255
|
+
'meta+alt+c': 'copyStyle',
|
|
256
|
+
'ctrl+alt+c': 'copyStyle',
|
|
257
|
+
'meta+alt+v': 'pasteStyle',
|
|
258
|
+
'ctrl+alt+v': 'pasteStyle',
|
|
259
|
+
|
|
260
|
+
// Grouping
|
|
261
|
+
'meta+g': 'group',
|
|
262
|
+
'ctrl+g': 'group',
|
|
263
|
+
'meta+shift+g': 'ungroup',
|
|
264
|
+
'ctrl+shift+g': 'ungroup',
|
|
265
|
+
|
|
266
|
+
// Selection
|
|
267
|
+
'meta+a': 'selectAll',
|
|
268
|
+
'ctrl+a': 'selectAll',
|
|
269
|
+
'escape': 'deselect',
|
|
270
|
+
// Tab で兄弟要素を順に選ぶ(Figma準拠)。ブラウザ既定のフォーカス移動より
|
|
271
|
+
// キャンバス上の選択移動のほうが期待される操作なので、こちらへ割り当てる
|
|
272
|
+
'tab': 'selectNextSibling',
|
|
273
|
+
'shift+tab': 'selectPrevSibling',
|
|
274
|
+
|
|
275
|
+
// Movement (arrow keys)
|
|
276
|
+
// リサイズ(Cmd/Ctrl+矢印)。→↓で広がり、←↑で縮む
|
|
277
|
+
'meta+arrowright': 'resizeGrowX',
|
|
278
|
+
'ctrl+arrowright': 'resizeGrowX',
|
|
279
|
+
'meta+arrowleft': 'resizeShrinkX',
|
|
280
|
+
'ctrl+arrowleft': 'resizeShrinkX',
|
|
281
|
+
'meta+arrowdown': 'resizeGrowY',
|
|
282
|
+
'ctrl+arrowdown': 'resizeGrowY',
|
|
283
|
+
'meta+arrowup': 'resizeShrinkY',
|
|
284
|
+
'ctrl+arrowup': 'resizeShrinkY',
|
|
285
|
+
'meta+shift+arrowright': 'resizeGrowXLarge',
|
|
286
|
+
'ctrl+shift+arrowright': 'resizeGrowXLarge',
|
|
287
|
+
'meta+shift+arrowleft': 'resizeShrinkXLarge',
|
|
288
|
+
'ctrl+shift+arrowleft': 'resizeShrinkXLarge',
|
|
289
|
+
'meta+shift+arrowdown': 'resizeGrowYLarge',
|
|
290
|
+
'ctrl+shift+arrowdown': 'resizeGrowYLarge',
|
|
291
|
+
'meta+shift+arrowup': 'resizeShrinkYLarge',
|
|
292
|
+
'ctrl+shift+arrowup': 'resizeShrinkYLarge',
|
|
293
|
+
'arrowup': 'moveUp',
|
|
294
|
+
'arrowdown': 'moveDown',
|
|
295
|
+
'arrowleft': 'moveLeft',
|
|
296
|
+
'arrowright': 'moveRight',
|
|
297
|
+
'shift+arrowup': 'moveUpLarge',
|
|
298
|
+
'shift+arrowdown': 'moveDownLarge',
|
|
299
|
+
'shift+arrowleft': 'moveLeftLarge',
|
|
300
|
+
'shift+arrowright': 'moveRightLarge',
|
|
301
|
+
|
|
302
|
+
// Figma形式でコピー
|
|
303
|
+
'meta+shift+c': 'copyToFigma',
|
|
304
|
+
'ctrl+shift+c': 'copyToFigma',
|
|
305
|
+
|
|
306
|
+
// Zoom(Figma準拠: 0=全体表示 / 1=100% / 2=選択範囲にズーム)
|
|
307
|
+
'meta+0': 'zoomFit',
|
|
308
|
+
'ctrl+0': 'zoomFit',
|
|
309
|
+
'meta+1': 'zoomActual',
|
|
310
|
+
'ctrl+1': 'zoomActual',
|
|
311
|
+
'meta+2': 'zoomSelection',
|
|
312
|
+
'ctrl+2': 'zoomSelection',
|
|
313
|
+
|
|
314
|
+
// Layer ordering
|
|
315
|
+
'meta+]': 'bringForward',
|
|
316
|
+
'ctrl+]': 'bringForward',
|
|
317
|
+
'meta+[': 'sendBackward',
|
|
318
|
+
'ctrl+[': 'sendBackward',
|
|
319
|
+
'meta+shift+]': 'bringToFront',
|
|
320
|
+
'ctrl+shift+]': 'bringToFront',
|
|
321
|
+
'meta+shift+[': 'sendToBack',
|
|
322
|
+
'ctrl+shift+[': 'sendToBack',
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// Movement amounts in pixels
|
|
326
|
+
export const MOVEMENT_AMOUNTS = {
|
|
327
|
+
normal: 1,
|
|
328
|
+
large: 10,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// Maximum history stack size
|
|
332
|
+
export const MAX_HISTORY_SIZE = 50;
|
|
333
|
+
|
|
334
|
+
// Debounce delay for history saves (ms)
|
|
335
|
+
export const HISTORY_DEBOUNCE_MS = 300;
|
|
336
|
+
|
|
337
|
+
// Image fill modes (Figma-like)
|
|
338
|
+
export type ImageFillMode =
|
|
339
|
+
| 'fill' // 塗り - 要素全体を埋める(アスペクト比無視)
|
|
340
|
+
| 'fit' // 自動 - アスペクト比維持で収める(contain)
|
|
341
|
+
| 'crop' // トリミング - アスペクト比維持で埋める(cover)
|
|
342
|
+
| 'tile'; // タイル - 繰り返し
|
|
343
|
+
|
|
344
|
+
// Image fill settings
|
|
345
|
+
export interface ImageFillSettings {
|
|
346
|
+
url: string;
|
|
347
|
+
mode: ImageFillMode;
|
|
348
|
+
opacity: number; // 0-100
|
|
349
|
+
position: {
|
|
350
|
+
x: number; // -100 to 100 (percentage offset)
|
|
351
|
+
y: number; // -100 to 100 (percentage offset)
|
|
352
|
+
};
|
|
353
|
+
scale: number; // 1-500 (percentage)
|
|
354
|
+
rotation: number; // 0-360 degrees
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Element fill type
|
|
358
|
+
export type FillType = 'solid' | 'image' | 'gradient' | 'none';
|
|
359
|
+
|
|
360
|
+
// Element fill settings
|
|
361
|
+
export interface ElementFill {
|
|
362
|
+
type: FillType;
|
|
363
|
+
color?: string; // for solid
|
|
364
|
+
image?: ImageFillSettings; // for image
|
|
365
|
+
gradient?: {
|
|
366
|
+
type: 'linear' | 'radial';
|
|
367
|
+
angle: number;
|
|
368
|
+
stops: Array<{ color: string; position: number }>;
|
|
369
|
+
}; // for gradient
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Default image fill settings
|
|
373
|
+
export const DEFAULT_IMAGE_FILL: ImageFillSettings = {
|
|
374
|
+
url: '',
|
|
375
|
+
mode: 'crop',
|
|
376
|
+
opacity: 100,
|
|
377
|
+
position: { x: 0, y: 0 },
|
|
378
|
+
scale: 100,
|
|
379
|
+
rotation: 0,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// Default shape styles
|
|
383
|
+
export const DEFAULT_SHAPE_STYLES = {
|
|
384
|
+
rectangle: {
|
|
385
|
+
backgroundColor: '#3B82F6',
|
|
386
|
+
borderRadius: '4px',
|
|
387
|
+
},
|
|
388
|
+
ellipse: {
|
|
389
|
+
backgroundColor: '#3B82F6',
|
|
390
|
+
borderRadius: '50%',
|
|
391
|
+
},
|
|
392
|
+
line: {
|
|
393
|
+
stroke: '#1F2937',
|
|
394
|
+
strokeWidth: 2,
|
|
395
|
+
},
|
|
396
|
+
arrow: {
|
|
397
|
+
stroke: '#1F2937',
|
|
398
|
+
strokeWidth: 2,
|
|
399
|
+
},
|
|
400
|
+
text: {
|
|
401
|
+
fontSize: '16px',
|
|
402
|
+
color: '#1F2937',
|
|
403
|
+
fontFamily: 'inherit',
|
|
404
|
+
},
|
|
405
|
+
frame: {
|
|
406
|
+
backgroundColor: 'transparent',
|
|
407
|
+
border: '1px dashed #9CA3AF',
|
|
408
|
+
},
|
|
409
|
+
pen: {
|
|
410
|
+
stroke: '#1F2937',
|
|
411
|
+
strokeWidth: 2,
|
|
412
|
+
fill: 'none',
|
|
413
|
+
},
|
|
414
|
+
pencil: {
|
|
415
|
+
stroke: '#1F2937',
|
|
416
|
+
strokeWidth: 2,
|
|
417
|
+
fill: 'none',
|
|
418
|
+
},
|
|
419
|
+
scale: {},
|
|
420
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { Timestamp } from '../vendor/firebase-firestore';
|
|
2
|
+
import { PageCategory, SectionCategory, PageGenerationResult } from './website';
|
|
3
|
+
|
|
4
|
+
// =====================================================
|
|
5
|
+
// PageMaster(ページマスター/テンプレート)
|
|
6
|
+
// =====================================================
|
|
7
|
+
|
|
8
|
+
export interface PageMaster {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
category: SectionCategory; // セクション/コンポーネントの種類
|
|
13
|
+
userId: string;
|
|
14
|
+
isPublic?: boolean;
|
|
15
|
+
layout?: {
|
|
16
|
+
width: number;
|
|
17
|
+
minHeight: number;
|
|
18
|
+
sections: Array<{
|
|
19
|
+
type: 'header' | 'content' | 'footer' | 'sidebar' | 'hero' | 'cta';
|
|
20
|
+
position: { x: number; y: number; width: number; height: number };
|
|
21
|
+
styles?: Record<string, string>;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
template: {
|
|
25
|
+
htmlTemplate: string;
|
|
26
|
+
cssClasses: string[];
|
|
27
|
+
variables?: Record<string, string>; // テンプレート変数
|
|
28
|
+
};
|
|
29
|
+
metadata: {
|
|
30
|
+
usageCount: number;
|
|
31
|
+
tags: string[];
|
|
32
|
+
author?: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
rating?: number;
|
|
35
|
+
reviews?: unknown[];
|
|
36
|
+
};
|
|
37
|
+
// AI生成されたサンプルページ
|
|
38
|
+
generatedPage?: PageGenerationResult;
|
|
39
|
+
// 生成時のプロンプト情報(再生成用)
|
|
40
|
+
generationInfo?: {
|
|
41
|
+
prompt: string;
|
|
42
|
+
attachedFiles?: Array<{
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
size: number;
|
|
46
|
+
data: string;
|
|
47
|
+
}>;
|
|
48
|
+
modelName?: string;
|
|
49
|
+
};
|
|
50
|
+
createdAt: Timestamp;
|
|
51
|
+
updatedAt: Timestamp;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// =====================================================
|
|
55
|
+
// WebsiteMaster(Webサイトマスター/テンプレート)
|
|
56
|
+
// =====================================================
|
|
57
|
+
|
|
58
|
+
// Webサイトマスターのカテゴリ
|
|
59
|
+
export type WebsiteMasterCategory =
|
|
60
|
+
| 'landing' // ランディングページ
|
|
61
|
+
| 'corporate' // コーポレートサイト
|
|
62
|
+
| 'portfolio' // ポートフォリオ
|
|
63
|
+
| 'blog' // ブログ
|
|
64
|
+
| 'ecommerce' // ECサイト
|
|
65
|
+
| 'saas' // SaaSプロダクト
|
|
66
|
+
| 'agency' // エージェンシー
|
|
67
|
+
| 'other'; // その他
|
|
68
|
+
|
|
69
|
+
// Webサイトマスター内のページ定義
|
|
70
|
+
export interface WebsiteMasterPage {
|
|
71
|
+
id: string;
|
|
72
|
+
pageMasterId: string; // 参照するページマスターID
|
|
73
|
+
pageOrder: number; // ページ順序(1始まり)
|
|
74
|
+
title?: string; // カスタムタイトル(上書き用)
|
|
75
|
+
slug?: string; // カスタムスラッグ
|
|
76
|
+
notes?: string; // 生成時の指示メモ
|
|
77
|
+
overrides?: { // ページマスターからの上書き設定
|
|
78
|
+
category?: PageCategory;
|
|
79
|
+
variables?: Record<string, string>;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Webサイトマスター
|
|
84
|
+
export interface WebsiteMaster {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string; // 例: "SaaS LPテンプレート"
|
|
87
|
+
description: string;
|
|
88
|
+
category: WebsiteMasterCategory;
|
|
89
|
+
userId: string;
|
|
90
|
+
isPublic?: boolean;
|
|
91
|
+
|
|
92
|
+
// ページ構成(順序付きリスト)
|
|
93
|
+
pages: WebsiteMasterPage[];
|
|
94
|
+
|
|
95
|
+
settings: {
|
|
96
|
+
theme: 'light' | 'dark' | 'corporate' | 'modern';
|
|
97
|
+
primaryColor: string;
|
|
98
|
+
fontFamily: string;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
metadata: {
|
|
102
|
+
usageCount: number;
|
|
103
|
+
tags: string[];
|
|
104
|
+
author?: string;
|
|
105
|
+
version?: string;
|
|
106
|
+
estimatedBuildTime?: number; // 推定構築時間(分)
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// プレビュー用
|
|
110
|
+
preview?: {
|
|
111
|
+
thumbnailUrl?: string;
|
|
112
|
+
demoUrl?: string;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
createdAt: Timestamp;
|
|
116
|
+
updatedAt: Timestamp;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// =====================================================
|
|
120
|
+
// 作成・更新用データ型
|
|
121
|
+
// =====================================================
|
|
122
|
+
|
|
123
|
+
export interface CreatePageMasterData {
|
|
124
|
+
name: string;
|
|
125
|
+
description: string;
|
|
126
|
+
category: SectionCategory;
|
|
127
|
+
layout?: PageMaster['layout'];
|
|
128
|
+
template: PageMaster['template'];
|
|
129
|
+
metadata?: Partial<PageMaster['metadata']>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface UpdatePageMasterData {
|
|
133
|
+
name?: string;
|
|
134
|
+
description?: string;
|
|
135
|
+
category?: SectionCategory;
|
|
136
|
+
layout?: PageMaster['layout'];
|
|
137
|
+
template?: PageMaster['template'];
|
|
138
|
+
metadata?: Partial<PageMaster['metadata']>;
|
|
139
|
+
isPublic?: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface CreateWebsiteMasterData {
|
|
143
|
+
name: string;
|
|
144
|
+
description: string;
|
|
145
|
+
category: WebsiteMasterCategory;
|
|
146
|
+
pages: Omit<WebsiteMasterPage, 'id'>[];
|
|
147
|
+
settings?: Partial<WebsiteMaster['settings']>;
|
|
148
|
+
metadata?: Partial<WebsiteMaster['metadata']>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface UpdateWebsiteMasterData {
|
|
152
|
+
name?: string;
|
|
153
|
+
description?: string;
|
|
154
|
+
category?: WebsiteMasterCategory;
|
|
155
|
+
pages?: WebsiteMasterPage[];
|
|
156
|
+
settings?: Partial<WebsiteMaster['settings']>;
|
|
157
|
+
metadata?: Partial<WebsiteMaster['metadata']>;
|
|
158
|
+
isPublic?: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// =====================================================
|
|
162
|
+
// フィルター用型
|
|
163
|
+
// =====================================================
|
|
164
|
+
|
|
165
|
+
export interface PageMasterFilter {
|
|
166
|
+
category?: SectionCategory;
|
|
167
|
+
userId?: string;
|
|
168
|
+
tags?: string[];
|
|
169
|
+
search?: string;
|
|
170
|
+
isPublic?: boolean;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface WebsiteMasterFilter {
|
|
174
|
+
category?: WebsiteMasterCategory;
|
|
175
|
+
userId?: string;
|
|
176
|
+
tags?: string[];
|
|
177
|
+
search?: string;
|
|
178
|
+
isPublic?: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// =====================================================
|
|
182
|
+
// ページマスター生成用型
|
|
183
|
+
// =====================================================
|
|
184
|
+
|
|
185
|
+
export interface PageMasterGenerationRequest {
|
|
186
|
+
name: string;
|
|
187
|
+
description: string;
|
|
188
|
+
category: SectionCategory;
|
|
189
|
+
samplePrompt: string; // サンプルページ生成用プロンプト
|
|
190
|
+
pageCount?: number; // 自動生成するサンプルページ数(デフォルト1枚)
|
|
191
|
+
attachedFiles?: Array<{
|
|
192
|
+
name: string;
|
|
193
|
+
type: string;
|
|
194
|
+
size: number;
|
|
195
|
+
data: string;
|
|
196
|
+
}>;
|
|
197
|
+
}
|