11import {
2- Sidebar ,
3- SidebarContent ,
4- SidebarFooter ,
5- SidebarGroup ,
6- SidebarGroupContent ,
7- SidebarHeader ,
8- SidebarMenu ,
9- SidebarMenuButton ,
10- SidebarMenuItem ,
11- useSidebar ,
2+ Sidebar , SidebarContent , SidebarFooter , SidebarGroup , SidebarGroupContent , SidebarHeader , SidebarMenu , SidebarMenuButton , SidebarMenuItem , useSidebar ,
123} from "@/components/ui/sidebar"
13- import { ChevronDoubleRight , CircleNotch , DownloadSolid , SquareSolid } from "@mynaui/icons-react" ;
14- import { LargeP , P , TinyP } from "./typography" ;
4+ import { ChevronDoubleRight , CircleNotch , DownloadSolid , FileTextSolid , SquareSolid } from "@mynaui/icons-react" ;
5+ import { LargeP , P , SmallP , TinyP } from "./typography" ;
156import { Button } from "./ui/button" ;
167import { Link , useRouterState } from "@tanstack/react-router" ;
178import { useEffect , useState } from "react" ;
189import { app } from "@tauri-apps/api" ;
19- import { useSetAtom } from "jotai/react" ;
10+ import { useAtom , useSetAtom } from "jotai/react" ;
2011import { appStateAtom } from "@/lib/store" ;
2112import { routes } from "@/lib/routes" ;
2213import { invoke } from "@tauri-apps/api/core" ;
2314import { logEvent } from "firebase/analytics" ;
2415import { getFirebaseAnalytics } from "@/lib/firebase" ;
16+ import { fetchGithubRelease } from "@/lib/utils" ;
17+ import DialogUI from "./dialog" ;
18+ import Markdown from 'react-markdown'
2519
2620const analytics = getFirebaseAnalytics ( ) ;
2721
2822export function AppSidebar ( ) {
2923 const { resolvedLocation } = useRouterState ( ) ;
30- const setAppState = useSetAtom ( appStateAtom ) ;
24+ const [ appState , setAppState ] = useAtom ( appStateAtom ) ;
3125
3226 const { toggleSidebar, open } = useSidebar ( ) ;
3327 const [ version , setVersion ] = useState ( "" ) ;
28+ const [ releaseNotes , setReleaseNotes ] = useState ( "" ) ;
3429 const [ newVersion , setNewVersion ] = useState ( "" ) ;
3530 const [ isUpdating , setIsUpdating ] = useState ( false ) ;
31+ const [ viewedNotes , setViewedNotes ] = useState ( true ) ;
3632
3733 useEffect ( ( ) => {
3834 app . getVersion ( ) . then ( v => setVersion ( v ) ) ;
@@ -41,6 +37,7 @@ export function AppSidebar() {
4137
4238 useEffect ( ( ) => {
4339 logEvent ( analytics , "started_app" , { version } ) ;
40+ getReleaseNotes ( version ) ;
4441 } , [ version ] ) ;
4542
4643 useEffect ( ( ) => {
@@ -72,6 +69,22 @@ export function AppSidebar() {
7269 setIsUpdating ( false ) ;
7370 }
7471
72+ const getReleaseNotes = async ( tag : string ) => {
73+ const release = await fetchGithubRelease ( `v${ tag } ` ) ;
74+ if ( release ) {
75+ const body = release . body as string ;
76+ const notes = body . replace ( / ^ ( .| \n | \r ) * # # # R e l e a s e N o t e s \r \n / g, "" ) ;
77+ setReleaseNotes ( notes ) ;
78+ }
79+ }
80+
81+ const handleSetReleaseNotesAsViewed = ( isOpen : boolean ) => {
82+ if ( appState . viewedNotesForVersion === version ) return ;
83+ setAppState ( state => {
84+ state . viewedNotesForVersion = version ;
85+ } ) ;
86+ }
87+
7588 return (
7689 < Sidebar collapsible = "icon" >
7790 < SidebarHeader >
@@ -111,8 +124,28 @@ export function AppSidebar() {
111124 </ SidebarGroup >
112125 </ SidebarContent >
113126 < SidebarFooter className = "flex flex-col items-end gap-4" >
114- { newVersion &&
115- < SidebarMenu >
127+ < SidebarMenu className = "flex flex-col gap-2" >
128+ { ( version && releaseNotes ) &&
129+ < SidebarMenuItem className = "flex gap-2 justify-center items-center shadow-lg" >
130+ < DialogUI
131+ title = { `Release Notes (v${ version } )` }
132+ trigger = {
133+ < SidebarMenuButton size = "lg" className = "!bg-card border" >
134+ < FileTextSolid className = { `transition-all ml-[0.41rem] ${ open && "!size-7 ml-0" } ` } />
135+ < div className = "flex-1 text-sm leading-tight flex-col gap-1" >
136+ < P className = "truncate" > Release Notes</ P >
137+ < TinyP className = "truncate" > v{ version } </ TinyP >
138+ </ div >
139+ </ SidebarMenuButton >
140+ }
141+ defaultOpen = { appState . viewedNotesForVersion !== version }
142+ onOpenChange = { handleSetReleaseNotesAsViewed }
143+ >
144+ < Markdown > { releaseNotes } </ Markdown >
145+ </ DialogUI >
146+ </ SidebarMenuItem >
147+ }
148+ { newVersion &&
116149 < SidebarMenuItem className = "flex gap-2 justify-center items-center shadow-lg shadow-green-600 animate-pulse" >
117150 < SidebarMenuButton size = "lg" className = "!bg-card border border-green-900" onClick = { handleInstallUpdate } disabled = { isUpdating } >
118151 { isUpdating
@@ -125,8 +158,8 @@ export function AppSidebar() {
125158 </ div >
126159 </ SidebarMenuButton >
127160 </ SidebarMenuItem >
128- </ SidebarMenu >
129- }
161+ }
162+ </ SidebarMenu >
130163 < Button className = "size-8" variant = "outline" size = "icon" onClick = { toggleSidebar } >
131164 < ChevronDoubleRight className = { `transition-transform ${ open ? "rotate-180" : "" } ` } />
132165 </ Button >
0 commit comments