Skip to content

Commit ac48707

Browse files
drakehanguyenDrakeNguyen
andauthored
Feature/update UI add about page (#34)
* Update homepage * Add About Page --------- Co-authored-by: DrakeNguyen <drake.ha.nguyen@gmail.com>
1 parent 8392aa6 commit ac48707

11 files changed

Lines changed: 320 additions & 76 deletions

File tree

src/app/about/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Route handler for /about - content is rendered by AppLayout
2+
export default function AboutPageRoute() {
3+
return null;
4+
}

src/app/globals.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,28 @@
263263
* {
264264
@apply border-border;
265265
}
266+
html {
267+
width: 100%;
268+
border-width: 0px;
269+
border-color: rgba(0, 0, 0, 0);
270+
border-style: none;
271+
border-image: none;
272+
}
266273
body {
267274
@apply bg-background text-foreground;
268275
}
269276
h1 {
270277
@apply font-serif;
271278
}
279+
/* Style Radix SelectValue (Primitive.span) */
280+
[data-radix-select-value] {
281+
color: var(--color-neutral-800, hsl(0, 0%, 15%));
282+
letter-spacing: 0px;
283+
font-size: 13px;
284+
}
285+
.dark [data-radix-select-value] {
286+
color: var(--color-neutral-200, hsl(0, 0%, 90%));
287+
}
272288
}
273289

