Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 73 additions & 8 deletions src/features/editor/components/header/TheHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { Monitor, MoreHorizontal, Smartphone } from 'lucide-vue-next'
import { Monitor, MoreHorizontal, Redo2, Smartphone, Undo2 } from 'lucide-vue-next'
import { Button } from '@/shared/ui/button'
import { ButtonGroup } from '@/shared/ui/button-group'
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/shared/ui/dialog'
Expand All @@ -11,6 +11,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/shared/ui/dropdown-menu'
import { Separator } from '@/shared/ui/separator'
import { Switch } from '@/shared/ui/switch'
import { ToggleGroup, ToggleGroupItem } from '@/shared/ui/toggle-group'
import { useHeaderActions } from './use-header-actions'
Expand All @@ -28,12 +29,16 @@ const {
previewModeValue,
visibleImportIssues,
canImport,
canUndo,
canRedo,
exportTemplateToFile,
exportTemplateHtmlToFile,
openImportDialog,
closeImportDialog,
clearCanvasWithConfirm,
onConfirmClearCanvas,
onUndo,
onRedo,
onImportFileChange,
confirmImport,
} = useHeaderActions()
Expand All @@ -42,17 +47,40 @@ const {
<template>
<div
data-slot="editor-header"
class="flex items-center justify-between bg-foreground px-4 text-secondary"
class="flex items-center justify-between bg-sidebar-accent-foreground px-4 text-secondary"
>
<div class="flex items-center">
<SvgLogoWhite width="100" />
</div>
<div class="tools flex items-center justify-center">
<!-- <div class="flex items-center justify-center gap-4 dark">
<ButtonGroup>
<Button
variant="outline"
size="icon-sm"
aria-label="Undo (Cmd+Z)"
title="Undo (Cmd+Z)"
:disabled="!canUndo"
@click="onUndo"
>
<Undo2 class="size-4" />
</Button>
<Button
variant="outline"
size="icon-sm"
aria-label="Redo (Cmd+Shift+Z)"
title="Redo (Cmd+Shift+Z)"
:disabled="!canRedo"
@click="onRedo"
>
<Redo2 class="size-4" />
</Button>
</ButtonGroup>

<ToggleGroup
v-model="previewModeValue"
type="single"
variant="outline"
size="xs"
size="sm"
>
<ToggleGroupItem value="desktop">
<Monitor class="size-4" />
Expand All @@ -61,15 +89,52 @@ const {
<Smartphone class="size-4" />
</ToggleGroupItem>
</ToggleGroup>
</div>
<div class="actions flex items-center">
</div> -->
<div class="actions flex items-center dark gap-5 h-5">
<ButtonGroup>
<Button
variant="outline"
size="icon-sm"
aria-label="Undo (Cmd+Z)"
title="Undo (Cmd+Z)"
:disabled="!canUndo"
@click="onUndo"
>
<Undo2 class="size-4" />
</Button>
<Button
variant="outline"
size="icon-sm"
aria-label="Redo (Cmd+Shift+Z)"
title="Redo (Cmd+Shift+Z)"
:disabled="!canRedo"
@click="onRedo"
>
<Redo2 class="size-4" />
</Button>
</ButtonGroup>

<ToggleGroup
v-model="previewModeValue"
type="single"
variant="outline"
size="sm"
>
<ToggleGroupItem value="desktop">
<Monitor class="size-4" />
</ToggleGroupItem>
<ToggleGroupItem value="mobile">
<Smartphone class="size-4" />
</ToggleGroupItem>
</ToggleGroup>
<Separator orientation="vertical" />
<ButtonGroup>
<Button
size="sm"
variant="outline"
@click="clearCanvasWithConfirm"
>
New
New Template
</Button>
<DropdownMenu>
<DropdownMenuTrigger as-child>
Expand Down Expand Up @@ -208,7 +273,7 @@ const {
variant="destructive"
@click="onConfirmClearCanvas()"
>
Yes
Confirm
</Button>
</DialogFooter>
</DialogContent>
Expand Down
55 changes: 54 additions & 1 deletion src/features/editor/components/header/use-header-actions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import type { TemplateImportMode } from '@/entities/template'
import { useEventListener } from '@vueuse/core'
import { computed, ref, watch } from 'vue'
import { useCanvas, useTemplateIO } from '@/features/editor/model'
import { useCanvas, useHistory, useTemplateIO } from '@/features/editor/model'

function isTextInputElement(target: EventTarget | null) {
if (!(target instanceof HTMLElement))
return false

if (target.isContentEditable)
return true

return ['input', 'textarea', 'select'].includes(target.tagName.toLowerCase())
}

export function useHeaderActions() {
const { exportTemplateHtml, exportTemplateJson, importTemplateFromJson } = useTemplateIO()
const { templateImportIssues, clearCanvas, previewMode } = useCanvas()
const { canUndo, canRedo, undo, redo, resetHistory } = useHistory()

const importDialogVisible = ref(false)
const clearDialogVisible = ref(false)
Expand Down Expand Up @@ -104,6 +116,7 @@ export function useHeaderActions() {

function onConfirmClearCanvas() {
clearCanvas()
resetHistory()
clearDialogVisible.value = false
}

Expand Down Expand Up @@ -143,6 +156,42 @@ export function useHeaderActions() {
importMessage.value = 'Import failed. Check validation errors below.'
}

function onUndo() {
undo()
}

function onRedo() {
redo()
}

function onKeyDown(event: KeyboardEvent) {
if (!(event.metaKey || event.ctrlKey) || event.altKey)
return

if (isTextInputElement(event.target))
return

if (event.key.toLowerCase() !== 'z')
return

if (event.shiftKey) {
if (!canRedo.value)
return

event.preventDefault()
redo()
return
}

if (!canUndo.value)
return

event.preventDefault()
undo()
}

useEventListener('keydown', onKeyDown, { passive: false })

watch(importDialogVisible, (open) => {
if (!open)
resetImportDialog()
Expand All @@ -162,12 +211,16 @@ export function useHeaderActions() {
previewModeValue,
visibleImportIssues,
canImport,
canUndo,
canRedo,
exportTemplateToFile,
exportTemplateHtmlToFile,
openImportDialog,
closeImportDialog,
clearCanvasWithConfirm,
onConfirmClearCanvas,
onUndo,
onRedo,
onImportFileChange,
confirmImport,
}
Expand Down
1 change: 1 addition & 0 deletions src/features/editor/model/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './types'
export { useCanvas } from './use-canvas'
export { useCanvasTools } from './use-canvas-tools'
export { useHistory } from './use-history'
export { usePersistence } from './use-persistence'
export { useSelection } from './use-selection'
export { useTemplateIO } from './use-template-io'
10 changes: 10 additions & 0 deletions src/features/editor/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@ export type {
export type BlockSelectionLevel = 'block' | 'row' | 'cell' | 'atom'
export type SidebarTab = 'library' | 'tree'
export type PreviewMode = 'desktop' | 'mobile'

export interface EditorSelectionSnapshot {
editableId?: string
selectedBlockId?: string
selectedRowId?: string
selectedCellId?: string
selectedAtomId?: string
selectionLevel?: BlockSelectionLevel
sidebarActiveTab: SidebarTab
}
Loading