56 lines
1.8 KiB
Vue
56 lines
1.8 KiB
Vue
<script setup lang="ts">
|
|
import type { DashboardWidgetId } from '~/composables/useDashboardHomeWidgets'
|
|
|
|
const props = defineProps<{
|
|
widgetOrder: DashboardWidgetId[]
|
|
widgets: Record<DashboardWidgetId, boolean>
|
|
layoutUnlocked: boolean
|
|
draggingWidget: DashboardWidgetId | null
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
dragStart: [wid: DashboardWidgetId, e: DragEvent]
|
|
dragEnd: []
|
|
drop: [wid: DashboardWidgetId, e: DragEvent]
|
|
}>()
|
|
|
|
function shellClass(wid: DashboardWidgetId) {
|
|
return [
|
|
props.layoutUnlocked ? 'rounded-2xl ring-1 ring-dashed ring-[var(--brand-soft)]/50' : '',
|
|
props.draggingWidget === wid ? 'opacity-[0.58]' : ''
|
|
]
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mx-auto max-w-6xl space-y-10">
|
|
<template v-for="wid in widgetOrder" :key="'dash-' + wid">
|
|
<section
|
|
v-show="widgets[wid]"
|
|
:class="shellClass(wid)"
|
|
@dragover.prevent
|
|
@drop.prevent="emit('drop', wid, $event)"
|
|
>
|
|
<div class="flex items-start gap-1 sm:gap-3">
|
|
<div v-if="layoutUnlocked" class="flex shrink-0 flex-col pt-1">
|
|
<button
|
|
type="button"
|
|
draggable="true"
|
|
class="select-none cursor-grab rounded-lg border border-[var(--card-border)]/90 bg-[var(--surface)] p-2 text-[var(--text-muted)] shadow-sm hover:bg-[var(--badge-muted-bg)] active:cursor-grabbing"
|
|
tabindex="-1"
|
|
aria-label="Drag to reorder section"
|
|
@dragstart.stop="emit('dragStart', wid, $event)"
|
|
@dragend="emit('dragEnd')"
|
|
>
|
|
<UIcon name="i-heroicons-bars-3" class="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
<div class="min-w-0 flex-1">
|
|
<slot :name="wid" />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
</div>
|
|
</template>
|