styles: refactor codebase base style

This commit is contained in:
2026-06-17 14:46:12 +05:30
parent 182d4ac293
commit 15f54372f4
43 changed files with 161 additions and 268 deletions

15
package-lock.json generated
View File

@@ -9895,21 +9895,6 @@
"optional": true "optional": true
} }
} }
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "16.0.10",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz",
"integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
} }
} }
} }

View File

@@ -6,45 +6,19 @@ import { Label } from '@/components/ui/label';
import { GuestGuard } from '@/guards'; import { GuestGuard } from '@/guards';
import { useLoginForm } from '@/hooks/useLoginForm'; import { useLoginForm } from '@/hooks/useLoginForm';
import { Loader2 } from 'lucide-react'; import { Loader2 } from 'lucide-react';
import Image from 'next/image';
export default function LoginPage() { export default function LoginPage() {
const { register, handleSubmit, errors, isLoading } = useLoginForm(); const { register, handleSubmit, errors, isLoading } = useLoginForm();
return ( return (
<GuestGuard> <GuestGuard>
<main className="grid min-h-screen bg-background text-foreground lg:grid-cols-[1.05fr_0.95fr]"> <div className="flex min-h-screen w-full">
<section className="relative hidden overflow-hidden border-r border-border/60 lg:block"> <div className="hidden md:flex w-[40%]" />
<Image <div className="flex flex-1 md:w-[60%] items-center justify-center p-6 border-l border-border h-screen">
src="/background.png" <section className="w-full max-w-sm space-y-7">
alt="" <header className="space-y-2 text-center md:text-left">
fill
priority
className="object-cover"
sizes="55vw"
/>
<div className="absolute inset-0 bg-background/35" />
<div className="absolute inset-x-0 bottom-0 p-10">
<div className="max-w-lg space-y-3">
<p className="text-sm font-medium uppercase tracking-[0.18em] text-primary">
VisionRoad
</p>
<h1 className="text-4xl font-semibold tracking-normal text-foreground">
Road intelligence for faster inspection decisions
</h1>
<p className="text-sm leading-6 text-muted-foreground">
Review projects, uploads, detections, and chainage insights from one secure
workspace.
</p>
</div>
</div>
</section>
<section className="flex min-h-screen items-center justify-center px-6 py-10">
<div className="w-full max-w-sm space-y-7">
<header className="space-y-2">
<p className="text-sm font-medium text-muted-foreground">VisionRoad</p> <p className="text-sm font-medium text-muted-foreground">VisionRoad</p>
<h2 className="text-2xl font-semibold tracking-normal">Sign in</h2> <h1 className="text-2xl font-semibold tracking-tight">Sign in</h1>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Use your email and password to continue. Use your email and password to continue.
</p> </p>
@@ -98,9 +72,9 @@ export default function LoginPage() {
)} )}
</Button> </Button>
</form> </form>
</div>
</section> </section>
</main> </div>
</div>
</GuestGuard> </GuestGuard>
); );
} }

View File

@@ -4,7 +4,6 @@ import { useCallback, useMemo, useState } from 'react';
import { Building2, Plus } from 'lucide-react'; import { Building2, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions'; import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards'; import { PermissionGuard } from '@/guards';
@@ -120,8 +119,6 @@ export default function ClientsPage() {
onLimitChange={setLimit} onLimitChange={setLimit}
onSortingChange={setSorting} onSortingChange={setSorting}
/> />
<PoweredBy />
</main> </main>
<ClientSheet <ClientSheet

View File

@@ -33,7 +33,6 @@ import { Project } from '@/types';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { DashboardSkeleton } from '@/components/dashboard/dashboard-skeleton'; import { DashboardSkeleton } from '@/components/dashboard/dashboard-skeleton';
import { PoweredBy } from '@/components/powered-by';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { Reveal, StaggerContainer, StaggerItem } from '@/components/ui/reveal'; import { Reveal, StaggerContainer, StaggerItem } from '@/components/ui/reveal';
@@ -636,8 +635,6 @@ export default function DashboardPage() {
</Reveal> </Reveal>
</> </>
)} )}
<PoweredBy />
</div> </div>
</main> </main>
</> </>

View File

