unfied style

This commit is contained in:
root
2026-05-23 04:35:47 -04:00
parent fd10d0db6a
commit 07fba16ff2
57 changed files with 565 additions and 263 deletions
@@ -17,7 +17,7 @@ export default function HomeContent() {
const [content, setContent] = useState<MarketplaceHomepageConfig>(cloneMarketplaceHomepageContent())
const dict = content[language]
const sections = resolveMarketplaceHomepageSections(dict.sections)
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard')
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard')
const starterSignupHref = `${dashboardUrl}/sign-up?plan=STARTER&billing=MONTHLY&currency=MAD`
useEffect(() => {
@@ -46,9 +46,9 @@ export default function HomeContent() {
}
return (
<main className="min-h-screen overflow-hidden bg-[linear-gradient(180deg,#f8f5ef_0%,#f4efe6_28%,#fffdf8_58%,#ffffff_100%)] dark:bg-[linear-gradient(180deg,#14110f_0%,#17120d_35%,#0c0a09_100%)]">
<main className="min-h-screen overflow-hidden bg-transparent">
<section className="relative">
<div className="absolute inset-x-0 top-0 h-[38rem] bg-[radial-gradient(circle_at_top_left,rgba(217,119,6,0.24),transparent_34%),radial-gradient(circle_at_top_right,rgba(15,118,110,0.18),transparent_26%)] dark:bg-[radial-gradient(circle_at_top_left,rgba(251,191,36,0.16),transparent_34%),radial-gradient(circle_at_top_right,rgba(45,212,191,0.14),transparent_26%)]" />
<div className="site-glow absolute inset-x-0 top-0 h-[38rem]" />
<div className="shell relative py-10 sm:py-14 lg:py-20">
<div className={`grid gap-8 ${hasSection('hero') && hasSection('surface') ? 'lg:grid-cols-[minmax(0,1.15fr)_24rem] lg:items-stretch xl:grid-cols-[minmax(0,1.2fr)_28rem]' : ''}`}>
{hasSection('hero') ? (
@@ -82,8 +82,8 @@ export default async function CompanyProfilePage({ params }: { params: { slug: s
if (!company) {
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950 py-10">
<div className="shell">
<main className="site-page">
<div className="site-section">
<section className="card p-8">
<p className="text-sm uppercase tracking-[0.18em] text-amber-700 dark:text-amber-400">{dict.unavailable}</p>
<h1 className="mt-3 text-3xl font-black text-stone-900 dark:text-stone-100">{dict.unavailableTitle}</h1>
@@ -98,8 +98,8 @@ export default async function CompanyProfilePage({ params }: { params: { slug: s
}
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950 py-10">
<div className="shell space-y-8">
<main className="site-page">
<div className="site-section space-y-8">
<section className="card p-8">
<p className="text-sm uppercase tracking-[0.18em] text-amber-700 dark:text-amber-400">{company.brand?.publicCity ?? dict.partner}</p>
<h1 className="mt-3 text-4xl font-black text-stone-900 dark:text-stone-100">{company.brand?.displayName ?? company.name}</h1>
@@ -107,8 +107,8 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
if (!vehicle) {
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950 py-10">
<div className="shell">
<main className="site-page">
<div className="site-section">
<section className="card p-8">
<p className="text-sm uppercase tracking-[0.18em] text-amber-700 dark:text-amber-400">{dict.unavailable}</p>
<h1 className="mt-3 text-3xl font-black text-stone-900 dark:text-stone-100">{dict.unavailableTitle}</h1>
@@ -130,8 +130,8 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
const [heroPhoto, ...galleryPhotos] = vehicle.photos
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950 py-10">
<div className="shell space-y-8">
<main className="site-page">
<div className="site-section space-y-8">
{/* Breadcrumb */}
<nav className="flex items-center gap-2 text-sm text-stone-500 dark:text-stone-400">
@@ -237,10 +237,10 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
).sort((left, right) => left.localeCompare(right))
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950 py-10">
<div className="shell space-y-10">
<section className="rounded-[2rem] bg-[linear-gradient(135deg,#1c1917,#57534e)] dark:bg-[linear-gradient(135deg,#0c0a09,#292524)] px-8 py-12 text-white">
<p className="text-sm uppercase tracking-[0.2em] text-amber-300">{dict.kicker}</p>
<main className="site-page">
<div className="site-section space-y-10">
<section className="site-panel-contrast bg-[linear-gradient(135deg,#1c1917,#57534e)] dark:bg-[linear-gradient(135deg,#0c0a09,#292524)] px-8 py-12">
<p className="site-kicker text-amber-300 dark:text-amber-300">{dict.kicker}</p>
<h1 className="mt-4 text-4xl font-black tracking-tight">{dict.title}</h1>
<p className="mt-4 max-w-2xl text-stone-300">{dict.body}</p>
<ExploreSearchForm
@@ -6,7 +6,7 @@ const copy = {
en: {
kicker: 'Features',
title: 'Operations, marketplace discovery, and branded booking.',
body: 'RentalDriveGo combines company-only operations with a public marketplace that sends renters to each company's own payment flow.',
body: "RentalDriveGo combines company-only operations with a public marketplace that sends renters to each company's own payment flow.",
cards: [
['Private dashboard', 'Fleet, reservations, CRM, team permissions, billing, and reports stay isolated per company.'],
['Marketplace discovery', 'Published vehicles and public offers appear on `/explore` for cross-company browsing.'],
@@ -49,12 +49,12 @@ export default function FeaturesPage() {
const dict = copy[language]
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950">
<div className="shell space-y-12 py-16">
<main className="site-page">
<div className="site-section space-y-12">
<div className="max-w-3xl">
<p className="text-sm font-semibold uppercase tracking-[0.24em] text-amber-700 dark:text-amber-400">{dict.kicker}</p>
<h1 className="mt-4 text-5xl font-black tracking-tight text-stone-900 dark:text-stone-100">{dict.title}</h1>
<p className="mt-5 text-lg leading-8 text-stone-600 dark:text-stone-400">{dict.body}</p>
<p className="site-kicker">{dict.kicker}</p>
<h1 className="site-title">{dict.title}</h1>
<p className="site-lead">{dict.body}</p>
</div>
<div className="grid gap-6 md:grid-cols-2 xl:grid-cols-3">
+2 -2
View File
@@ -7,13 +7,13 @@ import { resolveBrowserAppUrl } from '@/lib/appUrls'
export default function PublicLayout({ children }: { children: React.ReactNode }) {
const { language, theme, dict, companyName, setLanguage, setTheme } = useMarketplacePreferences()
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard')
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard')
const footerContent = getFooterContent(language)
const available = localeOptions.filter((o) => o.value !== language)
const current = localeOptions.find((o) => o.value === language) ?? localeOptions[0]
return (
<div className="flex min-h-screen flex-col bg-stone-50 text-stone-900 transition-colors dark:bg-stone-950 dark:text-stone-100">
<div className="site-page flex min-h-screen flex-col">
<MarketplaceHeader
dict={dict}
theme={theme}
@@ -125,7 +125,7 @@ export default function PricingClient() {
const dict = copy[language]
const [currency, setCurrency] = useState<Currency>('MAD')
const [billing, setBilling] = useState<Billing>('monthly')
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard')
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard')
const savings = annualSavingsPct('STARTER', currency)
@@ -47,19 +47,19 @@ export default function PricingPageContent() {
const dict = copy[language]
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950">
<div className="shell py-20">
<main className="site-page">
<div className="site-section">
<div className="mx-auto max-w-2xl text-center">
<p className="text-sm font-semibold uppercase tracking-[0.24em] text-amber-700 dark:text-amber-400">{dict.kicker}</p>
<h1 className="mt-4 text-5xl font-black tracking-tight text-stone-900 dark:text-stone-100">{dict.title}</h1>
<p className="mt-5 text-lg leading-8 text-stone-600 dark:text-stone-400">{dict.body}</p>
<p className="site-kicker">{dict.kicker}</p>
<h1 className="site-title">{dict.title}</h1>
<p className="site-lead">{dict.body}</p>
</div>
<div className="mt-16">
<PricingClient />
</div>
<div className="mx-auto mt-24 max-w-3xl divide-y divide-stone-200 dark:divide-stone-800">
<div className="site-panel mx-auto mt-24 max-w-3xl divide-y divide-stone-200/80 dark:divide-stone-800">
<h2 className="pb-8 text-2xl font-bold text-stone-900 dark:text-stone-100">{dict.faq}</h2>
{dict.items.map(([q, a]) => (
<div key={q} className="py-6">
@@ -101,7 +101,7 @@ function ReviewPageContent() {
if (loadState === 'loading') {
return (
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<p className="text-sm text-stone-500 dark:text-stone-400">Loading</p>
</main>
)
@@ -109,7 +109,7 @@ function ReviewPageContent() {
if (loadState === 'invalid') {
return (
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<div className="card w-full max-w-md space-y-3 p-8 text-center">
<p className="text-2xl font-black text-stone-900 dark:text-stone-100">Link not found</p>
<p className="text-sm text-stone-500 dark:text-stone-400">This review link is invalid or has already been used.</p>
@@ -120,7 +120,7 @@ function ReviewPageContent() {
if (loadState === 'already_reviewed') {
return (
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<div className="card w-full max-w-md space-y-3 p-8 text-center">
<div className="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-950/50">
<svg className="h-7 w-7 text-emerald-600 dark:text-emerald-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /></svg>
@@ -134,7 +134,7 @@ function ReviewPageContent() {
if (submitState === 'done') {
return (
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<div className="card w-full max-w-md space-y-4 p-8 text-center">
<div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-950/50">
<svg className="h-8 w-8 text-emerald-600 dark:text-emerald-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /></svg>
@@ -147,7 +147,7 @@ function ReviewPageContent() {
}
return (
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<div className="card w-full max-w-lg overflow-hidden">
{/* Header */}
<div className="flex items-center gap-4 border-b border-stone-200 dark:border-stone-800 p-6">
@@ -201,7 +201,7 @@ export default function ReviewPage() {
return (
<Suspense
fallback={
<main className="flex min-h-screen items-center justify-center bg-stone-50 dark:bg-stone-950 p-6">
<main className="site-page flex min-h-screen items-center justify-center p-6">
<p className="text-sm text-stone-500 dark:text-stone-400">Loading</p>
</main>
}
+88 -1
View File
@@ -11,6 +11,93 @@ body {
}
.card {
@apply rounded-2xl border border-stone-200 bg-white shadow-sm transition-colors dark:border-stone-800 dark:bg-stone-900;
@apply rounded-[2rem] border p-0 shadow-[0_30px_80px_rgba(28,25,23,0.08)] backdrop-blur transition-colors dark:shadow-[0_30px_80px_rgba(0,0,0,0.26)];
border-color: rgb(231 229 228 / 0.8);
background-color: rgb(255 255 255 / 0.82);
}
html.dark .card {
border-color: rgb(41 37 36 / 0.96);
background-color: rgb(28 25 23 / 0.72);
}
.site-page {
@apply min-h-screen overflow-hidden text-stone-900;
background-image:
linear-gradient(180deg, #f8f5ef 0%, #f4efe6 28%, #fffdf8 58%, #ffffff 100%);
}
html.dark .site-page {
@apply text-stone-100;
background-image:
linear-gradient(180deg, #14110f 0%, #17120d 35%, #0c0a09 100%);
}
.site-glow {
background-image:
radial-gradient(circle at top left, rgba(217, 119, 6, 0.24), transparent 34%),
radial-gradient(circle at top right, rgba(15, 118, 110, 0.18), transparent 26%);
}
html.dark .site-glow {
background-image:
radial-gradient(circle at top left, rgba(251, 191, 36, 0.16), transparent 34%),
radial-gradient(circle at top right, rgba(45, 212, 191, 0.14), transparent 26%);
}
.site-section {
@apply shell py-10 sm:py-14 lg:py-16;
}
.site-panel {
@apply rounded-[2rem] border p-7 shadow-[0_30px_80px_rgba(28,25,23,0.08)] backdrop-blur transition-colors sm:p-8;
border-color: rgb(231 229 228 / 0.8);
background-color: rgb(255 255 255 / 0.82);
}
html.dark .site-panel {
border-color: rgb(41 37 36 / 0.96);
background-color: rgb(28 25 23 / 0.72);
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.26);
}
.site-panel-muted {
@apply rounded-[2rem] border p-7 transition-colors sm:p-8;
border-color: rgb(231 229 228 / 0.8);
background-image: linear-gradient(160deg, #fffdf8 0%, #f1ebe1 100%);
}
html.dark .site-panel-muted {
border-color: rgb(41 37 36 / 0.96);
background-image: linear-gradient(160deg, #17120d 0%, #221a14 100%);
}
.site-panel-contrast {
@apply rounded-[2rem] border p-7 text-white shadow-[0_30px_80px_rgba(28,25,23,0.18)] transition-colors sm:p-8;
border-color: rgb(231 229 228 / 0.8);
background-color: rgb(12 10 9);
}
html.dark .site-panel-contrast {
border-color: rgb(68 64 60);
}
.site-kicker {
@apply text-xs font-bold uppercase tracking-[0.28em] text-amber-700 dark:text-amber-300;
}
.site-title {
@apply mt-4 text-4xl font-black tracking-[-0.04em] text-stone-950 dark:text-stone-50 sm:text-5xl;
}
.site-lead {
@apply mt-5 text-base leading-8 text-stone-600 dark:text-stone-300 sm:text-lg;
}
.site-link-primary {
@apply rounded-full bg-stone-950 px-6 py-3 text-sm font-semibold text-white transition hover:bg-stone-800 dark:bg-amber-400 dark:text-stone-950 dark:hover:bg-amber-300;
}
.site-link-secondary {
@apply rounded-full border border-stone-300 bg-white/85 px-6 py-3 text-sm font-semibold text-stone-700 transition hover:border-stone-950 hover:text-stone-950 dark:border-stone-700 dark:bg-stone-950/30 dark:text-stone-200 dark:hover:border-stone-200 dark:hover:text-white;
}
+2 -1
View File
@@ -21,7 +21,8 @@ export default function RootLayout({ children }: { children: React.ReactNode })
{/* Runs before hydration to prevent flash of wrong theme */}
<script
dangerouslySetInnerHTML={{
__html: `(function(){try{var t=document.cookie.split(';').map(function(c){return c.trim()}).find(function(c){return c.startsWith('rentaldrivego-theme=')});if(t)t=t.split('=')[1];if(!t)t=localStorage.getItem('rentaldrivego-theme');if(t==='dark'){document.documentElement.classList.add('dark');document.documentElement.style.colorScheme='dark';}}catch(e){}})()`,
__html:
"(function(){try{var m=document.cookie.match(/(?:^|; )rentaldrivego-theme=([^;]+)/);var theme=m?decodeURIComponent(m[1]):(localStorage.getItem('rentaldrivego-theme')||localStorage.getItem('marketplace-theme'));if(theme!=='light'&&theme!=='dark'){theme=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.classList.toggle('dark',theme==='dark');document.documentElement.style.colorScheme=theme;document.body&&document.body.setAttribute('data-theme',theme)}catch(e){}})();",
}}
/>
</head>
@@ -5,7 +5,7 @@ import { resolveServerAppUrl } from '@/lib/appUrls'
export default function RenterSignInPage() {
const requestHeaders = headers()
const dashboardUrl = resolveServerAppUrl(
process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard',
process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard',
requestHeaders.get('host'),
requestHeaders.get('x-forwarded-proto'),
)
@@ -5,7 +5,7 @@ import { resolveServerAppUrl } from '@/lib/appUrls'
export default function RenterSignUpPage() {
const requestHeaders = headers()
const dashboardUrl = resolveServerAppUrl(
process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard',
process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard',
requestHeaders.get('host'),
requestHeaders.get('x-forwarded-proto'),
)
@@ -28,14 +28,14 @@ export default function FooterContentPage({ slug }: { slug: FooterPageSlug }) {
const isArabic = language === 'ar'
return (
<main className="min-h-screen bg-stone-50 dark:bg-stone-950">
<div className="mx-auto max-w-4xl px-4 py-16 sm:px-6 lg:px-8">
<section className="overflow-hidden rounded-[2rem] border border-stone-200 dark:border-stone-800 bg-white dark:bg-stone-900 shadow-[0_30px_80px_rgba(12,18,28,0.08)]">
<div className="bg-stone-50 dark:bg-stone-900 px-6 py-10 sm:px-10 sm:py-14 border-b border-stone-100 dark:border-stone-800">
<p className="text-sm font-semibold uppercase tracking-[0.24em] text-amber-700 dark:text-amber-400">
<main className="site-page">
<div className="site-section mx-auto max-w-4xl">
<section className="site-panel overflow-hidden p-0">
<div className="site-panel-muted rounded-none border-0 border-b border-stone-100/80 px-6 py-10 sm:px-10 sm:py-14 dark:border-stone-800">
<p className="site-kicker">
{meta.kicker}
</p>
<h1 className="mt-4 text-4xl font-black tracking-tight text-stone-900 dark:text-stone-100 sm:text-5xl">
<h1 className="site-title">
{content.title}
</h1>
</div>
@@ -47,7 +47,7 @@ export default function FooterContentPage({ slug }: { slug: FooterPageSlug }) {
</p>
))}
<div className="rounded-3xl border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 px-6 py-5">
<div className="rounded-3xl border border-amber-200 bg-amber-50 px-6 py-5 dark:border-amber-800 dark:bg-amber-950/30">
<p className="text-sm font-semibold uppercase tracking-[0.18em] text-amber-800 dark:text-amber-400">
{meta.cta}
</p>
@@ -47,7 +47,7 @@ export default function MarketplaceFooter({
}, [])
return (
<footer className="border-t border-stone-200 bg-white/90 px-4 py-8 text-stone-600 transition-colors dark:border-white/5 dark:bg-[#111111] dark:text-stone-300">
<footer className="border-t border-stone-200/80 bg-white/72 px-4 py-8 text-stone-600 backdrop-blur-xl transition-colors dark:border-stone-800 dark:bg-stone-950/72 dark:text-stone-300">
<div className="shell flex flex-col items-center gap-5 text-center">
<nav className="flex flex-wrap items-center justify-center gap-y-3 text-sm">
{primaryItems.map((item, index) => (
@@ -82,7 +82,7 @@ export default function MarketplaceHeader({
}
return (
<header className="sticky top-0 z-50 border-b border-stone-200 bg-white shadow-[0_10px_30px_rgba(15,23,42,0.08)] transition-colors dark:border-stone-800 dark:bg-stone-950 dark:shadow-[0_10px_30px_rgba(0,0,0,0.32)]">
<header className="sticky top-0 z-50 border-b border-stone-200/80 bg-white/78 backdrop-blur-xl shadow-[0_10px_30px_rgba(15,23,42,0.08)] transition-colors dark:border-stone-800 dark:bg-stone-950/76 dark:shadow-[0_10px_30px_rgba(0,0,0,0.32)]">
<div className="shell flex min-h-14 flex-col gap-1.5 py-1.5 lg:flex-row lg:items-center lg:justify-between lg:gap-3 lg:py-2">
<div className="flex items-center justify-between gap-3">
<Link href="/" className="flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-[0.14em] text-stone-900 dark:text-stone-100 sm:text-sm sm:tracking-[0.2em]">
@@ -174,13 +174,10 @@ export default function MarketplaceHeader({
<button
type="button"
onClick={toggleThemeMenu}
className="inline-flex items-center gap-1.5 rounded-full px-1.5 py-1 transition hover:bg-stone-100 dark:hover:bg-stone-800 sm:gap-2 sm:px-2 sm:py-1.5"
className="inline-flex items-center gap-1.5 rounded-full px-2 py-1 transition hover:bg-stone-100 dark:hover:bg-stone-800 sm:px-2.5 sm:py-1.5"
aria-expanded={themeMenuOpen}
aria-haspopup="menu"
>
<span className="px-1.5 text-[10px] font-semibold uppercase tracking-[0.16em] text-stone-500 dark:text-stone-400 sm:px-2 sm:text-[11px] sm:tracking-[0.2em]">
{dict.theme}
</span>
<span className="rounded-full bg-stone-900 px-3 py-1 text-[11px] font-semibold text-white dark:bg-amber-400 dark:text-stone-950 sm:px-3.5 sm:py-1.5 sm:text-xs">
{currentTheme.label}
</span>
@@ -100,7 +100,7 @@ export default function RenterShell({ children }: { children: React.ReactNode })
const pageTitle = activeNav ? (dict[activeNav.key as keyof typeof dict] as string) : dict.dashboard
return (
<div className="flex min-h-screen bg-stone-50 dark:bg-stone-950">
<div className="site-page flex min-h-screen">
{open && (
<div
className="fixed inset-0 z-30 bg-black/50 lg:hidden"
@@ -201,7 +201,7 @@ export default function RenterShell({ children }: { children: React.ReactNode })
isRtl ? 'lg:mr-64' : 'lg:ml-64',
].join(' ')}
>
<header className="flex h-16 items-center justify-between border-b border-stone-200 bg-white px-6 transition-colors dark:border-stone-800 dark:bg-stone-950">
<header className="flex h-16 items-center justify-between border-b border-stone-200/80 bg-white/80 px-6 backdrop-blur transition-colors dark:border-stone-800 dark:bg-stone-900/70">
<h1 className="text-lg font-semibold text-stone-900 dark:text-stone-100">{pageTitle}</h1>
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-amber-500 text-xs font-semibold text-white">
{userInitials}
@@ -212,7 +212,7 @@ export default function RenterShell({ children }: { children: React.ReactNode })
{children}
</main>
<footer className="border-t border-stone-200 bg-white/90 px-6 py-4 transition-colors dark:border-stone-800 dark:bg-stone-950/90">
<footer className="border-t border-stone-200/80 bg-white/80 px-6 py-4 backdrop-blur transition-colors dark:border-stone-800 dark:bg-stone-900/70">
<p className="text-center text-xs text-stone-400 dark:text-stone-500">
&copy; {new Date().getFullYear()} RentalDriveGo. {dict.rights}
</p>
@@ -9,7 +9,7 @@ type FrameId = 'sign-in'
const frameConfig: Record<FrameId, { label: string; appUrl: string; path: string }> = {
'sign-in': {
label: 'Sign in',
appUrl: process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard',
appUrl: process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard',
path: '/dashboard/sign-in',
},
}
@@ -84,19 +84,26 @@ export default function WorkspaceFrame({ target }: { target: FrameId }) {
}, [config.appUrl, framePath, language, theme])
return (
<main className="bg-stone-950" style={{ minHeight: FRAME_HEIGHT }}>
{src ? (
<iframe
title={config.label}
src={src}
className="w-full border-0 bg-white"
style={{ height: FRAME_HEIGHT }}
/>
) : (
<div className="flex items-center justify-center text-sm text-stone-300" style={{ height: FRAME_HEIGHT }}>
{loadingLabel} {config.label}
</div>
)}
<main className="site-page">
<div className="site-section py-6 sm:py-8 lg:py-10">
<section className="site-panel overflow-hidden p-0">
{src ? (
<iframe
title={config.label}
src={src}
className="w-full border-0 bg-white dark:bg-stone-950"
style={{ height: FRAME_HEIGHT }}
/>
) : (
<div
className="flex items-center justify-center text-sm text-stone-500 dark:text-stone-300"
style={{ height: FRAME_HEIGHT }}
>
{loadingLabel} {config.label}
</div>
)}
</section>
</div>
</main>
)
}
@@ -7,7 +7,7 @@ import { resolveBrowserAppUrl } from '@/lib/appUrls'
export default function WorkspaceTabs() {
const { language, theme } = useMarketplacePreferences()
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001/dashboard')
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard')
const copy = {
en: {