feat: journal dashboard widgets, agent polish, and edit-mode live previews
Journal dashboard widgets and quick-add; rich-text quick-add dialogs. Dashboard draft sync for live edit previews; assistant bubble + API tools. Journal UX: stress slider, mood grid, query cap fix.
This commit is contained in:
@@ -11,7 +11,12 @@ import { GripVertical, Settings2, Trash2, RotateCcw, Plus, LayoutGrid } from "lu
|
||||
import type { DashboardLayout, WidgetPlacement, PresetId } from "@/lib/dashboard";
|
||||
import { computePresetLayoutFromMetas, widgetContentKey } from "@/lib/dashboard";
|
||||
import type { SerializedWidgetMeta } from "@/modules/_core/registry";
|
||||
import { saveDashboardLayout, resetDashboardLayout } from "@/app/d/actions";
|
||||
import {
|
||||
saveDashboardLayout,
|
||||
resetDashboardLayout,
|
||||
syncEditorDraftLayout,
|
||||
discardEditorDraftLayout,
|
||||
} from "@/app/d/actions";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { WidgetPicker } from "./widget-picker";
|
||||
|
||||
@@ -58,8 +63,18 @@ export function DashboardEditor({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dashboard.slug]);
|
||||
|
||||
function publishDraft(next: WidgetPlacement[]) {
|
||||
startTransition(async () => {
|
||||
await syncEditorDraftLayout(dashboard.id, { version: 1, widgets: next });
|
||||
router.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
router.push(`/d/${dashboard.slug}`);
|
||||
startTransition(async () => {
|
||||
await discardEditorDraftLayout(dashboard.id);
|
||||
router.push(`/d/${dashboard.slug}`);
|
||||
});
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
@@ -89,26 +104,32 @@ export function DashboardEditor({
|
||||
}
|
||||
|
||||
function removeWidget(index: number) {
|
||||
setPlacements((current) => current.filter((_, i) => i !== index));
|
||||
const next = placements.filter((_, i) => i !== index);
|
||||
setPlacements(next);
|
||||
setIsDirty(true);
|
||||
publishDraft(next);
|
||||
}
|
||||
|
||||
function addWidget(widgetId: string, config: unknown) {
|
||||
const meta = widgetMetas.find((m) => m.id === widgetId);
|
||||
if (!meta) return;
|
||||
const maxY = placements.reduce((m, p) => Math.max(m, p.y + p.h), 0);
|
||||
setPlacements((current) => [
|
||||
...current,
|
||||
const next = [
|
||||
...placements,
|
||||
{ widgetId, config, x: 0, y: maxY, w: meta.defaultSize.w, h: meta.defaultSize.h },
|
||||
]);
|
||||
];
|
||||
setPlacements(next);
|
||||
setIsDirty(true);
|
||||
setPickerOpen(false);
|
||||
publishDraft(next);
|
||||
}
|
||||
|
||||
function updateConfig(index: number, config: unknown) {
|
||||
setPlacements((current) => current.map((p, i) => (i === index ? { ...p, config } : p)));
|
||||
const next = placements.map((p, i) => (i === index ? { ...p, config } : p));
|
||||
setPlacements(next);
|
||||
setIsDirty(true);
|
||||
setConfiguringIndex(null);
|
||||
publishDraft(next);
|
||||
}
|
||||
|
||||
function applyPreset(preset: PresetId) {
|
||||
@@ -116,6 +137,7 @@ export function DashboardEditor({
|
||||
setPlacements(next.widgets);
|
||||
setIsDirty(true);
|
||||
setPresetMenuOpen(false);
|
||||
publishDraft(next.widgets);
|
||||
}
|
||||
|
||||
const gridItems: Layout = placements.map((p, i) => ({
|
||||
|
||||
Reference in New Issue
Block a user