feat(ui): add scroll area component and navigation enhancements

Add ScrollArea UI component using Radix UI for better content scrolling.
Enhance header navigation with back button and conditional home button display.
Update dependencies including @radix-ui/react-scroll-area and reorganize @nontara/server.
This commit is contained in:
2025-10-02 09:16:38 +00:00
parent a44c4afbc3
commit cdda5108dd
5 changed files with 112 additions and 20 deletions

View File

@@ -9,9 +9,11 @@
},
"dependencies": {
"@nontara/language-codes": "workspace:*",
"@nontara/server": "workspace:*",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
@@ -26,7 +28,6 @@
"@trpc/client": "^11.5.0",
"@trpc/server": "^11.5.0",
"@trpc/tanstack-react-query": "^11.5.0",
"@nontara/server": "workspace:*",
"better-auth": "^1.3.10",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",

View File

@@ -1,5 +1,6 @@
import { Link, useRouterState } from "@tanstack/react-router";
import { Link, useRouter, useRouterState } from "@tanstack/react-router";
import {
ArrowLeft,
Folder,
FolderTree,
Home,
@@ -115,8 +116,9 @@ NavigationSheetContent.displayName = "NavigationSheetContent";
function HeaderBar() {
const [open, setOpen] = useState(false);
const handleNavigate = useCallback(() => setOpen(false), []);
const router = useRouterState();
const pathname = router.location.pathname;
const router = useRouter();
const routerState = useRouterState();
const pathname = routerState.location.pathname;
if (pathname.endsWith("dashboard") || pathname.endsWith("dashboard/")) {
return;
@@ -125,6 +127,30 @@ function HeaderBar() {
return (
<header className="sticky top-0 z-50 flex items-center justify-between border-border border-b bg-muted/95 px-5 py-3 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-muted/80">
<div className="flex items-center gap-3">
{pathname !== "/home" && (
<>
<Button
type="button"
variant="ghost"
size="icon"
aria-label="Go back"
onClick={() => router.history.back()}
>
<ArrowLeft className="size-5" aria-hidden="true" />
</Button>
<Button
type="button"
variant="ghost"
size="icon"
aria-label="Go to home"
asChild
>
<Link to="/home">
<Home className="size-5" aria-hidden="true" />
</Link>
</Button>
</>
)}
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
@@ -141,15 +167,19 @@ function HeaderBar() {
<NavigationSheetContent onNavigate={handleNavigate} />
</SheetContent>
</Sheet>
<img
src={logoSrc}
alt="Nontara logo"
className="h-9 w-auto select-none"
loading="eager"
fetchPriority="high"
decoding="async"
draggable={false}
/>
{pathname === "/home" && (
<Link to="/home" className="flex items-center">
<img
src={logoSrc}
alt="Nontara logo"
className="h-9 w-auto select-none"
loading="eager"
fetchPriority="high"
decoding="async"
draggable={false}
/>
</Link>
)}
</div>
<div className="flex items-center gap-2">
<Button

View File

@@ -0,0 +1,56 @@
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import type * as React from "react";
import { cn } from "@/lib/utils";
function ScrollArea({
className,
children,
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn("relative", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] focus-visible:ring-ring/50"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
);
}
function ScrollBar({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
return (
<ScrollAreaPrimitive.ScrollAreaScrollbar
data-slot="scroll-area-scrollbar"
orientation={orientation}
className={cn(
"flex touch-none select-none p-px transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent",
className,
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb
data-slot="scroll-area-thumb"
className="relative flex-1 rounded-full bg-border"
/>
</ScrollAreaPrimitive.ScrollAreaScrollbar>
);
}
export { ScrollArea, ScrollBar };

View File

@@ -11,6 +11,7 @@ import {
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import type { TRPCOptionsProxy } from "@trpc/tanstack-react-query";
import { ThemeProvider } from "next-themes";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Toaster } from "@/components/ui/sonner";
import type { AppRouter } from "../../../server/src/trpc";
import appCss from "../index.css?url";
@@ -57,11 +58,14 @@ function RootDocument() {
enableSystem
disableTransitionOnChange
>
<div className="grid h-svh grid-rows-[auto_1fr]">
{/* <Header />
{isFetching ? <Loader /> : <Outlet />} */}
<Outlet />
</div>
<ScrollArea className="h-svh w-full">
<div className="grid min-h-svh grid-rows-[auto_1fr]">
{/* <Header />
{isFetching ? <Loader /> : <Outlet />} */}
<Outlet />
</div>
<ScrollBar orientation="vertical" />
</ScrollArea>
<Toaster richColors />
</ThemeProvider>
<TanStackRouterDevtools position="bottom-left" />

View File

@@ -41,6 +41,7 @@
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
@@ -67,8 +68,8 @@
"react-dom": "19.1.0",
"sonner": "^2.0.3",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.13",
"tw-animate-css": "^1.4.0",
"tailwindcss": "^4.1.3",
"tw-animate-css": "^1.2.5",
"vite-tsconfig-paths": "^5.1.4",
"zod": "^4.0.2",
},