97 lines
3 KiB
Vue
97 lines
3 KiB
Vue
<script setup lang="ts">
|
|
import { twMerge } from 'tailwind-merge'
|
|
|
|
import { applySolidFillColor, FillPickerRoot, useI18n } from '@open-pencil/vue'
|
|
|
|
import GradientEditor from './GradientEditor.vue'
|
|
import ColorPickerPanel from '@/components/ColorPickerPanel/ColorPickerPanel.vue'
|
|
import ImageFillPicker from './ImageFillPicker.vue'
|
|
import Tip from './ui/Tip.vue'
|
|
import { usePopoverUI } from './ui/popover'
|
|
|
|
import type { Fill } from '@open-pencil/core/scene-graph'
|
|
import type { OkHCLControls } from '@open-pencil/vue'
|
|
|
|
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,
|
|
okhcl = null,
|
|
swatchBackground
|
|
} = defineProps<{
|
|
fill: Fill
|
|
okhcl?: OkHCLControls | null
|
|
swatchBackground?: string
|
|
}>()
|
|
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 #trigger="{ style }">
|
|
<button
|
|
data-test-id="fill-picker-swatch"
|
|
class="size-5 shrink-0 cursor-pointer rounded border border-border p-0"
|
|
:style="{ ...style, background: swatchBackground ?? style.background }"
|
|
/>
|
|
</template>
|
|
<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>
|
|
|
|
<ColorPickerPanel
|
|
v-if="category === 'SOLID'"
|
|
:color="currentFill.color"
|
|
:okhcl="okhcl"
|
|
@update="update(applySolidFillColor(currentFill, $event))"
|
|
/>
|
|
|
|
<GradientEditor v-if="category === 'GRADIENT'" :fill="currentFill" @update="update($event)" />
|
|
|
|
<ImageFillPicker v-if="category === 'IMAGE'" :fill="currentFill" @update="update($event)" />
|
|
</template>
|
|
</FillPickerRoot>
|
|
</template>
|