openpencil/src/components/properties/frame-presets/FramePresetSelect.vue
Luca Candela 18899ff13c
feat(editor): add Figma-style frame presets (#418)
Add frame preset creation and resizing with constraint-aware layout, undo/redo, toolbar flyouts, localization, documentation, and regression coverage.
2026-07-26 00:05:57 +03:00

56 lines
1.7 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
import { useI18n, useSelectionState } from '@open-pencil/vue'
import { useEditorStore } from '@/app/editor/active-store'
import {
findFrameResizePreset,
FRAME_RESIZE_PRESET_CATEGORIES,
FRAME_RESIZE_PRESETS
} from '@/app/editor/frame-presets'
import AppGroupedSelect from '@/components/ui/AppGroupedSelect.vue'
import PanelSection from '@/components/ui/panel/PanelSection.vue'
const store = useEditorStore()
const { selectedNode } = useSelectionState()
const { panels } = useI18n()
const selectedPreset = computed(() => {
const node = selectedNode.value
return node ? findFrameResizePreset(node.width, node.height, node.name) : undefined
})
const selectedPresetId = computed({
get: () => selectedPreset.value?.id ?? 'custom',
set: (id: string) => {
const node = selectedNode.value
const preset = FRAME_RESIZE_PRESETS.find((candidate) => candidate.id === id)
if (node?.type === 'FRAME' && preset) store.resizeFrameToPreset(node.id, preset)
}
})
const groups = computed(() =>
FRAME_RESIZE_PRESET_CATEGORIES.map((category) => ({
label: panels.value[category.labelKey],
items: category.presets.map((preset) => ({ value: preset.id, label: preset.name }))
}))
)
const displayValue = computed(() => selectedPreset.value?.name ?? panels.value.framePresetCustom)
const selectUI = {
content: 'max-h-80',
viewport: 'max-h-80'
}
</script>
<template>
<PanelSection :label="panels.frame">
<AppGroupedSelect
v-model="selectedPresetId"
data-property="frame-preset"
:aria-label="panels.framePreset"
:groups="groups"
:display-value="displayValue"
:ui="selectUI"
/>
</PanelSection>
</template>