274290
/* ============================================

src/app/icon.svg

Lines changed: 6 additions & 0 deletions
Loading

src/app/layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AppLayout } from '@/components/layout/AppLayout'
22
import { ThemeProvider } from '@/components/providers/ThemeProvider'
33
import type { Metadata, Viewport } from 'next'
4-
import { Geist, Geist_Mono, DM_Serif_Text } from 'next/font/google'
4+
import { DM_Serif_Text, Geist, Geist_Mono } from 'next/font/google'
55
import './globals.css'
66

77
const geistSans = Geist({
@@ -16,6 +16,7 @@ const geistMono = Geist_Mono({
1616

1717
const dmSerifText = DM_Serif_Text({
1818
weight: ['400'],
19+
style: ['normal', 'italic'],
1920
subsets: ['latin'],
2021
variable: '--font-dm-serif',
2122
})

src/components/AppSidebar.tsx

Lines changed: 110 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ import {
4040
Code,
4141
FileText,
4242
Globe,
43+
Heart,
4344
Home,
45+
Info,
4446
Lock,
4547
Moon,
4648
PanelLeft,
@@ -73,13 +75,15 @@ interface AppSidebarProps extends React.ComponentProps<typeof Sidebar> {
7375
onToolSelect?: (toolId: string) => void
7476
onHomeClick?: () => void
7577
onLogoClick?: () => void // Clears all state and navigates home
78+
onAboutClick?: () => void // Handles About page navigation
7679
}
7780

7881
export function AppSidebar({
7982
selectedTool,
8083
onToolSelect,
8184
onHomeClick,
8285
onLogoClick,
86+
onAboutClick,
8387
...props
8488
}: AppSidebarProps) {
8589
const router = useRouter()
@@ -293,58 +297,116 @@ export function AppSidebar({
293297
)
294298
})}
295299
</SidebarContent>
296-
<SidebarFooter className="px-2 py-2 group-data-[collapsible=icon]:hidden">
297-
<div className="space-y-2">
298-
{/* Code Editor Theme Selector */}
299-
<div className="bg-neutral-100 dark:bg-neutral-800 rounded-[10px] p-2">
300-
<div className="text-xs font-medium text-neutral-600 dark:text-neutral-400 mb-1.5 px-1">
301-
Code Editor Theme
302-
</div>
303-
<Select
304-
value={codeEditorTheme}
305-
onValueChange={(value) => setCodeEditorTheme(value as CodeEditorTheme)}
300+
<SidebarFooter className="px-2 pt-2 pb-5 gap-2 group-data-[collapsible=icon]:items-center">
301+
{/* Top Separator */}
302+
<SidebarSeparator className="my-1 -mx-2 w-auto self-stretch" />
303+
304+
{/* About and Support us menu items */}
305+
<SidebarMenu className="group-data-[collapsible=icon]:w-auto">
306+
<SidebarMenuItem>
307+
<SidebarMenuButton
308+
tooltip={isCollapsed ? "About" : undefined}
309+
onClick={() => {
310+
if (onAboutClick) {
311+
onAboutClick();
312+
} else {
313+
router.push('/about');
314+
}
315+
}}
306316
>
307-
<SelectTrigger className="h-8 w-full text-xs">
308-
<SelectValue />
309-
</SelectTrigger>
310-
<SelectContent container={typeof document !== 'undefined' ? document.body : undefined}>
311-
{Object.values(CODE_EDITOR_THEMES).map((themeConfig) => (
312-
<SelectItem key={themeConfig.name} value={themeConfig.name}>
313-
{themeConfig.label}
314-
</SelectItem>
315-
))}
316-
</SelectContent>
317-
</Select>
317+
<Info className="h-4 w-4" />
318+
<span className={cn(isCollapsed && "hidden")}>About</span>
319+
</SidebarMenuButton>
320+
</SidebarMenuItem>
321+
<SidebarMenuItem>
322+
<SidebarMenuButton tooltip={isCollapsed ? "Support us" : undefined}>
323+
<Heart className="h-4 w-4" />
324+
<span className={cn(isCollapsed && "hidden")}>Support us</span>
325+
</SidebarMenuButton>
326+
</SidebarMenuItem>
327+
</SidebarMenu>
328+
329+
{/* Separator */}
330+
<SidebarSeparator className="my-1 -mx-2 w-auto self-stretch" />
331+
332+
{/* Theme Toggle - Different layouts for collapsed vs expanded */}
333+
{isCollapsed ? (
334+
/* Collapsed: Single icon toggle button */
335+
<div className="flex justify-center">
336+
<Tooltip>
337+
<TooltipTrigger asChild>
338+
<button
339+
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
340+
className={cn(
341+
'flex items-center justify-center h-8 w-8 rounded-[8px] transition-colors bg-neutral-100 dark:bg-neutral-800 hover:bg-neutral-200 dark:hover:bg-neutral-700'
342+
)}
343+
>
344+
{mounted && theme === 'dark' ? (
345+
<Sun className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
346+
) : (
347+
<Moon className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
348+
)}
349+
</button>
350+
</TooltipTrigger>
351+
<TooltipContent side="right">
352+
{mounted && theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
353+
</TooltipContent>
354+
</Tooltip>
318355
</div>
356+
) : (
357+
/* Expanded: Combined Theme Toggle and Code Editor Theme Selector */
358+
<div className="flex items-center gap-2 pl-1.5 pr-[8px] pt-1">
359+
{/* Dark/Light Mode Toggle */}
360+
<div className="bg-neutral-100 dark:bg-neutral-800 rounded-[10px] p-[3px] flex items-center flex-shrink-0">
361+
<button
362+
onClick={() => setTheme('light')}
363+
className={cn(
364+
'flex items-center justify-center min-h-[29px] min-w-[29px] px-2 py-1 rounded-[8px] transition-colors',
365+
mounted && theme === 'light'
366+
? 'bg-white dark:bg-neutral-900 shadow-xs'
367+
: 'bg-transparent'
368+
)}
369+
title="Light mode"
370+
>
371+
<Sun className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
372+
</button>
373+
<button
374+
onClick={() => setTheme('dark')}
375+
className={cn(
376+
'flex items-center justify-center min-h-[29px] min-w-[29px] px-2 py-1 rounded-[8px] transition-colors',
377+
mounted && theme === 'dark'
378+
? 'bg-white dark:bg-neutral-900 shadow-xs'
379+
: 'bg-transparent'
380+
)}
381+
title="Dark mode"
382+
>
383+
<Moon className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
384+
</button>
385+
</div>
319386

320-
{/* Dark/Light Mode Toggle */}
321-
<div className="bg-neutral-100 dark:bg-neutral-800 rounded-[10px] p-[3px] flex items-center">
322-
<button
323-
onClick={() => setTheme('light')}
324-
className={cn(
325-
'flex-1 flex items-center justify-center min-h-[29px] min-w-[29px] px-2 py-1 rounded-[10px] transition-colors',
326-
mounted && theme === 'light'
327-
? 'bg-white dark:bg-neutral-900 shadow-xs'
328-
: 'bg-transparent'
329-
)}
330-
title="Light mode"
331-
>
332-
<Sun className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
333-
</button>
334-
<button
335-
onClick={() => setTheme('dark')}
336-
className={cn(
337-
'flex-1 flex items-center justify-center min-h-[29px] min-w-[29px] px-2 py-1 rounded-[10px] transition-colors',
338-
mounted && theme === 'dark'
339-
? 'bg-white dark:bg-neutral-900 shadow-xs'
340-
: 'bg-transparent'
341-
)}
342-
title="Dark mode"
343-
>
344-
<Moon className="h-4 w-4 text-neutral-600 dark:text-neutral-400" />
345-
</button>
387+
{/* Code Editor Theme Selector */}
388+
<div className="flex-1">
389+
<Select
390+
value={codeEditorTheme}
391+
onValueChange={(value) => setCodeEditorTheme(value as CodeEditorTheme)}
392+
>
393+
<SelectTrigger className="h-[35px] w-full text-xs bg-neutral-100 dark:bg-neutral-800">
394+
<div className="flex items-center gap-2">
395+
<Code className="h-3.5 w-3.5 text-neutral-600 dark:text-neutral-400" />
396+
<SelectValue />
397+
</div>
398+
</SelectTrigger>
399+
<SelectContent container={typeof document !== 'undefined' ? document.body : undefined}>
400+
{Object.values(CODE_EDITOR_THEMES).map((themeConfig) => (
401+
<SelectItem key={themeConfig.name} value={themeConfig.name}>
402+
{themeConfig.label}
403+
</SelectItem>
404+
))}
405+
</SelectContent>
406+
</Select>
407+
</div>
346408
</div>
347-
</div>
409+
)}
348410
</SidebarFooter>
349411
<SidebarRail />
350412
</Sidebar>

0 commit comments

Comments
 (0)