diff --git a/packages/core/src/tools/schema.ts b/packages/core/src/tools/schema.ts index 6f46ad16e..8a09000ad 100644 --- a/packages/core/src/tools/schema.ts +++ b/packages/core/src/tools/schema.ts @@ -6,6 +6,9 @@ * and MCP (JSON Schema) are generated from these definitions. */ +import { parseColor } from '../color' +import { DEFAULT_SHADOW_COLOR } from '../constants' + import type { FigmaAPI, FigmaNodeProxy } from '../figma-api' export type ParamType = 'string' | 'number' | 'boolean' | 'color' | 'string[]' diff --git a/src/components/AppMenu.vue b/src/components/AppMenu.vue index 5e8db6aaf..c149bb0f8 100644 --- a/src/components/AppMenu.vue +++ b/src/components/AppMenu.vue @@ -16,7 +16,7 @@ import { import IconChevronRight from '~icons/lucide/chevron-right' -import { ref, nextTick } from 'vue' +import { ref } from 'vue' import { IS_TAURI } from '@/constants' import { openFileDialog } from '@/composables/use-menu' @@ -25,14 +25,13 @@ import { useEditorStore } from '@/stores/editor' const store = useEditorStore() const editingName = ref(false) +const nameInputRef = ref(null) -function startRename() { +async function startRename() { editingName.value = true - nextTick(() => { - const input = document.querySelector('[data-doc-name-edit]') - input?.focus() - input?.select() - }) + await nextTick() + nameInputRef.value?.focus() + nameInputRef.value?.select() } function commitRename(input: HTMLInputElement) { @@ -177,7 +176,7 @@ const topMenus = [ OpenPencil import { useElementSize, useWindowSize } from '@vueuse/core' +import { TabsContent, TabsList, TabsRoot, TabsTrigger } from 'reka-ui' import { motion } from 'motion-v' import type { PanInfo } from 'motion-v' import { computed, ref } from 'vue' @@ -20,6 +21,7 @@ import { import { useEditorStore } from '@/stores/editor' type Snap = 'closed' | 'half' | 'full' +type DrawerTab = 'layers' | 'design' | 'code' | 'ai' const store = useEditorStore() @@ -35,22 +37,32 @@ const snap = computed({ } }) +const activeDrawerTab = computed({ + get: () => { + if (store.state.activeRibbonTab === 'code') return 'code' + if (store.state.activeRibbonTab === 'ai') return 'ai' + return store.state.panelMode === 'design' ? 'design' : 'layers' + }, + set: (tab) => { + if (tab === 'code' || tab === 'ai') { + store.state.activeRibbonTab = tab + return + } + store.state.activeRibbonTab = 'panels' + store.state.panelMode = tab + } +}) + const isOpen = computed(() => snap.value !== 'closed') -const isPanelActive = computed(() => isOpen.value && store.state.activeRibbonTab === 'panels') - -function selectTab(tab: 'panels' | 'code' | 'ai', panelMode?: 'layers' | 'design') { - const isSameTab = - store.state.activeRibbonTab === tab && (!panelMode || store.state.panelMode === panelMode) - - if (isSameTab && isOpen.value) { +function toggleTab(tab: DrawerTab) { + if (activeDrawerTab.value === tab && isOpen.value) { snap.value = 'closed' targetHeight.value = snapHeight('closed') return } - store.state.activeRibbonTab = tab - if (panelMode) store.state.panelMode = panelMode + activeDrawerTab.value = tab if (!isOpen.value) { snap.value = 'half' targetHeight.value = snapHeight('half') @@ -74,10 +86,6 @@ function onPan(_e: PointerEvent, info: PanInfo) { const maxHeight = snapHeight('full') const raw = snapHeight(snap.value) - info.offset.y targetHeight.value = Math.max(headerH.value, Math.min(maxHeight, raw)) - - if (info.offset.y < 0 && !store.state.activeRibbonTab) { - store.state.activeRibbonTab = 'panels' - } } function onPanEnd(_e: PointerEvent, info: PanInfo) { @@ -111,109 +119,82 @@ const drawerTransition = { @pan="onPan" @panEnd="onPanEnd" > - - -
-
- -
-
- Layers -
- -
- -
- -
- -
- -
- -
- -
-
+ diff --git a/src/components/PagesPanel.vue b/src/components/PagesPanel.vue index be8f89ef3..7995e775b 100644 --- a/src/components/PagesPanel.vue +++ b/src/components/PagesPanel.vue @@ -1,5 +1,5 @@ @@ -43,7 +56,7 @@ function startRename(pg: { id: string; name: string }) {
{ }) const editingCollectionId = ref(null) +const collectionInputRefs = new Map() +const pendingCollectionFocusId = ref(null) + +function setCollectionInputRef(id: string, el: HTMLInputElement | null) { + if (el) collectionInputRefs.set(id, el) + else collectionInputRefs.delete(id) + + if (el && pendingCollectionFocusId.value === id) { + pendingCollectionFocusId.value = null + void nextTick(() => { + el.focus() + el.select() + }) + } +} function startRenameCollection(id: string) { editingCollectionId.value = id - nextTick(() => { - const input = document.querySelector('[data-collection-edit]') - input?.focus() - input?.select() - }) + pendingCollectionFocusId.value = id } function commitRenameCollection(id: string, input: HTMLInputElement) { @@ -412,7 +423,7 @@ const table = useVueTable({