Compare commits

...

1 Commits

Author SHA1 Message Date
Jiang Bohan
9641a9dc1c feat(changelog): surface release notes from sidebar menu + update prompt
Two entry points to multica.ai/changelog so users actually find out
what shipped:

- Sidebar user menu (both expanded popover + collapsed dropdown
  variants) gains a "What's new" item with a Sparkles icon, sitting
  above Log out. Plain `<a target="_blank">` works on both surfaces:
  web opens a new tab, desktop's main-process
  setWindowOpenHandler intercepts and routes through
  openExternalSafely. The shared view doesn't need to branch.
- Desktop's UpdateNotification "ready to restart" card grows a
  secondary "See changes" button next to "Restart now", giving the
  user a reason to actually restart instead of dismissing. Mirrors
  Conductor's update prompt pattern. The "available" / "downloading"
  states stay action-only — the changelog isn't useful before the
  download finishes.

No version-detection / unread-tracking yet. Web users still need to
click into the menu to see the changelog; that's a follow-up if the
team wants Linear-style "new" dot.
2026-04-22 15:11:36 +08:00
2 changed files with 45 additions and 6 deletions

View File

@@ -110,12 +110,25 @@ export function UpdateNotification() {
<p className="text-xs text-muted-foreground mt-0.5">
Restart to apply the update
</p>
<button
onClick={handleInstall}
className="mt-2 inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
>
Restart now
</button>
<div className="mt-2 flex items-center gap-1.5">
{/* Secondary "See changes" — gives the user a reason to
restart by surfacing what they're about to get. Opens
in the default browser via the shared openExternal
bridge so the URL hits the same allow-list as every
other outbound link. */}
<button
onClick={() => window.desktopAPI.openExternal("https://multica.ai/changelog")}
className="inline-flex items-center rounded-md border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground hover:bg-accent transition-colors"
>
See changes
</button>
<button
onClick={handleInstall}
className="inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
>
Restart now
</button>
</div>
</div>
</div>
)}

View File

@@ -28,6 +28,7 @@ import {
SquarePen,
CircleUser,
FolderKanban,
Sparkles,
X,
Zap,
} from "lucide-react";
@@ -415,6 +416,22 @@ export function AppSidebar({ topSlot, searchSlot, headerClassName, headerStyle }
)}
<DropdownMenuSeparator />
<DropdownMenuGroup>
{/* Plain anchor with target=_blank works on both web
(new tab) and desktop (intercepted by the main
process's setWindowOpenHandler → openExternalSafely),
so the shared component doesn't need to branch. */}
<DropdownMenuItem
render={
<a
href="https://multica.ai/changelog"
target="_blank"
rel="noopener noreferrer"
/>
}
>
<Sparkles className="h-3.5 w-3.5" />
What&apos;s new
</DropdownMenuItem>
<DropdownMenuItem variant="destructive" onClick={logout}>
<LogOut className="h-3.5 w-3.5" />
Log out
@@ -599,6 +616,15 @@ export function AppSidebar({ topSlot, searchSlot, headerClassName, headerStyle }
</div>
</div>
<div className="p-1">
<a
href="https://multica.ai/changelog"
target="_blank"
rel="noopener noreferrer"
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-foreground hover:bg-accent transition-colors cursor-pointer"
>
<Sparkles className="h-3.5 w-3.5" />
What&apos;s new
</a>
<button
onClick={logout}
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-destructive hover:bg-destructive/10 transition-colors cursor-pointer"