GrDashboardItemSettings
Берут, когда у виджета есть что настраивать.
Когда брать
- у виджета есть что настраивать — период, источник, порог тревоги: окно даёт им место, не заставляя приложение собирать диалог заново на каждом дашборде;
- размер задаётся числом, а не жестом — с клавиатуры уголок растягивания требует счёта нажатий, а тут ширина и высота вводятся прямо;
- виджет нельзя растянуть мышью — узкий экран, сенсорный ввод,
resizableснят у соседей: поля остаются единственным способом изменить размер; - отказ должен быть виден — «на сетке нет места» окно показывает на месте, а не закрывается над несделанным.
Когда взять другое
| Нужно | Берите |
|---|---|
| Своё окно со своей шапкой и подвалом | GrDialog |
| Спросить «точно?» перед разрушительным действием | GrConfirmDialog |
| Продуктовые кнопки прямо в шапке виджета | GrDashboardItem |
| Форму из схемы бэкенда | GrSchemaForm |
Кнопку открывает виджет, окно рисует пакет
Шестерёнка живёт у GrDashboardItem под пропом showSettings и появляется там
же, где #editActions: в шапке, если она есть, и в панели поверх содержимого,
если шапки нет. Шапку она, в отличие от #actions, не включает — иначе вход в
режим редактирования сдвигал бы содержимое на её высоту.
Нажатие эмитит settings у виджета и itemSettings у сетки. Второе нужно
затем, чтобы приложение слушало одно место, а не подписывалось на каждый виджет
отдельно.
Размер коммитит сетка, а не окно
Ширина и высота уходят в раскладку через контекст сетки — с её компактизацией,
её preventCollision и её проверкой static. Своей арифметики у окна нет
намеренно: посчитай оно размер само, на дашборде появились бы две раскладки,
расходящиеся на первом же столкновении.
Отсюда и границы полей. Верхний предел ширины — не число колонок и не maxW, а
меньшее из них и cols - x: виджет растёт вправо и за правый край не выйдет.
Поле, предлагающее двенадцать колонок виджету, стоящему на восьмой, молча отдало
бы четыре.
Применение по кнопке, а не вживую
Изменение размера двигает соседей, и живой предпросмотр потребовал бы снимка
раскладки и отката по Esc. Поэтому одно нажатие «Применить» — один коммит, а
«Отмена» не оставляет следов: черновик набирается заново при каждом открытии.
Вне сетки окно работает без размера
Контекст GrDashboard — единственный источник и виджета, и числа колонок.
Стоит окно снаружи, itemId равен null или сетка в режиме просмотра — блока
размера просто нет, а слот приложения продолжает работать. Проп hideSize
убирает его и там, где сетка есть: бывает, что размер приложение считает само.
Границы
Заголовок виджета, его static и границы minW/maxW окно не редактирует.
Первый не входит в раскладку намеренно — уехав в хранилище, он протух бы при
первой смене языка; остальные объявляет разметка виджета, и редактор для них
завёл бы вторую правду о том же самом.
Установка
npm i @feugene/granularity-dashboardИмпорт
import { GrDashboardItemSettings } from '@feugene/granularity-dashboard/components/GrDashboardItemSettings'API
API этого компонента ещё не посчитан: генератор витрины пока обходит только ядро. Пока его нет, справочник — в документации пакета.
Примеры 1
Basic
<script setup lang="ts">
import { ref } from 'vue'
import type { GrDashboardResponsiveLayout } from '@feugene/granularity-dashboard'
/**
* Настройки виджета: размер в ячейках даёт пакет, период — приложение.
*
* Кнопку-шестерёнку рисует сам виджет (`show-settings`), окно приложение
* открывает по `item-settings` от сетки — так подписка одна на всю сетку, а не
* по одной на каждый виджет.
*/
const layout = ref<GrDashboardResponsiveLayout>({
lg: [
{ id: 'revenue', x: 0, y: 0, w: 6, h: 2 },
{ id: 'orders', x: 6, y: 0, w: 6, h: 2, minW: 3 },
],
})
const titles: Record<string, string> = { revenue: 'Выручка', orders: 'Заказы' }
const periods = [
{ value: 'week', label: 'Неделя' },
{ value: 'month', label: 'Месяц' },
{ value: 'quarter', label: 'Квартал' },
]
const period = ref<Record<string, string>>({ revenue: 'month', orders: 'week' })
const draft = ref('month')
const open = ref(false)
const editing = ref<string | null>(null)
function openSettings(id: string): void {
editing.value = id
draft.value = period.value[id] ?? 'month'
open.value = true
}
function apply(id: string): void {
period.value = { ...period.value, [id]: draft.value }
}
const breakpoints = { lg: 680, md: 520, sm: 400, xs: 0 }
const cols = { lg: 12, md: 8, sm: 4, xs: 2 }
</script>
<template>
<GrDashboard
v-model:layout="layout"
mode="edit"
:breakpoints="breakpoints"
:cols="cols"
:row-height="72"
aria-label="Настройки виджета"
@item-settings="openSettings"
>
<GrDashboardItem
v-for="item in layout.lg"
:key="item.id"
:item-id="item.id"
:title="titles[item.id]"
show-settings
overflow="hidden"
>
<p class="text-[var(--gr-muted-fg)]">
Период: {{ periods.find(entry => entry.value === period[item.id])?.label }}
</p>
</GrDashboardItem>
<GrDashboardItemSettings v-model="open" :item-id="editing" @apply="apply">
<GrFormField label="Период">
<GrSelect v-model="draft" :options="periods" />
</GrFormField>
</GrDashboardItemSettings>
</GrDashboard>
</template>