feat(branding): add RoadMonitor logo and update auth/sidebar branding
This commit is contained in:
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 278 KiB |
@@ -31,7 +31,7 @@ function ForgotPasswordContent() {
|
|||||||
<div className="flex h-screen flex-1 items-center justify-center border-l border-border p-6 md:w-[60%]">
|
<div className="flex h-screen flex-1 items-center justify-center border-l border-border p-6 md:w-[60%]">
|
||||||
<section className="w-full max-w-sm space-y-7">
|
<section className="w-full max-w-sm space-y-7">
|
||||||
<header className="space-y-2 text-center md:text-left">
|
<header className="space-y-2 text-center md:text-left">
|
||||||
<p className="text-muted-foreground">VisionRoad</p>
|
<p className="text-muted-foreground">RoadMonitor</p>
|
||||||
<h1>{displayInfo.title}</h1>
|
<h1>{displayInfo.title}</h1>
|
||||||
<p className="text-muted-foreground">{displayInfo.description}</p>
|
<p className="text-muted-foreground">{displayInfo.description}</p>
|
||||||
</header>
|
</header>
|
||||||
@@ -60,7 +60,11 @@ function ForgotPasswordContent() {
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isLoading || !canSubmit}
|
disabled={isLoading || !canSubmit}
|
||||||
>
|
>
|
||||||
{isLoading ? <Loader2 className="size-4 animate-spin" /> : <Send />}
|
{isLoading ? (
|
||||||
|
<Loader2 className="size-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Send />
|
||||||
|
)}
|
||||||
{displayInfo.buttonLabel}
|
{displayInfo.buttonLabel}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default function LoginPage() {
|
|||||||
<section className="w-full max-w-sm space-y-7">
|
<section className="w-full max-w-sm space-y-7">
|
||||||
<header className="space-y-2 text-center md:text-left">
|
<header className="space-y-2 text-center md:text-left">
|
||||||
<p className="text-sm font-medium text-muted-foreground">
|
<p className="text-sm font-medium text-muted-foreground">
|
||||||
VisionRoad
|
RoadMonitor
|
||||||
</p>
|
</p>
|
||||||
<h1 className="text-2xl font-semibold tracking-tight">Sign in</h1>
|
<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">
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ function ResetPasswordContent() {
|
|||||||
<div className="flex h-screen flex-1 items-center justify-center border-l border-border p-6 md:w-[60%]">
|
<div className="flex h-screen flex-1 items-center justify-center border-l border-border p-6 md:w-[60%]">
|
||||||
<section className="w-full max-w-sm space-y-7">
|
<section className="w-full max-w-sm space-y-7">
|
||||||
<header className="space-y-2 text-center md:text-left">
|
<header className="space-y-2 text-center md:text-left">
|
||||||
<p className="text-muted-foreground">VisionRoad</p>
|
<p className="text-muted-foreground">RoadMonitor</p>
|
||||||
<h1>{displayInfo.title}</h1>
|
<h1>{displayInfo.title}</h1>
|
||||||
<p className="text-muted-foreground">{displayInfo.description}</p>
|
<p className="text-muted-foreground">{displayInfo.description}</p>
|
||||||
</header>
|
</header>
|
||||||
@@ -69,7 +69,9 @@ function ResetPasswordContent() {
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isLoading || !canSubmit}
|
disabled={isLoading || !canSubmit}
|
||||||
>
|
>
|
||||||
{isLoading ? <Loader2 className="size-4 animate-spin" /> : null}
|
{isLoading ? (
|
||||||
|
<Loader2 className="size-4 animate-spin" />
|
||||||
|
) : null}
|
||||||
{displayInfo.buttonLabel}
|
{displayInfo.buttonLabel}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function UploadCardGrid({
|
|||||||
onViewVideo,
|
onViewVideo,
|
||||||
onViewDetails,
|
onViewDetails,
|
||||||
}: UploadCardGridProps) {
|
}: UploadCardGridProps) {
|
||||||
const skeletonItems = Array.from({ length: Math.min(limit, 20) });
|
const skeletonItems = Array.from({ length: 6 });
|
||||||
|
|
||||||
if (!isLoading && uploads.length === 0) {
|
if (!isLoading && uploads.length === 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ const geistMono = Geist_Mono({
|
|||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
default: 'VisionRoad',
|
default: 'RoadMonitor',
|
||||||
template: '%s | VisionRoad',
|
template: '%s | RoadMonitor',
|
||||||
},
|
},
|
||||||
description: 'Road infrastructure monitoring and pothole detection platform',
|
description: 'Road infrastructure monitoring and pothole detection platform',
|
||||||
};
|
};
|
||||||
|
|||||||
57
src/components/LogoWrapper.tsx
Normal file
57
src/components/LogoWrapper.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const sizeClasses = {
|
||||||
|
sm: 'size-8 rounded-md border-2 p-0.5',
|
||||||
|
md: 'size-12 rounded-md border-2 p-1.5',
|
||||||
|
lg: 'size-28 rounded-lg border-[5px] p-3',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const variantClasses = {
|
||||||
|
default: 'border-white bg-primary shadow-md',
|
||||||
|
solid: 'border-white bg-primary',
|
||||||
|
glass: 'border-primary-foreground bg-primary/85 shadow-md',
|
||||||
|
sidebar: 'border-0 bg-primary',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type LogoWrapperProps = {
|
||||||
|
alt?: string;
|
||||||
|
className?: string;
|
||||||
|
imageClassName?: string;
|
||||||
|
priority?: boolean;
|
||||||
|
size?: keyof typeof sizeClasses;
|
||||||
|
variant?: keyof typeof variantClasses;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function LogoWrapper({
|
||||||
|
alt = 'RoadMonitor logo',
|
||||||
|
className,
|
||||||
|
imageClassName,
|
||||||
|
priority = false,
|
||||||
|
size = 'md',
|
||||||
|
variant = 'default',
|
||||||
|
}: LogoWrapperProps) {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'inline-flex shrink-0 items-center justify-center',
|
||||||
|
sizeClasses[size],
|
||||||
|
variantClasses[variant],
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/logo.png"
|
||||||
|
alt={alt}
|
||||||
|
width={112}
|
||||||
|
height={112}
|
||||||
|
className={cn(
|
||||||
|
'size-full object-contain brightness-0 invert',
|
||||||
|
imageClassName,
|
||||||
|
)}
|
||||||
|
priority={priority}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ChevronRight, Package } from 'lucide-react';
|
import { ChevronRight } from 'lucide-react';
|
||||||
|
import { LogoWrapper } from '@/components/LogoWrapper';
|
||||||
import { NavUser } from '@/components/nav-user';
|
import { NavUser } from '@/components/nav-user';
|
||||||
import {
|
import {
|
||||||
filterMenuItems,
|
filterMenuItems,
|
||||||
@@ -49,12 +50,10 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|||||||
<Sidebar collapsible="icon" {...props}>
|
<Sidebar collapsible="icon" {...props}>
|
||||||
<SidebarHeader>
|
<SidebarHeader>
|
||||||
<div className="flex items-center gap-2 py-2">
|
<div className="flex items-center gap-2 py-2">
|
||||||
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-primary text-primary-foreground">
|
<LogoWrapper size="sm" variant="sidebar" />
|
||||||
<Package className="size-4" />
|
|
||||||
</div>
|
|
||||||
<div className="grid flex-1 text-left text-sm leading-tight group-data-[collapsible=icon]:hidden">
|
<div className="grid flex-1 text-left text-sm leading-tight group-data-[collapsible=icon]:hidden">
|
||||||
<span className="truncate font-semibold">Vision Road</span>
|
<span className="truncate font-semibold">RoadMonitor</span>
|
||||||
<span className="truncate text-xs">Analytics Platform</span>
|
<span className="truncate text-xs">Road Intelligence</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
@@ -148,3 +147,4 @@ function SidebarNavItem({
|
|||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { LogoWrapper } from '@/components/LogoWrapper';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const BOKEH_ORBS = [
|
const BOKEH_ORBS = [
|
||||||
@@ -80,6 +81,30 @@ export function AuthBackground({ className }: AuthBackgroundProps) {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<div className="absolute inset-x-10 top-1/2 -translate-y-1/2 text-center text-primary-foreground">
|
||||||
|
<div className="mb-9 inline-flex items-center gap-5 text-left">
|
||||||
|
<LogoWrapper
|
||||||
|
alt=""
|
||||||
|
className="size-28 rounded-2xl border-[5px] p-4"
|
||||||
|
priority
|
||||||
|
variant="glass"
|
||||||
|
/>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span className="block text-5xl font-semibold leading-none tracking-normal">
|
||||||
|
Road
|
||||||
|
</span>
|
||||||
|
<span className="block text-5xl font-semibold leading-none tracking-normal">
|
||||||
|
Monitor
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="mx-auto max-w-md text-base leading-7 text-primary-foreground/82">
|
||||||
|
Map, monitor, and repair road issues with data-driven surface
|
||||||
|
intelligence.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user