UPD: Fancy animated TabSelect

This commit is contained in:
Robert Kossessa
2024-02-04 01:20:24 +01:00
parent 5f3c31a315
commit 0dda27b9bb
2 changed files with 48 additions and 13 deletions

View File

@@ -1,26 +1,61 @@
<template> <template>
<div class="flex font-heading px-4 py-2 gap-2"> <div class="relative">
<div class="absolute"/> <div
<TabSelectButton :style="backgroundStyle"
v-for="(option, key) in options" :key="key" class="absolute bg-zinc-300 outline outline-zinc-100 rounded-xl transition-all ease-out duration-75" />
:title="$t(option.titleKey)" <div class="flex font-heading px-4 py-2 gap-2 relative">
:icon="option.icon" :selected="model===key" <TabSelectButton
@select="model=key"> v-for="(option, key) in options" :key="key"
<template v-if="$slots[key]" #replace> :ref="(el) => buttons[key] = el"
<slot :name="key" /> :title="$t(option.titleKey)"
</template> :icon="option.icon" :selected="model===key"
</TabSelectButton> @select="model=key">
<template v-if="$slots[key]" #replace>
<slot :name="key" />
</template>
</TabSelectButton>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { CircleDot } from 'lucide-vue-next' import { CircleDot } from 'lucide-vue-next'
import TabSelectButton from '@/components/config/TabSelectButton.vue' import TabSelectButton from '@/components/config/TabSelectButton.vue'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
const model = defineModel({ const model = defineModel({
type: String, type: String,
default: 'a', default: 'a',
}) })
const buttons = ref({})
const backgroundStyle = ref({})
const updateBackgroundStyle = () => {
const selected = buttons.value[model.value]
if (selected) {
backgroundStyle.value = {
top: `${selected.$el.offsetTop}px`,
left: `${selected.$el.offsetLeft}px`,
width: `${selected.$el.offsetWidth}px`,
height: `${selected.$el.offsetHeight}px`,
}
}
}
watch([model, buttons], updateBackgroundStyle)
let observer = null
onMounted(() => {
observer = new ResizeObserver(updateBackgroundStyle)
observer.observe(buttons.value[model.value].$el)
})
onBeforeUnmount(() => {
observer.disconnect()
})
defineProps({ defineProps({
options: { options: {
type: Object, type: Object,

View File

@@ -1,7 +1,7 @@
<template> <template>
<button <button
class="flex-1 flex flex-col items-center rounded-xl p-1 gap-2" class="flex-1 flex flex-col items-center rounded-xl p-1 gap-2 transition-colors"
:class="{'text-black bg-zinc-300 hover:bg-zinc-200 outline outline-zinc-100': selected, :class="{'text-black hover:bg-zinc-200': selected,
'hover:bg-zinc-800 text-muted-foreground' : !selected}" 'hover:bg-zinc-800 text-muted-foreground' : !selected}"
@click="$emit('select'); $refs.title.scramble()"> @click="$emit('select'); $refs.title.scramble()">
<slot v-if="$slots['replace']" name="replace" /> <slot v-if="$slots['replace']" name="replace" />