feat(ui): expose app theme contract and public components
This commit is contained in:
@@ -1,14 +1,284 @@
|
||||
component PublicHeader {
|
||||
props {
|
||||
class = ""
|
||||
brand = "WRNexusJS"
|
||||
homeHref = "/"
|
||||
signInHref = "/signin"
|
||||
ctaHref = "/start"
|
||||
ctaLabel = "Get started"
|
||||
}
|
||||
state mobileOpen = false
|
||||
view {
|
||||
<header class="sticky top-0 z-40 border-b border-slate-200/80 bg-white/85 backdrop-blur-xl dark:border-slate-800 dark:bg-slate-950/85 {class}"><div class="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8"><a href="{homeHref}" class="text-lg font-black tracking-tight">{brand}</a><nav class="hidden items-center gap-7 md:flex" aria-label="Primary"><slot /></nav><div class="hidden items-center gap-3 md:flex"><a href="{signInHref}" class="text-sm font-semibold">Sign in</a><a href="{ctaHref}" class="inline-flex min-h-10 items-center rounded-xl bg-violet-600 px-4 text-sm font-semibold text-white">{ctaLabel}</a><button data-wire-theme-toggle type="button" aria-label="Toggle theme" class="size-10 rounded-xl hover:bg-slate-100 dark:hover:bg-slate-800">◐</button></div><button type="button" aria-label="Open menu" aria-expanded="{mobileOpen}" @click="mobileOpen = !mobileOpen" class="size-11 rounded-xl md:hidden">☰</button></div><div data-show="mobileOpen" class="border-t border-slate-200 px-4 py-5 md:hidden dark:border-slate-800"><div class="space-y-3"><slot name="mobile" /></div><div class="mt-5 grid grid-cols-2 gap-3"><a href="{signInHref}" class="inline-flex min-h-11 items-center justify-center rounded-xl border border-slate-300 font-semibold">Sign in</a><a href="{ctaHref}" class="inline-flex min-h-11 items-center justify-center rounded-xl bg-violet-600 font-semibold text-white">{ctaLabel}</a></div></div></header>
|
||||
}
|
||||
props {
|
||||
class: string = ""
|
||||
}
|
||||
state activeMenu = ""
|
||||
state mobileMenuOpen = false
|
||||
state headerScrolled = false
|
||||
|
||||
view {
|
||||
<header
|
||||
data-public-header
|
||||
class="relative sticky top-0 z-50 w-full border-b transition-all duration-300 {class}"
|
||||
class:border-transparent="!headerScrolled"
|
||||
class:bg-transparent="!headerScrolled"
|
||||
class:border-slate-200/80="headerScrolled"
|
||||
class:bg-white/90="headerScrolled"
|
||||
class:shadow-sm="headerScrolled"
|
||||
class:backdrop-blur-xl="headerScrolled"
|
||||
class:dark:border-white/10="headerScrolled"
|
||||
class:dark:bg-slate-950/90="headerScrolled"
|
||||
>
|
||||
<div
|
||||
class="relative z-[60] flex h-18 w-full items-center justify-between gap-6 px-5 sm:px-8 lg:px-10 xl:px-12"
|
||||
>
|
||||
|
||||
<!-- Brand -->
|
||||
<a
|
||||
href="/"
|
||||
aria-label="WrNexus home"
|
||||
class="group inline-flex shrink-0 items-center gap-3 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950"
|
||||
>
|
||||
<span
|
||||
class="grid h-10 w-10 place-items-center rounded-xl bg-indigo-600 text-white shadow-lg shadow-indigo-600/20 transition duration-200 group-hover:-translate-y-0.5 group-hover:bg-indigo-500 group-hover:shadow-xl"
|
||||
>
|
||||
<span class="icon-[lucide--blocks] h-5 w-5" aria-hidden="true" ></span>
|
||||
</span>
|
||||
|
||||
<span class="min-w-0">
|
||||
<span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white">
|
||||
WrNexus
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400"
|
||||
>
|
||||
Identity Cloud
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- Desktop navigation -->
|
||||
<nav
|
||||
aria-label="Main navigation"
|
||||
class="hidden items-center gap-1 lg:flex"
|
||||
>
|
||||
<!-- Product -->
|
||||
<button
|
||||
type="button"
|
||||
@click="activeMenu = activeMenu === 'product' ? '' : 'product'"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{activeMenu === 'product'}"
|
||||
class="inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
|
||||
class:bg-indigo-50="activeMenu === 'product'"
|
||||
class:text-indigo-700="activeMenu === 'product'"
|
||||
class:text-slate-700="activeMenu !== 'product'"
|
||||
class:hover:bg-slate-100="activeMenu !== 'product'"
|
||||
class:dark:bg-indigo-500/10="activeMenu === 'product'"
|
||||
class:dark:text-indigo-300="activeMenu === 'product'"
|
||||
class:dark:text-slate-300="activeMenu !== 'product'"
|
||||
class:dark:hover:bg-white/5="activeMenu !== 'product'"
|
||||
>
|
||||
Product
|
||||
|
||||
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'product'" aria-hidden="true" ></span>
|
||||
</button>
|
||||
|
||||
<!-- Solutions -->
|
||||
<button
|
||||
type="button"
|
||||
@click="activeMenu = activeMenu === 'solutions' ? '' : 'solutions'"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{activeMenu === 'solutions'}"
|
||||
class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
|
||||
class:bg-indigo-50="activeMenu === 'solutions'"
|
||||
class:text-indigo-700="activeMenu === 'solutions'"
|
||||
class:text-slate-700="activeMenu !== 'solutions'"
|
||||
class:hover:bg-slate-100="activeMenu !== 'solutions'"
|
||||
class:hover:text-slate-950="activeMenu !== 'solutions'"
|
||||
class:dark:bg-indigo-500/10="activeMenu === 'solutions'"
|
||||
class:dark:text-indigo-300="activeMenu === 'solutions'"
|
||||
class:dark:text-slate-300="activeMenu !== 'solutions'"
|
||||
class:dark:hover:bg-white/5="activeMenu !== 'solutions'"
|
||||
class:dark:hover:text-white="activeMenu !== 'solutions'"
|
||||
>
|
||||
Solutions
|
||||
|
||||
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'solutions'" aria-hidden="true" ></span>
|
||||
</button>
|
||||
|
||||
<!-- Developers -->
|
||||
<button
|
||||
type="button"
|
||||
@click="activeMenu = activeMenu === 'developers' ? '' : 'developers'"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{activeMenu === 'developers'}"
|
||||
class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
|
||||
class:bg-indigo-50="activeMenu === 'developers'"
|
||||
class:text-indigo-700="activeMenu === 'developers'"
|
||||
class:text-slate-700="activeMenu !== 'developers'"
|
||||
class:hover:bg-slate-100="activeMenu !== 'developers'"
|
||||
class:hover:text-slate-950="activeMenu !== 'developers'"
|
||||
class:dark:bg-indigo-500/10="activeMenu === 'developers'"
|
||||
class:dark:text-indigo-300="activeMenu === 'developers'"
|
||||
class:dark:text-slate-300="activeMenu !== 'developers'"
|
||||
class:dark:hover:bg-white/5="activeMenu !== 'developers'"
|
||||
class:dark:hover:text-white="activeMenu !== 'developers'"
|
||||
>
|
||||
Developers
|
||||
|
||||
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'developers'" aria-hidden="true" ></span>
|
||||
</button>
|
||||
|
||||
<!-- Resources -->
|
||||
<button
|
||||
type="button"
|
||||
@click="activeMenu = activeMenu === 'resources' ? '' : 'resources'"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{activeMenu === 'resources'}"
|
||||
class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
|
||||
class:bg-indigo-50="activeMenu === 'resources'"
|
||||
class:text-indigo-700="activeMenu === 'resources'"
|
||||
class:text-slate-700="activeMenu !== 'resources'"
|
||||
class:hover:bg-slate-100="activeMenu !== 'resources'"
|
||||
class:hover:text-slate-950="activeMenu !== 'resources'"
|
||||
class:dark:bg-indigo-500/10="activeMenu === 'resources'"
|
||||
class:dark:text-indigo-300="activeMenu === 'resources'"
|
||||
class:dark:text-slate-300="activeMenu !== 'resources'"
|
||||
class:dark:hover:bg-white/5="activeMenu !== 'resources'"
|
||||
class:dark:hover:text-white="activeMenu !== 'resources'"
|
||||
>
|
||||
Resources
|
||||
|
||||
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'resources'" aria-hidden="true" ></span>
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="/pricing"
|
||||
class="inline-flex h-10 items-center rounded-xl px-3.5 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-300 dark:hover:bg-white/5 dark:hover:text-white"
|
||||
>
|
||||
Pricing
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- Desktop actions -->
|
||||
<div class="hidden items-center gap-2 lg:flex">
|
||||
<a
|
||||
href="/status"
|
||||
class="mr-1 inline-flex items-center gap-2 rounded-xl px-3 py-2 text-xs font-semibold text-slate-500 transition hover:bg-slate-100 hover:text-slate-950 dark:text-slate-400 dark:hover:bg-white/5 dark:hover:text-white"
|
||||
>
|
||||
<span class="relative flex h-2 w-2">
|
||||
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-60"></span>
|
||||
<span class="relative inline-flex h-2 w-2 rounded-full bg-emerald-500"></span>
|
||||
</span>
|
||||
|
||||
All systems operational
|
||||
</a>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
data-wire-theme-toggle
|
||||
aria-label="Toggle color theme"
|
||||
title="Toggle color theme"
|
||||
class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:border-slate-300 hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-300 dark:hover:border-white/20 dark:hover:bg-white/10 dark:hover:text-white"
|
||||
>
|
||||
<span class="icon-[lucide--moon] h-4 w-4 dark:hidden" aria-hidden="true" ></span>
|
||||
|
||||
<span class="icon-[lucide--sun] hidden h-4 w-4 dark:block" aria-hidden="true" ></span>
|
||||
|
||||
<span class="sr-only">
|
||||
Toggle color theme
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="/sign-in"
|
||||
class="inline-flex h-10 items-center justify-center rounded-xl px-4 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-200 dark:hover:bg-white/5 dark:hover:text-white"
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/sign-up"
|
||||
class="group inline-flex h-10 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-4 text-sm font-bold text-white shadow-lg shadow-indigo-600/20 transition hover:-translate-y-0.5 hover:bg-indigo-500 hover:shadow-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950"
|
||||
>
|
||||
Start free
|
||||
|
||||
<span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Mobile actions -->
|
||||
<div class="flex items-center gap-2 lg:hidden">
|
||||
<button
|
||||
type="button"
|
||||
data-wire-theme-toggle
|
||||
aria-label="Toggle color theme"
|
||||
title="Toggle color theme"
|
||||
class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white"
|
||||
>
|
||||
<span class="icon-[lucide--moon] h-4 w-4 dark:hidden" aria-hidden="true" ></span>
|
||||
|
||||
<span class="icon-[lucide--sun] hidden h-4 w-4 dark:block" aria-hidden="true" ></span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="mobileMenuOpen = !mobileMenuOpen"
|
||||
aria-label="{mobileMenuOpen ? 'Close navigation menu' : 'Open navigation menu'}"
|
||||
aria-expanded="{mobileMenuOpen}"
|
||||
aria-controls="public-mobile-navigation"
|
||||
class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-700 shadow-sm transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-200 dark:hover:bg-white/10 dark:hover:text-white"
|
||||
>
|
||||
<span data-show="!mobileMenuOpen" class="icon-[lucide--menu] h-5 w-5" aria-hidden="true" ></span>
|
||||
|
||||
<span data-show="mobileMenuOpen" class="icon-[lucide--x] h-5 w-5" aria-hidden="true" ></span>
|
||||
|
||||
<span class="sr-only">
|
||||
Toggle navigation
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Outside-click backdrop -->
|
||||
<button type="button" data-show="activeMenu !== ''" @click="activeMenu = ''" aria-label="Close navigation menu" class="fixed inset-0 z-40 hidden cursor-default bg-transparent lg:block" class:hidden="activeMenu === ''" class:block="activeMenu !== ''" ></button>
|
||||
|
||||
<!-- Desktop mega menus -->
|
||||
<div
|
||||
class="absolute inset-x-0 top-full z-50 max-lg:hidden"
|
||||
class:hidden="activeMenu === ''"
|
||||
class:block="activeMenu !== ''"
|
||||
>
|
||||
<div
|
||||
class:hidden="activeMenu !== 'product'"
|
||||
class:block="activeMenu === 'product'"
|
||||
>
|
||||
<ProductMegaMenu />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:hidden="activeMenu !== 'solutions'"
|
||||
class:block="activeMenu === 'solutions'"
|
||||
>
|
||||
<SolutionsMegaMenu />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:hidden="activeMenu !== 'developers'"
|
||||
class:block="activeMenu === 'developers'"
|
||||
>
|
||||
<DevelopersMegaMenu />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:hidden="activeMenu !== 'resources'"
|
||||
class:block="activeMenu === 'resources'"
|
||||
>
|
||||
<ResourcesMegaMenu />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile navigation -->
|
||||
<div
|
||||
id="public-mobile-navigation"
|
||||
class="lg:hidden"
|
||||
class:hidden="!mobileMenuOpen"
|
||||
class:block="mobileMenuOpen"
|
||||
>
|
||||
<PublicMobileNavigation />
|
||||
</div>
|
||||
</header>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user