@@ -13,13 +13,12 @@ const ModulesLayout = ({
}>) => { }>) => {
return ( return (
<AuthGuard> <AuthGuard>
<SidebarProvider className="bg-transparent overflow-hidden"> <SidebarProvider>
<AppSidebar className="bg-transparent" /> <AppSidebar />
<main className="flex flex-1 flex-col w-full h-screen overflow-hidden bg-transparent"> <main className="flex flex-1 flex-col w-full h-screen overflow-hidden">
<div className="flex-1 overflow-auto"> <div className="flex-1 overflow-auto">
{/* Centering container wrapper */}
<div className="max-w-380 mx-auto w-full flex flex-col min-h-full"> <div className="max-w-380 mx-auto w-full flex flex-col min-h-full">
<div className="flex gap-3 items-center sticky top-0 bg-background/30 backdrop-blur-xl z-30 py-3 px-6 border-b border-border/10"> <div className="flex gap-3 items-center sticky top-0 bg-background z-50 py-3 px-6 border-b border-border">
<SidebarTrigger /> <SidebarTrigger />
<ModeToggle /> <ModeToggle />
<Separator orientation="vertical" className="mx-2 h-4" /> <Separator orientation="vertical" className="mx-2 h-4" />

View File

@@ -35,14 +35,14 @@ function StateBadges({ value }: { value: string | null }) {
<PopoverTrigger asChild> <PopoverTrigger asChild>
<button <button
type="button" type="button"
className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-[10px] font-bold text-muted-foreground transition-colors hover:bg-muted" className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-muted-foreground transition-colors hover:bg-muted"
> >
+{remainingStates.length} +{remainingStates.length}
</button> </button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-auto p-2" align="start"> <PopoverContent className="w-auto p-2" align="start">
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<p className="mb-0.5 px-1 text-[10px] font-bold uppercase tracking-wider text-muted-foreground"> <p className="mb-0.5 px-1 text-muted-foreground">
Other States Other States
</p> </p>
{remainingStates.map((state) => ( {remainingStates.map((state) => (
@@ -64,7 +64,7 @@ export function usePackageColumns(projects: Project[]) {
{ {
accessorKey: 'name', accessorKey: 'name',
header: 'Package Name', header: 'Package Name',
cell: ({ row }) => <div className="font-semibold">{row.original.name}</div>, cell: ({ row }) => <div>{row.original.name}</div>,
}, },
{ {
accessorKey: 'project_id', accessorKey: 'project_id',

View File

@@ -70,13 +70,13 @@ export function PackageDialog({
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl" onOpenAutoFocus={(event) => event.preventDefault()}> <DialogContent className="max-w-2xl" onOpenAutoFocus={(event) => event.preventDefault()}>
<DialogHeader className="gap-2"> <DialogHeader className="gap-2">
<DialogTitle className="flex items-center gap-3 text-xl"> <DialogTitle className="flex items-center gap-3">
<div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm"> <div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm">
<PackageIcon className="size-5" /> <PackageIcon className="size-5" />
</div> </div>
{packageId ? 'Edit Package Details' : 'Create New Package'} {packageId ? 'Edit Package Details' : 'Create New Package'}
</DialogTitle> </DialogTitle>
<DialogDescription className="text-sm"> <DialogDescription>
{packageId {packageId
? 'Update the technical specifications for your road infrastructure package.' ? 'Update the technical specifications for your road infrastructure package.'
: 'Select a project and provide the essential data to establish a new package.'} : 'Select a project and provide the essential data to establish a new package.'}
@@ -89,7 +89,7 @@ export function PackageDialog({
<Select value={projectId} onValueChange={onProjectChange}> <Select value={projectId} onValueChange={onProjectChange}>
<SelectTrigger aria-invalid={!!projectErrorMessage}> <SelectTrigger aria-invalid={!!projectErrorMessage}>
{isProjectsLoading ? ( {isProjectsLoading ? (
<span className="flex items-center gap-2 text-sm text-muted-foreground"> <span className="flex items-center gap-2 text-muted-foreground">
<Loader2 className="size-4 animate-spin" /> <Loader2 className="size-4 animate-spin" />
Loading... Loading...
</span> </span>

View File

@@ -4,7 +4,6 @@ import { useCallback, useState } from 'react';
import { Package as PackageIcon, Plus } from 'lucide-react'; import { Package as PackageIcon, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import type { Package } from '@/types'; import type { Package } from '@/types';
@@ -108,8 +107,6 @@ export default function PackagePage() {
onEdit={openEdit} onEdit={openEdit}
onDelete={deletePackage} onDelete={deletePackage}
/> />
<PoweredBy />
</main> </main>
<PackageDialog <PackageDialog

View File

@@ -47,8 +47,8 @@ export function usePlanColumns({
header: 'Plan', header: 'Plan',
cell: ({ row }) => ( cell: ({ row }) => (
<div> <div>
<p className="font-medium">{row.original.name}</p> <p>{row.original.name}</p>
<p className="text-xs text-muted-foreground">{row.original.slug}</p> <p className="text-muted-foreground">{row.original.slug}</p>
</div> </div>
), ),
}, },
@@ -67,7 +67,7 @@ export function usePlanColumns({
header: 'Limits', header: 'Limits',
enableSorting: false, enableSorting: false,
cell: ({ row }) => ( cell: ({ row }) => (
<div className="text-xs text-muted-foreground"> <div className="text-muted-foreground">
<p>{row.original.max_projects} projects</p> <p>{row.original.max_projects} projects</p>
<p>{row.original.max_users} users</p> <p>{row.original.max_users} users</p>
</div> </div>

View File

@@ -93,7 +93,7 @@ export function PlanSheet({
placeholder="Basic plan for small teams" placeholder="Basic plan for small teams"
{...register('description', { required: true })} {...register('description', { required: true })}
required required
className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
/> />
</div> </div>
@@ -180,7 +180,7 @@ export function PlanSheet({
</div> </div>
<div className="flex flex-wrap gap-5"> <div className="flex flex-wrap gap-5">
<label className="flex items-center gap-2 text-sm"> <label className="flex items-center gap-2">
<input <input
type="checkbox" type="checkbox"
className="size-4 rounded border-border accent-primary" className="size-4 rounded border-border accent-primary"
@@ -188,7 +188,7 @@ export function PlanSheet({
/> />
Active Active
</label> </label>
<label className="flex items-center gap-2 text-sm"> <label className="flex items-center gap-2">
<input <input
type="checkbox" type="checkbox"
className="size-4 rounded border-border accent-primary" className="size-4 rounded border-border accent-primary"
@@ -201,10 +201,10 @@ export function PlanSheet({
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between gap-3"> <div className="flex items-center justify-between gap-3">
<Label>Permissions</Label> <Label>Permissions</Label>
<span className="text-xs text-muted-foreground">{permissionIds.length} selected</span> <span className="text-muted-foreground">{permissionIds.length} selected</span>
</div> </div>
{isPermissionsLoading ? ( {isPermissionsLoading ? (
<div className="rounded-md border p-6 text-sm text-muted-foreground"> <div className="rounded-md border p-6 text-muted-foreground">
Loading permissions... Loading permissions...
</div> </div>
) : ( ) : (

View File

@@ -4,7 +4,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { BadgeIndianRupee, Plus } from 'lucide-react'; import { BadgeIndianRupee, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions'; import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards'; import { PermissionGuard } from '@/guards';
@@ -174,8 +173,6 @@ export default function PlansPage() {
onLimitChange={setLimit} onLimitChange={setLimit}
onSortingChange={setSorting} onSortingChange={setSorting}
/> />
<PoweredBy />
</main> </main>
<PlanSheet <PlanSheet

View File

@@ -35,14 +35,14 @@ function StateBadges({ value }: { value: string | null }) {
<PopoverTrigger asChild> <PopoverTrigger asChild>
<button <button
type="button" type="button"
className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-[10px] font-bold text-muted-foreground transition-colors hover:bg-muted" className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-muted-foreground transition-colors hover:bg-muted"
> >
+{remainingStates.length} +{remainingStates.length}
</button> </button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-auto p-2" align="start"> <PopoverContent className="w-auto p-2" align="start">
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<p className="mb-0.5 px-1 text-[10px] font-bold uppercase tracking-wider text-muted-foreground"> <p className="mb-0.5 px-1 text-muted-foreground">
Other States Other States
</p> </p>
{remainingStates.map((state) => ( {remainingStates.map((state) => (
@@ -64,7 +64,7 @@ export function useProjectColumns() {
{ {
accessorKey: 'name', accessorKey: 'name',
header: 'Project Name', header: 'Project Name',
cell: ({ row }) => <div className="font-semibold">{row.original.name}</div>, cell: ({ row }) => <div>{row.original.name}</div>,
}, },
{ {
accessorKey: 'state', accessorKey: 'state',

View File

@@ -51,13 +51,13 @@ export function ProjectDialog({
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl" onOpenAutoFocus={(event) => event.preventDefault()}> <DialogContent className="max-w-2xl" onOpenAutoFocus={(event) => event.preventDefault()}>
<DialogHeader className="gap-2"> <DialogHeader className="gap-2">
<DialogTitle className="flex items-center gap-3 text-xl"> <DialogTitle className="flex items-center gap-3">
<div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm"> <div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm">
<Layers className="size-5" /> <Layers className="size-5" />
</div> </div>
{projectId ? 'Edit Project Details' : 'Create New Project'} {projectId ? 'Edit Project Details' : 'Create New Project'}
</DialogTitle> </DialogTitle>
<DialogDescription className="text-sm"> <DialogDescription>
{projectId {projectId
? 'Update the technical specifications for your road infrastructure project.' ? 'Update the technical specifications for your road infrastructure project.'
: 'Provide the essential road data to establish a new analysis project.'} : 'Provide the essential road data to establish a new analysis project.'}
@@ -97,7 +97,7 @@ export function ProjectDialog({
<div className="grid gap-8 pt-2 md:grid-cols-2"> <div className="grid gap-8 pt-2 md:grid-cols-2">
<div className="space-y-4"> <div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground"> <p className="flex items-center gap-2 text-muted-foreground">
<MapPin className="size-3.5 opacity-60" /> <MapPin className="size-3.5 opacity-60" />
START POINT START POINT
</p> </p>
@@ -108,7 +108,7 @@ export function ProjectDialog({
type="number" type="number"
step="any" step="any"
placeholder="0.0000" placeholder="0.0000"
className="font-mono text-xs" className="font-mono"
aria-invalid={!!startLatErrorMessage} aria-invalid={!!startLatErrorMessage}
{...register('start_lat')} {...register('start_lat')}
/> />
@@ -119,7 +119,7 @@ export function ProjectDialog({
type="number" type="number"
step="any" step="any"
placeholder="0.0000" placeholder="0.0000"
className="font-mono text-xs" className="font-mono"
aria-invalid={!!startLngErrorMessage} aria-invalid={!!startLngErrorMessage}
{...register('start_lng')} {...register('start_lng')}
/> />
@@ -128,7 +128,7 @@ export function ProjectDialog({
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground"> <p className="flex items-center gap-2 text-muted-foreground">
<MapPin className="size-3.5 opacity-60" /> <MapPin className="size-3.5 opacity-60" />
END POINT END POINT
</p> </p>
@@ -139,7 +139,7 @@ export function ProjectDialog({
type="number" type="number"
step="any" step="any"
placeholder="0.0000" placeholder="0.0000"
className="font-mono text-xs" className="font-mono"
aria-invalid={!!endLatErrorMessage} aria-invalid={!!endLatErrorMessage}
{...register('end_lat')} {...register('end_lat')}
/> />
@@ -150,7 +150,7 @@ export function ProjectDialog({
type="number" type="number"
step="any" step="any"
placeholder="0.0000" placeholder="0.0000"
className="font-mono text-xs" className="font-mono"
aria-invalid={!!endLngErrorMessage} aria-invalid={!!endLngErrorMessage}
{...register('end_lng')} {...register('end_lng')}
/> />

View File

@@ -4,7 +4,6 @@ import { useCallback, useState } from 'react';
import { Layers, Plus } from 'lucide-react'; import { Layers, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import type { Project } from '@/types'; import type { Project } from '@/types';
@@ -100,8 +99,6 @@ export default function ProjectPage() {
onEdit={openEdit} onEdit={openEdit}
onDelete={deleteProject} onDelete={deleteProject}
/> />
<PoweredBy />
</main> </main>
<ProjectDialog <ProjectDialog

View File

@@ -6,7 +6,6 @@ import { Button } from '@/components/ui/button';
import { Loader2, TrendingUp, ArrowUp, ArrowDown } from 'lucide-react'; import { Loader2, TrendingUp, ArrowUp, ArrowDown } from 'lucide-react';
import VideoPlayerSection from '@/components/video-player-section'; import VideoPlayerSection from '@/components/video-player-section';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { sessionService, videoService } from '@/services/api'; import { sessionService, videoService } from '@/services/api';
import { SessionContext, DetectionData, DetectionType } from '@/types'; import { SessionContext, DetectionData, DetectionType } from '@/types';
import { getVideoFile, clearVideoFile } from '@/lib/video-storage'; import { getVideoFile, clearVideoFile } from '@/lib/video-storage';
@@ -182,7 +181,6 @@ export default function VideoResultsPage() {
projectId={session?.projectId || undefined} projectId={session?.projectId || undefined}
/> />
)} )}
<PoweredBy />
</div> </div>
</main> </main>
</div> </div>

View File

@@ -6,7 +6,6 @@ import { Button } from '@/components/ui/button';
import { Loader2, TrendingUp } from 'lucide-react'; import { Loader2, TrendingUp } from 'lucide-react';
import VideoPlayerSection from '@/components/video-player-section'; import VideoPlayerSection from '@/components/video-player-section';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { sessionService } from '@/services/api'; import { sessionService } from '@/services/api';
import { SessionContext, DetectionData, DetectionType } from '@/types'; import { SessionContext, DetectionData, DetectionType } from '@/types';
import { clearVideoFile } from '@/lib/video-storage'; import { clearVideoFile } from '@/lib/video-storage';
@@ -147,7 +146,6 @@ export default function ResultsPage() {
projectId={session?.projectId || undefined} projectId={session?.projectId || undefined}
/> />
)} )}
<PoweredBy />
</div> </div>
</main> </main>
</div> </div>

View File

@@ -30,7 +30,7 @@ export function useRoleColumns({
{ {
accessorKey: 'name', accessorKey: 'name',
header: 'Name', header: 'Name',
cell: ({ row }) => <span className="font-medium">{row.original.name}</span>, cell: ({ row }) => <span>{row.original.name}</span>,
}, },
{ {
accessorKey: 'display_name', accessorKey: 'display_name',

View File

@@ -117,11 +117,11 @@ export function RoleSheet({
error={errors.permission_ids?.message} error={errors.permission_ids?.message}
className="space-y-3" className="space-y-3"
labelEnd={ labelEnd={
<span className="text-xs text-muted-foreground">{permissionIds.length} selected</span> <span className="text-muted-foreground">{permissionIds.length} selected</span>
} }
> >
{isPermissionsLoading ? ( {isPermissionsLoading ? (
<div className="rounded-md border p-6 text-sm text-muted-foreground"> <div className="rounded-md border p-6 text-muted-foreground">
Loading permissions... Loading permissions...
</div> </div>
) : ( ) : (

View File

@@ -4,7 +4,6 @@ import { useCallback, useState } from 'react';
import { Plus, ShieldCheck } from 'lucide-react'; import { Plus, ShieldCheck } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions'; import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards'; import { PermissionGuard } from '@/guards';
@@ -136,8 +135,6 @@ export default function RolesPage() {
onLimitChange={setLimit} onLimitChange={setLimit}
onSortingChange={setSorting} onSortingChange={setSorting}
/> />
<PoweredBy />
</main> </main>
<RoleSheet <RoleSheet

View File

@@ -36,14 +36,14 @@ function StateBadges({ value }: { value: string | null }) {
<PopoverTrigger asChild> <PopoverTrigger asChild>
<button <button
type="button" type="button"
className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-[10px] font-bold text-muted-foreground transition-colors hover:bg-muted" className="flex items-center justify-center rounded-full border border-border/40 bg-muted/50 px-1.5 py-0.5 text-muted-foreground transition-colors hover:bg-muted"
> >
+{remainingStates.length} +{remainingStates.length}
</button> </button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-auto p-2" align="start"> <PopoverContent className="w-auto p-2" align="start">
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<p className="mb-0.5 px-1 text-[10px] font-bold uppercase tracking-wider text-muted-foreground"> <p className="mb-0.5 px-1 text-muted-foreground">
Other States Other States
</p> </p>
{remainingStates.map((state) => ( {remainingStates.map((state) => (
@@ -65,7 +65,7 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) {
{ {
accessorKey: 'segment_name', accessorKey: 'segment_name',
header: 'Segment Name', header: 'Segment Name',
cell: ({ row }) => <div className="font-semibold">{row.original.segment_name}</div>, cell: ({ row }) => <div>{row.original.segment_name}</div>,
}, },
{ {
accessorKey: 'package_id', accessorKey: 'package_id',
@@ -101,7 +101,7 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) {
<div className="flex flex-row gap-2"> <div className="flex flex-row gap-2">
<Badge <Badge
variant="outline" variant="outline"
className="flex items-center gap-1.5 border-amber-500/50 font-bold text-amber-500" className="flex items-center gap-1.5 border-amber-500/50 text-amber-500"
> >
<Milestone className="size-3" /> <Milestone className="size-3" />
{segment.chainage_start_km} - {segment.chainage_end_km} {segment.chainage_start_km} - {segment.chainage_end_km}
@@ -124,7 +124,7 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) {
cell: ({ row }) => ( cell: ({ row }) => (
<Badge <Badge
variant="outline" variant="outline"
className="flex items-center gap-1.5 border-blue-500/50 font-bold text-blue-500" className="flex items-center gap-1.5 border-blue-500/50 text-blue-500"
> >
<MapPin className="size-3" /> <MapPin className="size-3" />
{row.original.start_lat.toFixed(4)}, {row.original.start_lng.toFixed(4)} {row.original.start_lat.toFixed(4)}, {row.original.start_lng.toFixed(4)}
@@ -137,7 +137,7 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) {
cell: ({ row }) => ( cell: ({ row }) => (
<Badge <Badge
variant="outline" variant="outline"
className="flex items-center gap-1.5 border-blue-500/50 font-bold text-blue-500" className="flex items-center gap-1.5 border-blue-500/50 text-blue-500"
> >
<MapPin className="size-3" /> <MapPin className="size-3" />
{row.original.end_lat.toFixed(4)}, {row.original.end_lng.toFixed(4)} {row.original.end_lat.toFixed(4)}, {row.original.end_lng.toFixed(4)}

View File

@@ -79,13 +79,13 @@ export function SegmentDialog({
onOpenAutoFocus={(event) => event.preventDefault()} onOpenAutoFocus={(event) => event.preventDefault()}
> >
<DialogHeader className="gap-2"> <DialogHeader className="gap-2">
<DialogTitle className="flex items-center gap-3 text-xl"> <DialogTitle className="flex items-center gap-3">
<div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm"> <div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm">
<Milestone className="size-5" /> <Milestone className="size-5" />
</div> </div>
{segmentId ? 'Edit Segment' : 'Create Segment'} {segmentId ? 'Edit Segment' : 'Create Segment'}
</DialogTitle> </DialogTitle>
<DialogDescription className="text-sm"> <DialogDescription>
{segmentId {segmentId
? 'Update the technical specifications for your road segment.' ? 'Update the technical specifications for your road segment.'
: 'Select a project and package, then provide the segment data.'} : 'Select a project and package, then provide the segment data.'}
@@ -99,7 +99,7 @@ export function SegmentDialog({
<Select value={projectId} onValueChange={onProjectChange}> <Select value={projectId} onValueChange={onProjectChange}>
<SelectTrigger aria-invalid={!!getError('project_id')}> <SelectTrigger aria-invalid={!!getError('project_id')}>
{isProjectsLoading ? ( {isProjectsLoading ? (
<span className="flex items-center gap-2 text-sm text-muted-foreground"> <span className="flex items-center gap-2 text-muted-foreground">
<Loader2 className="size-4 animate-spin" /> <Loader2 className="size-4 animate-spin" />
Loading... Loading...
</span> </span>
@@ -126,7 +126,7 @@ export function SegmentDialog({
> >
<SelectTrigger aria-invalid={!!getError('package_id')}> <SelectTrigger aria-invalid={!!getError('package_id')}>
{isPackagesLoading ? ( {isPackagesLoading ? (
<span className="flex items-center gap-2 text-sm text-muted-foreground"> <span className="flex items-center gap-2 text-muted-foreground">
<Loader2 className="size-4 animate-spin" /> <Loader2 className="size-4 animate-spin" />
Loading... Loading...
</span> </span>
@@ -211,7 +211,7 @@ export function SegmentDialog({
<div className="grid gap-6 md:grid-cols-2"> <div className="grid gap-6 md:grid-cols-2">
<div className="space-y-4"> <div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground"> <p className="flex items-center gap-2 text-muted-foreground">
<MapPin className="size-3.5 opacity-60" /> <MapPin className="size-3.5 opacity-60" />
START COORDINATES START COORDINATES
</p> </p>
@@ -244,7 +244,7 @@ export function SegmentDialog({
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground"> <p className="flex items-center gap-2 text-muted-foreground">
<MapPin className="size-3.5 opacity-60" /> <MapPin className="size-3.5 opacity-60" />
END COORDINATES END COORDINATES
</p> </p>

View File

@@ -4,7 +4,6 @@ import { useCallback, useState } from 'react';
import { Milestone, Plus } from 'lucide-react'; import { Milestone, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import type { Chainage } from '@/types'; import type { Chainage } from '@/types';
@@ -119,8 +118,6 @@ export default function SegmentPage() {
onEdit={openEdit} onEdit={openEdit}
onDelete={deleteSegment} onDelete={deleteSegment}
/> />
<PoweredBy />
</main> </main>
<SegmentDialog <SegmentDialog

View File

@@ -41,8 +41,8 @@ export function useTenantColumns({
header: 'Tenant', header: 'Tenant',
cell: ({ row }) => ( cell: ({ row }) => (
<div> <div>
<p className="font-medium">{row.original.name}</p> <p>{row.original.name}</p>
<p className="text-xs text-muted-foreground">{row.original.slug}</p> <p className="text-muted-foreground">{row.original.slug}</p>
</div> </div>
), ),
}, },

View File

@@ -74,8 +74,8 @@ export function TenantSheet({
</DialogHeader> </DialogHeader>
<form onSubmit={onSubmit} className="flex flex-1 flex-col gap-5 px-4"> <form onSubmit={onSubmit} className="flex flex-1 flex-col gap-5 px-4">
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium">Basic Information</p> <p>Basic Information</p>
<p className="text-xs text-muted-foreground">Tenant identity and subscription binding.</p> <p className="text-muted-foreground">Tenant identity and subscription binding.</p>
</div> </div>
<div className="grid gap-4 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2">
@@ -147,7 +147,7 @@ export function TenantSheet({
id="tenant-description" id="tenant-description"
placeholder="North zone operations" placeholder="North zone operations"
{...register('description')} {...register('description')}
className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
/> />
</div> </div>
</div> </div>
@@ -155,8 +155,8 @@ export function TenantSheet({
{!isEditMode ? ( {!isEditMode ? (
<> <>
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium">Tenant Administrator</p> <p>Tenant Administrator</p>
<p className="text-xs text-muted-foreground"> <p className="text-muted-foreground">
Invitation details for the primary tenant admin account. Invitation details for the primary tenant admin account.
</p> </p>
</div> </div>
@@ -204,10 +204,10 @@ export function TenantSheet({
</div> </div>
</> </>
) : adminEmail ? ( ) : adminEmail ? (
<div className="rounded-md border bg-muted/40 p-4 text-sm text-muted-foreground"> <div className="rounded-md border bg-muted/40 p-4 text-muted-foreground">
Admin invitation details cannot be changed after tenant creation. Admin invitation details cannot be changed after tenant creation.
<p className="mt-1 text-foreground"> <p className="mt-1 text-foreground">
Current admin email: <span className="font-medium">{adminEmail}</span> Current admin email: <span>{adminEmail}</span>
</p> </p>
</div> </div>
) : null} ) : null}

View File

@@ -4,7 +4,6 @@ import { useCallback, useMemo, useState } from 'react';
import { Globe, Plus } from 'lucide-react'; import { Globe, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions'; import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards'; import { PermissionGuard } from '@/guards';
@@ -171,8 +170,6 @@ export default function TenantsPage() {
onLimitChange={setLimit} onLimitChange={setLimit}
onSortingChange={setSorting} onSortingChange={setSorting}
/> />
<PoweredBy />
</main> </main>
<TenantSheet <TenantSheet

View File

@@ -5,7 +5,6 @@ import { useRouter, useParams } from 'next/navigation';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Loader2, TrendingUp, ArrowUp, ArrowDown } from 'lucide-react'; import { Loader2, TrendingUp, ArrowUp, ArrowDown } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { sessionService, videoService } from '@/services/api'; import { sessionService, videoService } from '@/services/api';
import { SessionContext } from '@/types'; import { SessionContext } from '@/types';
import { ROUTES } from '@/utils/routes'; import { ROUTES } from '@/utils/routes';
@@ -241,8 +240,6 @@ export default function VideoProcessingPage() {
)} )}
</div> </div>
</Card> </Card>
<PoweredBy />
</div> </div>
</main> </main>
</div> </div>

View File

@@ -15,7 +15,6 @@ import {
} from '@/components/ui/select'; } from '@/components/ui/select';
import { Loader2, TrendingUp, ChevronRight } from 'lucide-react'; import { Loader2, TrendingUp, ChevronRight } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { sessionService, videoService } from '@/services/api'; import { sessionService, videoService } from '@/services/api';
import { SessionContext } from '@/types'; import { SessionContext } from '@/types';
import { storeVideoFile } from '@/lib/video-storage'; import { storeVideoFile } from '@/lib/video-storage';
@@ -265,12 +264,6 @@ export default function UploadPage() {
</Card> </Card>
</Reveal> </Reveal>
</div> </div>
<div className="mt-12">
<Reveal delay={0.4}>
<PoweredBy />
</Reveal>
</div>
</main> </main>
</div> </div>
); );

View File

@@ -40,7 +40,7 @@ export function useUserColumns({
accessorKey: 'first_name', accessorKey: 'first_name',
header: 'Name', header: 'Name',
cell: ({ row }) => ( cell: ({ row }) => (
<span className="font-medium"> <span>
{[row.original.first_name, row.original.last_name].filter(Boolean).join(' ') || {[row.original.first_name, row.original.last_name].filter(Boolean).join(' ') ||
row.original.username} row.original.username}
</span> </span>

View File

@@ -19,8 +19,8 @@ export function UserStats({ total, activeCount, inactiveCount, pendingCount }: U
<div className="grid gap-3 md:grid-cols-4"> <div className="grid gap-3 md:grid-cols-4">
{stats.map((stat) => ( {stats.map((stat) => (
<div key={stat.label} className="rounded-lg border bg-card p-4"> <div key={stat.label} className="rounded-lg border bg-card p-4">
<p className="text-xs text-muted-foreground">{stat.label}</p> <p className="text-muted-foreground">{stat.label}</p>
<p className="mt-1 text-2xl font-semibold">{stat.value}</p> <p>{stat.value}</p>
</div> </div>
))} ))}
</div> </div>

View File

@@ -4,7 +4,6 @@ import { useCallback, useMemo, useState } from 'react';
import { Plus, Users } from 'lucide-react'; import { Plus, Users } from 'lucide-react';
import { PageHeader } from '@/components/page-header'; import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions'; import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards'; import { PermissionGuard } from '@/guards';
@@ -139,8 +138,6 @@ export default function UsersPage() {
onLimitChange={setLimit} onLimitChange={setLimit}
onSortingChange={setSorting} onSortingChange={setSorting}
/> />
<PoweredBy />
</main> </main>
<UserSheet <UserSheet

View File

@@ -1,5 +1,6 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import 'tw-animate-css'; @import 'tw-animate-css';
@import './typography.css';
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@@ -7,7 +8,7 @@
--radius: 0.65rem; --radius: 0.65rem;
--background: oklch(1 0 0); --background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823); --foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0 / 0.4); --card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823); --card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0); --popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823); --popover-foreground: oklch(0.141 0.005 285.823);
@@ -30,7 +31,7 @@
--chart-5: oklch(0.85 0.08 195); /* Soft Cyan - Subdued */ --chart-5: oklch(0.85 0.08 195); /* Soft Cyan - Subdued */
--chart-6: oklch(0.62 0.22 295); /* Deep Violet - Theme Primary */ --chart-6: oklch(0.62 0.22 295); /* Deep Violet - Theme Primary */
--chart-8: oklch(0.58 0.2 335); /* Cool Magenta - Distant Accent */ --chart-8: oklch(0.58 0.2 335); /* Cool Magenta - Distant Accent */
--sidebar: oklch(0.985 0 0 / 0.6); --sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823); --sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.541 0.281 293.009); --sidebar-primary: oklch(0.541 0.281 293.009);
--sidebar-primary-foreground: oklch(0.969 0.016 293.756); --sidebar-primary-foreground: oklch(0.969 0.016 293.756);
@@ -43,7 +44,7 @@
.dark { .dark {
--background: oklch(0.141 0.005 285.823); --background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0); --foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885 / 0.6); --card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0); --card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885); --popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0); --popover-foreground: oklch(0.985 0 0);
@@ -66,7 +67,7 @@
--chart-5: oklch(0.88 0.1 195); --chart-5: oklch(0.88 0.1 195);
--chart-6: oklch(0.65 0.24 295); --chart-6: oklch(0.65 0.24 295);
--chart-8: oklch(0.62 0.22 335); --chart-8: oklch(0.62 0.22 335);
--sidebar: oklch(0.21 0.006 285.885 / 0.6); --sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0); --sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.606 0.25 292.717); --sidebar-primary: oklch(0.606 0.25 292.717);
--sidebar-primary-foreground: oklch(0.969 0.016 293.756); --sidebar-primary-foreground: oklch(0.969 0.016 293.756);
@@ -126,30 +127,6 @@
} }
body { body {
@apply bg-transparent text-foreground; @apply bg-background text-foreground;
min-height: 100vh;
}
/* Modern Scrollbar Styles */
::-webkit-scrollbar {
width: 8px; /* Slightly wider for better accessibility */
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--muted-foreground);
border-radius: 20px;
border: 2px solid transparent;
background-clip: content-box;
opacity: 0.5; /* More visible default */
}
/* Firefox Support */
* {
/* scrollbar-width: ; */
scrollbar-color: var(--muted-foreground) transparent;
} }
} }

View File

@@ -5,7 +5,6 @@ import { ThemeProvider } from '@/providers/ThemeProvider';
import AppInitializer from '@/providers/AppInitializer'; import AppInitializer from '@/providers/AppInitializer';
import QueryProvider from '@/providers/QueryProvider'; import QueryProvider from '@/providers/QueryProvider';
import { Toaster } from '@/components/ui/sonner'; import { Toaster } from '@/components/ui/sonner';
import { BackgroundGradient } from '@/components/background-gradient';
const geistSans = Geist({ const geistSans = Geist({
variable: '--font-geist-sans', variable: '--font-geist-sans',
@@ -38,10 +37,7 @@ export default function RootLayout({
> >
<QueryProvider> <QueryProvider>
<AppInitializer> <AppInitializer>
<div className="relative min-h-screen isolate">
<BackgroundGradient />
{children} {children}
</div>
<Toaster position="top-center" /> <Toaster position="top-center" />
</AppInitializer> </AppInitializer>
</QueryProvider> </QueryProvider>

56
src/app/typography.css Normal file
View File

@@ -0,0 +1,56 @@
@layer base {
h1,
h2,
h3,
h4,
h5,
h6 {
/* margin: 0.1rem 0 0.1rem; */
font-family: inherit;
font-weight: 600;
line-height: 1.2;
color: var(--foreground);
}
h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child,
h6:first-child {
margin-top: 0;
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.875rem;
}
h3 {
font-size: 1.75rem;
}
h4 {
font-size: 1.5rem;
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin: 0.2rem 0 0.1rem;
/* line-height: 1.5; */
}
p:last-child {
margin-bottom: 0;
}
}

View File

@@ -1,36 +0,0 @@
import React from 'react';
export function BackgroundGradient() {
return (
<div
className="fixed inset-0 -z-10 h-full w-full overflow-hidden pointer-events-none"
aria-hidden="true"
>
{/* Top Gradient */}
<div className="absolute inset-x-0 top-0 transform-gpu overflow-hidden blur-3xl">
<div
className="relative left-[calc(50%-11rem)] aspect-1155/678 w-144.5 -translate-x-1/2 rotate-30 bg-linear-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-288.75"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
{/* Middle/Bottom Gradient for balance */}
<div className="absolute inset-x-0 bottom-0 transform-gpu overflow-hidden blur-3xl">
<div
className="relative left-[calc(50%+11rem)] aspect-1155/678 w-144.5 -translate-x-1/2 rotate-30 bg-linear-to-tr from-[#ff80b5] to-[#9089fc] opacity-20 sm:left-[calc(50%+30rem)] sm:w-288.75"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
</div>
);
}
export function BackgroundGradientBottom() {
return null; // Integrated into the main BackgroundGradient component
}

View File

@@ -23,8 +23,8 @@ const TopHeader = ({
{(title || onAddNew) && ( {(title || onAddNew) && (
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between"> <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div> <div>
{title ? <h2 className="text-base font-semibold">{title}</h2> : null} {title ? <h2>{title}</h2> : null}
<p className="text-sm text-muted-foreground">Total {itemCount ?? 0}</p> <p className="text-muted-foreground">Total {itemCount ?? 0}</p>
</div> </div>
{onAddNew ? ( {onAddNew ? (
<Button onClick={onAddNew}> <Button onClick={onAddNew}>

View File

@@ -7,7 +7,7 @@ import { cn } from '@/lib/utils';
const TableHeader = <TData, _>({ table }: { table: Table<TData> }) => { const TableHeader = <TData, _>({ table }: { table: Table<TData> }) => {
return ( return (
<ShadTableHeader className="sticky top-0 z-10 bg-card/80 backdrop-blur-xl"> <ShadTableHeader className="sticky top-0 z-10 bg-card">
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}> <TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => { {headerGroup.headers.map((header) => {
@@ -25,7 +25,7 @@ const TableHeader = <TData, _>({ table }: { table: Table<TData> }) => {
key={header.id} key={header.id}
onClick={canSort ? header.column.getToggleSortingHandler() : undefined} onClick={canSort ? header.column.getToggleSortingHandler() : undefined}
className={cn( className={cn(
'h-10 bg-card/80 px-2 text-foreground backdrop-blur-xl transition-colors', 'h-10 bg-card px-2 text-foreground transition-colors',
canSort && 'cursor-pointer select-none hover:bg-muted/60', canSort && 'cursor-pointer select-none hover:bg-muted/60',
sortDirection && 'bg-muted/70', sortDirection && 'bg-muted/70',
)} )}

View File

@@ -15,17 +15,10 @@ export function PageHeader({ title, description, icon: Icon, children, actions }
return ( return (
<Reveal direction="down" className="w-full"> <Reveal direction="down" className="w-full">
<div className="flex items-center justify-between w-full"> <div className="flex items-center justify-between w-full">
<div className="flex items-center gap-6">
{/* <div className="p-3.5 rounded-xl bg-primary text-primary-foreground flex items-center justify-center shadow-lg shadow-primary/5 ring-1 ring-white/10">
{Icon && <Icon className="h-7 w-7" />}
{children}
</div> */}
<div className="flex flex-col"> <div className="flex flex-col">
<h1 className="text-3xl font-extrabold tracking-tight ">{title}</h1> <h1>{title}</h1>
<p className="text-muted-foreground mt-1 text-sm font-semibold tracking-wide opacity-80"> <p className="text-muted-foreground opacity-80">{description}</p>
{description}
</p>
</div>
</div> </div>
{actions && <div className="flex items-center gap-4">{actions}</div>} {actions && <div className="flex items-center gap-4">{actions}</div>}
</div> </div>

View File

@@ -1,10 +0,0 @@
import Image from 'next/image';
export function PoweredBy() {
return (
<div className="flex items-center justify-center gap-2 mt-3 transition-opacity duration-300">
<span className="font-medium text-muted-foreground">Powered by</span>
<Image src="/sg.svg" alt="Sentient Geeks" width={130} height={20} />
</div>
);
}

View File

@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<'div'>) {
<div <div
data-slot="card" data-slot="card"
className={cn( className={cn(
'flex flex-col gap-6 rounded-xl border bg-card backdrop-blur-xl py-6 text-card-foreground', 'flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground',
className, className,
)} )}
{...props} {...props}

View File

@@ -130,7 +130,7 @@ function DialogTitle({
return ( return (
<DialogPrimitive.Title <DialogPrimitive.Title
data-slot="dialog-title" data-slot="dialog-title"
className={cn("text-lg leading-none font-semibold", className)} className={cn(className)}
{...props} {...props}
/> />
) )
@@ -143,7 +143,7 @@ function DialogDescription({
return ( return (
<DialogPrimitive.Description <DialogPrimitive.Description
data-slot="dialog-description" data-slot="dialog-description"
className={cn("text-sm text-muted-foreground", className)} className={cn("text-muted-foreground", className)}
{...props} {...props}
/> />
) )

View File

@@ -112,7 +112,7 @@ function SheetTitle({
return ( return (
<SheetPrimitive.Title <SheetPrimitive.Title
data-slot="sheet-title" data-slot="sheet-title"
className={cn("font-semibold text-foreground", className)} className={cn("text-foreground", className)}
{...props} {...props}
/> />
) )
@@ -125,7 +125,7 @@ function SheetDescription({
return ( return (
<SheetPrimitive.Description <SheetPrimitive.Description
data-slot="sheet-description" data-slot="sheet-description"
className={cn("text-sm text-muted-foreground", className)} className={cn("text-muted-foreground", className)}
{...props} {...props}
/> />
) )

View File

@@ -162,7 +162,7 @@ function Sidebar({
<div <div
data-slot="sidebar" data-slot="sidebar"
className={cn( className={cn(
'bg-sidebar backdrop-blur-xl text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col', 'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
className, className,
)} )}
{...props} {...props}
@@ -179,7 +179,7 @@ function Sidebar({
data-sidebar="sidebar" data-sidebar="sidebar"
data-slot="sidebar" data-slot="sidebar"
data-mobile="true" data-mobile="true"
className="bg-sidebar backdrop-blur-xl text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden" className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
style={ style={
{ {
'--sidebar-width': SIDEBAR_WIDTH_MOBILE, '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
@@ -236,7 +236,7 @@ function Sidebar({
<div <div
data-sidebar="sidebar" data-sidebar="sidebar"
data-slot="sidebar-inner" data-slot="sidebar-inner"
className="bg-sidebar backdrop-blur-xl group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm" className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
> >
{children} {children}
</div> </div>

View File

@@ -1,9 +1,9 @@
'use client'; "use client"
import * as React from 'react'; import * as React from "react"
import * as TooltipPrimitive from '@radix-ui/react-tooltip'; import { Tooltip as TooltipPrimitive } from "radix-ui"
import { cn } from '@/lib/utils'; import { cn } from "@/lib/utils"
function TooltipProvider({ function TooltipProvider({
delayDuration = 0, delayDuration = 0,
@@ -15,19 +15,19 @@ function TooltipProvider({
delayDuration={delayDuration} delayDuration={delayDuration}
{...props} {...props}
/> />
); )
} }
function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) { function Tooltip({
return ( ...props
<TooltipProvider> }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
<TooltipPrimitive.Root data-slot="tooltip" {...props} /> return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
</TooltipProvider>
);
} }
function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) { function TooltipTrigger({
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />; ...props
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
} }
function TooltipContent({ function TooltipContent({
@@ -42,16 +42,16 @@ function TooltipContent({
data-slot="tooltip-content" data-slot="tooltip-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
'bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance', "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
className, className
)} )}
{...props} {...props}
> >
{children} {children}
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" /> <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
</TooltipPrimitive.Content> </TooltipPrimitive.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
); )
} }
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }