@@ -3,10 +3,18 @@ import { Link, Outlet } from "@tanstack/react-router";
33import { isAuthorizationRequired } from "@/components/shared/Authentication/helpers" ;
44import { TopBarAuthentication } from "@/components/shared/Authentication/TopBarAuthentication" ;
55import { Icon , type IconName } from "@/components/ui/icon" ;
6- import { BlockStack , InlineStack } from "@/components/ui/layout" ;
7- import { Heading , Text } from "@/components/ui/typography" ;
6+ import { InlineStack } from "@/components/ui/layout" ;
7+ import { Text } from "@/components/ui/typography" ;
88import { cn } from "@/lib/utils" ;
9- import { DOCUMENTATION_URL } from "@/utils/constants" ;
9+ import {
10+ ABOUT_URL ,
11+ DOCUMENTATION_URL ,
12+ GIT_COMMIT ,
13+ GIT_REPO_URL ,
14+ GIVE_FEEDBACK_URL ,
15+ PRIVACY_POLICY_URL ,
16+ TOP_NAV_HEIGHT ,
17+ } from "@/utils/constants" ;
1018
1119interface SidebarItem {
1220 to : string ;
@@ -32,74 +40,109 @@ export function DashboardLayout() {
3240 const requiresAuthorization = isAuthorizationRequired ( ) ;
3341
3442 return (
35- < div className = "w-full px-8 py-6" >
36- < BlockStack gap = "6" >
37- < InlineStack gap = "2" blockAlign = "center" >
38- < Heading level = { 1 } > Dashboard</ Heading >
39- < Text
40- as = "span"
41- size = "xs"
42- weight = "semibold"
43- className = "px-2 py-1 rounded-full bg-amber-100 text-amber-800"
44- >
45- Beta
46- </ Text >
47- </ InlineStack >
43+ < div
44+ className = "flex w-full overflow-hidden"
45+ style = { { height : `calc(100vh - ${ TOP_NAV_HEIGHT } px)` } }
46+ >
47+ { /* Sidebar — fixed height, independent scroll */ }
48+ < div className = "w-56 shrink-0 border-r border-border flex flex-col overflow-y-auto" >
49+ { /* Dashboard heading */ }
50+ < div className = "px-6 pt-6 pb-4 shrink-0" >
51+ < InlineStack gap = "2" blockAlign = "center" >
52+ < Text size = "lg" weight = "semibold" >
53+ Dashboard
54+ </ Text >
55+ < Text
56+ as = "span"
57+ size = "xs"
58+ weight = "semibold"
59+ className = "px-2 py-0.5 rounded-full bg-amber-100 text-amber-800"
60+ >
61+ Beta
62+ </ Text >
63+ </ InlineStack >
64+ </ div >
65+
66+ { /* Top nav items */ }
67+ < div className = "flex flex-col gap-1 px-3" >
68+ { SIDEBAR_ITEMS . map ( ( item ) => (
69+ < Link
70+ key = { item . to }
71+ to = { item . to }
72+ className = "w-full"
73+ activeProps = { { className : "is-active" } }
74+ >
75+ { ( { isActive } ) => (
76+ < div className = { navItemClass ( isActive ) } >
77+ < Icon name = { item . icon } size = "sm" />
78+ < Text size = "sm" > { item . label } </ Text >
79+ </ div >
80+ ) }
81+ </ Link >
82+ ) ) }
83+ </ div >
4884
49- < InlineStack gap = "8" blockAlign = "start" className = "w-full min-h-100" >
50- { /* Sidebar */ }
51- < div className = "w-48 shrink-0 border-r border-border pr-4 flex flex-col justify-between self-stretch" >
52- { /* Top nav */ }
53- < BlockStack gap = "1" >
54- { SIDEBAR_ITEMS . map ( ( item ) => (
55- < Link
56- key = { item . to }
57- to = { item . to }
58- className = "w-full"
59- activeProps = { { className : "is-active" } }
60- >
61- { ( { isActive } ) => (
62- < div className = { navItemClass ( isActive ) } >
63- < Icon name = { item . icon } size = "sm" />
64- < Text size = "sm" > { item . label } </ Text >
65- </ div >
66- ) }
67- </ Link >
68- ) ) }
69- </ BlockStack >
85+ { /* Spacer */ }
86+ < div className = "flex-1 min-h-4" />
7087
71- { /* Bottom utilities */ }
72- < BlockStack gap = "1" className = "border-t border-border pt-3" >
88+ { /* Bottom utilities */ }
89+ < div className = "flex flex-col gap-1 px-3 border-t border-border pt-3 pb-3" >
90+ < a
91+ href = { DOCUMENTATION_URL }
92+ target = "_blank"
93+ rel = "noopener noreferrer"
94+ className = { navItemClass ( false ) }
95+ >
96+ < Icon name = "BookOpen" size = "sm" />
97+ < Text size = "sm" > Docs</ Text >
98+ </ a >
99+ < Link to = "/settings/backend" className = "w-full" >
100+ { ( { isActive } ) => (
101+ < div className = { navItemClass ( isActive ) } >
102+ < Icon name = "Settings" size = "sm" />
103+ < Text size = "sm" > Settings</ Text >
104+ </ div >
105+ ) }
106+ </ Link >
107+ { requiresAuthorization && (
108+ < div className = "px-3 py-2" >
109+ < TopBarAuthentication />
110+ </ div >
111+ ) }
112+
113+ { /* Footer links */ }
114+ < div className = "flex flex-col gap-0.5 pt-2 mt-1 border-t border-border" >
115+ { [
116+ { label : "About" , href : ABOUT_URL } ,
117+ { label : "Give feedback" , href : GIVE_FEEDBACK_URL } ,
118+ { label : "Privacy policy" , href : PRIVACY_POLICY_URL } ,
119+ ] . map ( ( { label, href } ) => (
73120 < a
74- href = { DOCUMENTATION_URL }
121+ key = { label }
122+ href = { href }
75123 target = "_blank"
76124 rel = "noopener noreferrer"
77- className = { navItemClass ( false ) }
125+ className = "px-3 py-1 text-xs text-muted-foreground hover:text-foreground rounded-md hover:bg-accent"
78126 >
79- < Icon name = "BookOpen" size = "sm" />
80- < Text size = "sm" > Docs</ Text >
127+ { label }
81128 </ a >
82- < Link to = "/settings/backend" className = "w-full" >
83- { ( { isActive } ) => (
84- < div className = { navItemClass ( isActive ) } >
85- < Icon name = "Settings" size = "sm" />
86- < Text size = "sm" > Settings</ Text >
87- </ div >
88- ) }
89- </ Link >
90- { requiresAuthorization && (
91- < div className = "px-3 py-2" >
92- < TopBarAuthentication />
93- </ div >
94- ) }
95- </ BlockStack >
129+ ) ) }
130+ < a
131+ href = { `${ GIT_REPO_URL } /commit/${ GIT_COMMIT } ` }
132+ target = "_blank"
133+ rel = "noopener noreferrer"
134+ className = "px-3 py-1 text-xs text-muted-foreground hover:text-foreground rounded-md hover:bg-accent font-mono"
135+ >
136+ ver: { GIT_COMMIT . substring ( 0 , 6 ) }
137+ </ a >
96138 </ div >
139+ </ div >
140+ </ div >
97141
98- < BlockStack className = "flex-1 min-w-0" >
99- < Outlet />
100- </ BlockStack >
101- </ InlineStack >
102- </ BlockStack >
142+ { /* Main content — independent scroll */ }
143+ < div className = "flex-1 min-w-0 overflow-y-auto px-8 pb-6 pt-4" >
144+ < Outlet />
145+ </ div >
103146 </ div >
104147 ) ;
105148}
0 commit comments