Files
famapp/src/modules/notes/components/shared-view.tsx
T
ginnoir a4be5d5061 feat(notes): rich-text editor with tiptap (task 85)
Replace plain textarea with shared tiptap editor and sanitized html rendering.

Adds interactive checklists on read surfaces and mobile overflow fixes.
2026-07-04 19:25:15 -05:00

68 lines
1.8 KiB
TypeScript

"use client";
import { FileText, Pin } from "lucide-react";
import { RichTextContent } from "@/components/rich-text";
import { ShareEyebrow } from "@/components/share/share-eyebrow";
import type { NoteShareData } from "../server/share-queries";
import { toggleShareNoteChecklistItem } from "../server/checklist-actions";
type Props = {
data: NoteShareData;
canWrite?: boolean;
token?: string;
};
export function NoteSharedView({ data, canWrite = false, token }: Props) {
const updated = new Date(data.updatedAt).toLocaleDateString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
});
return (
<>
<ShareEyebrow>
<FileText className="size-3" />
Note
</ShareEyebrow>
<h1
className="serif"
style={{
fontSize: "clamp(28px, 6vw, 38px)",
lineHeight: 1.15,
letterSpacing: "-0.02em",
color: "var(--ink)",
margin: "0 0 8px",
textWrap: "pretty",
}}
>
{data.title}
</h1>
<p className="muted text-[13px] mb-6 inline-flex items-center gap-2">
{data.pinned && (
<span className="inline-flex items-center gap-1">
<Pin className="size-3 text-[var(--accent)]" />
Pinned
</span>
)}
{data.pinned && <span>·</span>}
<span>Updated {updated}</span>
</p>
{data.body ? (
<RichTextContent
html={data.body}
interactiveChecklists={canWrite && !!token}
onToggleChecklist={
canWrite && token
? async (taskIndex, checked) => {
await toggleShareNoteChecklistItem(token, data.id, taskIndex, checked);
}
: undefined
}
/>
) : null}
</>
);
}