Extract DesignPanel from PropertiesPanel

This commit is contained in:
Danila Poyarkov 2026-03-01 10:55:52 +03:00
parent bf5c905134
commit b10785fdee
3 changed files with 88 additions and 81 deletions

1
components.d.ts vendored
View file

@ -16,6 +16,7 @@ declare module 'vue' {
ChatPanel: typeof import('./src/components/ChatPanel.vue')['default']
ColorInput: typeof import('./src/components/ColorInput.vue')['default']
ColorPicker: typeof import('./src/components/ColorPicker.vue')['default']
DesignPanel: typeof import('./src/components/DesignPanel.vue')['default']
EditorCanvas: typeof import('./src/components/EditorCanvas.vue')['default']
EffectsSection: typeof import('./src/components/properties/EffectsSection.vue')['default']
ExportSection: typeof import('./src/components/properties/ExportSection.vue')['default']

View file

@ -0,0 +1,85 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useEditorStore } from '@/stores/editor'
import VariablesDialog from './VariablesDialog.vue'
import AppearanceSection from './properties/AppearanceSection.vue'
import EffectsSection from './properties/EffectsSection.vue'
import ExportSection from './properties/ExportSection.vue'
import FillSection from './properties/FillSection.vue'
import LayoutSection from './properties/LayoutSection.vue'
import PageSection from './properties/PageSection.vue'
import PositionSection from './properties/PositionSection.vue'
import StrokeSection from './properties/StrokeSection.vue'
import TypographySection from './properties/TypographySection.vue'
import VariablesSection from './properties/VariablesSection.vue'
const store = useEditorStore()
const variablesOpen = ref(false)
const node = computed(() => store.selectedNode.value)
const multiCount = computed(() => store.selectedNodes.value.length)
const isComponentType = computed(() => {
const t = node.value?.type
return t === 'COMPONENT' || t === 'COMPONENT_SET' || t === 'INSTANCE'
})
</script>
<template>
<!-- Multi-select summary -->
<div v-if="multiCount > 1" class="flex-1 overflow-y-auto pb-4">
<div class="flex items-center gap-1.5 border-b border-border px-3 py-2">
<span class="text-[11px] text-muted">Mixed</span>
<span class="text-xs font-semibold">{{ multiCount }} layers</span>
</div>
<AppearanceSection />
</div>
<!-- Single selection -->
<div v-else-if="node" class="flex-1 overflow-y-auto pb-4">
<!-- Node header -->
<div class="flex items-center gap-1.5 border-b border-border px-3 py-2">
<span class="text-[11px]" :class="isComponentType ? 'text-[#9747ff]' : 'text-muted'">{{
node.type
}}</span>
<span class="text-xs font-semibold">{{ node.name }}</span>
</div>
<!-- Component actions -->
<div
v-if="node.type === 'INSTANCE'"
class="flex flex-col gap-1 border-b border-border px-3 py-2"
>
<button
class="rounded bg-[#9747ff]/10 px-2 py-1 text-left text-[11px] text-[#9747ff] hover:bg-[#9747ff]/20"
@click="store.goToMainComponent()"
>
Go to Main Component
</button>
<button
class="rounded px-2 py-1 text-left text-[11px] text-muted hover:bg-hover"
@click="store.detachInstance()"
>
Detach Instance
</button>
</div>
<PositionSection />
<LayoutSection />
<AppearanceSection />
<TypographySection v-if="node.type === 'TEXT'" />
<FillSection />
<StrokeSection />
<EffectsSection />
<ExportSection />
</div>
<div v-else class="flex-1 overflow-y-auto pb-4">
<PageSection />
<VariablesSection @open-dialog="variablesOpen = true" />
</div>
<VariablesDialog v-model:open="variablesOpen" />
</template>

View file

@ -1,32 +1,12 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useAIChat } from '@/composables/use-chat'
import { useEditorStore } from '@/stores/editor'
import ChatPanel from './ChatPanel.vue'
import VariablesDialog from './VariablesDialog.vue'
import AppearanceSection from './properties/AppearanceSection.vue'
import EffectsSection from './properties/EffectsSection.vue'
import ExportSection from './properties/ExportSection.vue'
import FillSection from './properties/FillSection.vue'
import LayoutSection from './properties/LayoutSection.vue'
import PageSection from './properties/PageSection.vue'
import PositionSection from './properties/PositionSection.vue'
import StrokeSection from './properties/StrokeSection.vue'
import TypographySection from './properties/TypographySection.vue'
import VariablesSection from './properties/VariablesSection.vue'
import DesignPanel from './DesignPanel.vue'
const store = useEditorStore()
const { activeTab } = useAIChat()
const variablesOpen = ref(false)
const node = computed(() => store.selectedNode.value)
const multiCount = computed(() => store.selectedNodes.value.length)
const isComponentType = computed(() => {
const t = node.value?.type
return t === 'COMPONENT' || t === 'COMPONENT_SET' || t === 'INSTANCE'
})
</script>
<template>
@ -61,66 +41,7 @@ const isComponentType = computed(() => {
</span>
</div>
<!-- AI Chat tab -->
<ChatPanel v-if="activeTab === 'ai'" />
<!-- Design tab -->
<template v-else>
<!-- Multi-select summary -->
<div v-if="multiCount > 1" class="flex-1 overflow-y-auto pb-4">
<div class="flex items-center gap-1.5 border-b border-border px-3 py-2">
<span class="text-[11px] text-muted">Mixed</span>
<span class="text-xs font-semibold">{{ multiCount }} layers</span>
</div>
<AppearanceSection />
</div>
<!-- Single selection -->
<div v-else-if="node" class="flex-1 overflow-y-auto pb-4">
<!-- Node header -->
<div class="flex items-center gap-1.5 border-b border-border px-3 py-2">
<span class="text-[11px]" :class="isComponentType ? 'text-[#9747ff]' : 'text-muted'">{{
node.type
}}</span>
<span class="text-xs font-semibold">{{ node.name }}</span>
</div>
<!-- Component actions -->
<div
v-if="node.type === 'INSTANCE'"
class="flex flex-col gap-1 border-b border-border px-3 py-2"
>
<button
class="rounded bg-[#9747ff]/10 px-2 py-1 text-left text-[11px] text-[#9747ff] hover:bg-[#9747ff]/20"
@click="store.goToMainComponent()"
>
Go to Main Component
</button>
<button
class="rounded px-2 py-1 text-left text-[11px] text-muted hover:bg-hover"
@click="store.detachInstance()"
>
Detach Instance
</button>
</div>
<PositionSection />
<LayoutSection />
<AppearanceSection />
<TypographySection v-if="node.type === 'TEXT'" />
<FillSection />
<StrokeSection />
<EffectsSection />
<ExportSection />
</div>
<div v-else class="flex-1 overflow-y-auto pb-4">
<PageSection />
<VariablesSection @open-dialog="variablesOpen = true" />
</div>
<VariablesDialog v-model:open="variablesOpen" />
</template>
<DesignPanel v-else />
</aside>
</template>