feat(meetings): center clock, fullscreen toggle, quick-note tab (#583)
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
This commit is contained in:
@@ -286,14 +286,10 @@ export default function NotesPage() {
|
|||||||
setView("active");
|
setView("active");
|
||||||
// The top Composer is only mounted when
|
// The top Composer is only mounted when
|
||||||
// `view === "active" && folderSelection.kind !== "shared-folder"`.
|
// `view === "active" && folderSelection.kind !== "shared-folder"`.
|
||||||
// If the user arrived from /notes?new=1 while sitting inside a
|
// Always land on the default "all" folder so /notes?new=1 has a
|
||||||
// shared folder, leaving the selection alone would mean the
|
// deterministic landing state and the composer is guaranteed
|
||||||
// Composer is never rendered and the open trigger would be lost.
|
// mounted regardless of where the user was before.
|
||||||
// Reset to the default "all" folder so the composer is guaranteed
|
setFolderSelection({ kind: "all" });
|
||||||
// visible regardless of where they were before.
|
|
||||||
setFolderSelection((cur) =>
|
|
||||||
cur.kind === "shared-folder" ? { kind: "all" } : cur,
|
|
||||||
);
|
|
||||||
setComposerOpenTrigger((n) => n + 1);
|
setComposerOpenTrigger((n) => n + 1);
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
params.delete("new");
|
params.delete("new");
|
||||||
@@ -3566,10 +3562,14 @@ function Composer({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// External open trigger (e.g. /notes?new=1 from the meetings quick
|
// External open trigger (e.g. /notes?new=1 from the meetings quick
|
||||||
// note tab). Skip the initial mount value (0) and only react to
|
// note tab). React both to subsequent bumps AND to the initial mount
|
||||||
// subsequent bumps, then focus + scroll the textarea into view.
|
// when the trigger is already > 0 — this covers the case where the
|
||||||
const lastOpenTrigger = useRef(openTrigger);
|
// page resets folder selection and the Composer mounts fresh with a
|
||||||
|
// non-zero trigger (e.g. user was in a shared folder and clicked the
|
||||||
|
// quick-note tab).
|
||||||
|
const lastOpenTrigger = useRef(0);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (openTrigger === 0) return;
|
||||||
if (openTrigger === lastOpenTrigger.current) return;
|
if (openTrigger === lastOpenTrigger.current) return;
|
||||||
lastOpenTrigger.current = openTrigger;
|
lastOpenTrigger.current = openTrigger;
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user