openpencil/src/components/FillPicker.vue
2026-03-25 18:47:23 +03:00

80 lines
2.4 KiB
Vue

<script setup lang="ts">
import { twMerge } from 'tailwind-merge'
import { FillPickerRoot, useI18n } from '@open-pencil/vue'
import GradientEditor from './GradientEditor.vue'
import HsvColorArea from './HsvColorArea.vue'
import ImageFillPicker from './ImageFillPicker.vue'
import Tip from './ui/Tip.vue'
import { usePopoverUI } from './ui/popover'
import type { Fill } from '@open-pencil/core'
const TAB_BASE =
'flex size-6 cursor-pointer items-center justify-center rounded border-none p-0 transition-colors'
function tabClass(active: boolean) {
return twMerge(
TAB_BASE,
active ? 'bg-hover text-surface' : 'text-muted hover:bg-hover hover:text-surface'
)
}
const { fill } = defineProps<{ fill: Fill }>()
const emit = defineEmits<{ update: [fill: Fill] }>()
const cls = usePopoverUI({ content: 'w-60 p-2' })
const { panels } = useI18n()
</script>
<template>
<FillPickerRoot
:fill="fill"
:content-class="cls.content"
swatch-class="size-5 shrink-0 cursor-pointer rounded border border-border p-0"
@update="emit('update', $event)"
>
<template #default="{ fill: currentFill, category, toSolid, toGradient, toImage, update }">
<div class="mb-2 flex items-center gap-0.5">
<Tip :label="panels.solid">
<button
:class="tabClass(category === 'SOLID')"
data-test-id="fill-picker-tab-solid"
@click="toSolid"
>
<icon-lucide-square class="size-3.5" />
</button>
</Tip>
<Tip :label="panels.linearGradient">
<button
:class="tabClass(category === 'GRADIENT')"
data-test-id="fill-picker-tab-gradient"
@click="toGradient"
>
<icon-lucide-blend class="size-3.5" />
</button>
</Tip>
<Tip :label="panels.image">
<button
:class="tabClass(category === 'IMAGE')"
data-test-id="fill-picker-tab-image"
@click="toImage"
>
<icon-lucide-image class="size-3.5" />
</button>
</Tip>
</div>
<HsvColorArea
v-if="category === 'SOLID'"
:color="currentFill.color"
@update="update({ ...currentFill, color: $event })"
/>
<GradientEditor v-if="category === 'GRADIENT'" :fill="currentFill" @update="update($event)" />
<ImageFillPicker v-if="category === 'IMAGE'" :fill="currentFill" @update="update($event)" />
</template>
</FillPickerRoot>
</template>