Dynamic Dashboard with Widget Library

This commit is contained in:
2026-06-10 01:22:02 -05:00
parent 599465bdac
commit 7a54d1a386
25 changed files with 887 additions and 113 deletions

View File

@@ -0,0 +1,69 @@
<template>
<div class="widget-shell">
<div class="widget-handle" :class="{ 'is-edit': editing }">
<v-icon :icon="icon" size="small" class="mr-2" />
<span class="widget-title">{{ title }}</span>
<v-spacer />
<div class="widget-actions">
<v-progress-circular v-if="loading" indeterminate size="14" width="2" class="mr-1" />
<v-btn icon="mdi-refresh" size="x-small" variant="text" title="Refresh" @click="$emit('refresh')" />
<v-btn v-if="editing" icon="mdi-close" size="x-small" variant="text" color="error" title="Remove" @click="$emit('remove')" />
</div>
</div>
<div class="widget-body">
<slot />
</div>
</div>
</template>
<script>
// Common chrome for every dashboard widget: a draggable title bar (.widget-handle) with refresh/remove
// actions (.widget-actions are excluded from the drag), and a scrollable body slot.
export default {
props: {
title: { type: String, required: true },
icon: { type: String, default: 'mdi-view-dashboard-outline' },
editing: { type: Boolean, default: false },
loading: { type: Boolean, default: false }
},
emits: ['refresh', 'remove']
};
</script>
<style scoped>
.widget-shell {
height: 100%;
display: flex;
flex-direction: column;
background: rgb(var(--v-theme-surface));
border: 1px solid rgba(128, 128, 128, 0.22);
border-radius: 10px;
overflow: hidden;
}
.widget-handle {
display: flex;
align-items: center;
gap: 2px;
padding: 6px 8px 6px 12px;
border-bottom: 1px solid rgba(128, 128, 128, 0.18);
background: rgba(128, 128, 128, 0.06);
min-height: 38px;
}
.widget-handle.is-edit {
cursor: move;
background: rgba(var(--v-theme-primary), 0.08);
}
.widget-title {
font-weight: 600;
font-size: 0.9rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.widget-body {
flex: 1;
min-height: 0;
overflow: auto;
padding: 12px;
}
</style>