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:
@@ -8,7 +8,9 @@ import listPlugin from "@fullcalendar/list";
|
||||
import type { DateSelectArg, EventClickArg, EventDropArg } from "@fullcalendar/core";
|
||||
import type { EventResizeDoneArg } from "@fullcalendar/interaction";
|
||||
import { CalendarPlus, Check, Eye, EyeOff, Plus, Trash2, X } from "lucide-react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useMemo, useState, useEffect, useTransition } from "react";
|
||||
import { richTextToPlainText } from "@/components/rich-text";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -34,6 +36,18 @@ import {
|
||||
updateEvent,
|
||||
} from "../server/actions";
|
||||
|
||||
const RichTextEditor = dynamic(
|
||||
() => import("@/components/rich-text/rich-text-editor").then((mod) => mod.RichTextEditor),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="min-h-24 rounded-lg border border-input px-3 py-2 text-sm text-muted-foreground animate-pulse">
|
||||
Loading editor…
|
||||
</div>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
type EventDraft = {
|
||||
id?: string;
|
||||
calendarId: string;
|
||||
@@ -180,7 +194,7 @@ export function CalendarShell({
|
||||
endAt: new Date(selectedEvent.endAt),
|
||||
allDay: selectedEvent.allDay,
|
||||
location: selectedEvent.location || null,
|
||||
notes: selectedEvent.notes || null,
|
||||
notes: richTextToPlainText(selectedEvent.notes) ? selectedEvent.notes : null,
|
||||
};
|
||||
|
||||
startTransition(async () => {
|
||||
@@ -513,13 +527,17 @@ export function CalendarShell({
|
||||
value={selectedEvent.location}
|
||||
onChange={(event) => setSelectedEvent({ ...selectedEvent, location: event.target.value })}
|
||||
/>
|
||||
<Label htmlFor="event-notes">Notes</Label>
|
||||
<textarea
|
||||
id="event-notes"
|
||||
className="min-h-20 rounded-lg border border-input bg-transparent px-2.5 py-2 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
|
||||
value={selectedEvent.notes}
|
||||
onChange={(event) => setSelectedEvent({ ...selectedEvent, notes: event.target.value })}
|
||||
/>
|
||||
<div className="space-y-1.5 min-w-0">
|
||||
<Label htmlFor="event-notes">Notes</Label>
|
||||
<RichTextEditor
|
||||
id="event-notes"
|
||||
aria-label="Notes"
|
||||
value={selectedEvent.notes}
|
||||
onChange={(notes) => setSelectedEvent({ ...selectedEvent, notes })}
|
||||
disabled={isPending}
|
||||
placeholder="Add details…"
|
||||
/>
|
||||
</div>
|
||||
{!selectedEvent.id && (
|
||||
<label className="flex items-center gap-2 text-sm">
|
||||
<input
|
||||
@@ -696,7 +714,7 @@ export function CalendarShell({
|
||||
style={{
|
||||
borderRadius: isMobile ? "var(--r-xl) var(--r-xl) 0 0" : "var(--r-lg)",
|
||||
width: isMobile ? "100%" : undefined,
|
||||
maxWidth: isMobile ? undefined : "512px",
|
||||
maxWidth: isMobile ? undefined : "672px",
|
||||
maxHeight: "90dvh",
|
||||
padding: "1rem",
|
||||
paddingBottom: isMobile ? "calc(1rem + env(safe-area-inset-bottom))" : "1rem",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Calendar as CalendarIcon, MapPin } from "lucide-react";
|
||||
import { RichTextContent } from "@/components/rich-text";
|
||||
import type { CalendarShareData, EventShareData } from "../server/share-queries";
|
||||
import { ShareEyebrow } from "@/components/share/share-eyebrow";
|
||||
import { MiniDayCard } from "@/components/share/mini-day-card";
|
||||
@@ -92,7 +93,7 @@ export function EventSharedView({ data }: { data: EventShareData }) {
|
||||
</ShareDetailCard>
|
||||
|
||||
{data.notes && (
|
||||
<p
|
||||
<div
|
||||
className="serif"
|
||||
style={{
|
||||
fontSize: 16,
|
||||
@@ -103,11 +104,10 @@ export function EventSharedView({ data }: { data: EventShareData }) {
|
||||
padding: "18px 22px",
|
||||
margin: "14px 0 24px",
|
||||
textWrap: "pretty",
|
||||
whiteSpace: "pre-wrap",
|
||||
}}
|
||||
>
|
||||
{data.notes}
|
||||
</p>
|
||||
<RichTextContent html={data.notes} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user