feat: support WRN imports and dynamic public shell

This commit is contained in:
2026-07-21 11:15:06 +05:30
parent 0013c0771d
commit 2ca2d02b22
82 changed files with 959 additions and 174 deletions
+50 -9
View File
@@ -1,4 +1,15 @@
component PublicHeader {
types {
interface PublicHeaderNavigationItem {
label: string
href: string
ariaLabel?: string
target?: string
}
interface PublicHeaderActionItem extends PublicHeaderNavigationItem {
variant?: "primary" | "secondary" | "ghost"
}
}
props {
class: string = ""
homeHref: string = "/"
@@ -22,6 +33,14 @@ component PublicHeader {
solutionsLabel: string = "Solutions"
developersLabel: string = "Developers"
resourcesLabel: string = "Resources"
navigationAriaLabel: string = "Main navigation"
themeToggleLabel: string = "Toggle color theme"
mobileMenuOpenLabel: string = "Open navigation menu"
mobileMenuCloseLabel: string = "Close navigation menu"
navigationItems: PublicHeaderNavigationItem[] = []
actionItems: PublicHeaderActionItem[] = []
showNavigation: boolean = true
showMobileThemeToggle: boolean = true
}
state activeMenu = ""
state mobileMenuOpen = false
@@ -71,10 +90,16 @@ component PublicHeader {
<!-- Desktop navigation -->
<nav
aria-label="Main navigation"
aria-label="{navigationAriaLabel}"
data-show="showNavigation"
class="hidden items-center gap-1 lg:flex"
>
<slot name="navigation">
{#if navigationItems.length > 0}
{#each navigationItems as item}
<a href="{item.href}" aria-label="{item.ariaLabel || item.label}" target="{item.target || '_self'}" 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">{item.label}</a>
{/each}
{:else}
<!-- Product -->
<button
type="button"
@@ -171,12 +196,18 @@ component PublicHeader {
>
{pricingLabel}
</a>
{/if}
</slot>
</nav>
<!-- Desktop actions -->
<div class="hidden items-center gap-2 lg:flex">
<slot name="actions">
{#if actionItems.length > 0}
{#each actionItems as item}
<a href="{item.href}" aria-label="{item.ariaLabel || item.label}" target="{item.target || '_self'}" class="wire-public-header-action wire-public-header-action--{item.variant || 'secondary'}">{item.label}{#if item.variant === 'primary'}<span aria-hidden="true">→</span>{/if}</a>
{/each}
{:else}
<a data-show="showStatus"
href="{statusHref}"
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"
@@ -192,8 +223,8 @@ component PublicHeader {
<button data-show="showThemeToggle"
type="button"
data-wire-theme-toggle
aria-label="Toggle color theme"
title="Toggle color theme"
aria-label="{themeToggleLabel}"
title="{themeToggleLabel}"
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>
@@ -201,7 +232,7 @@ component PublicHeader {
<span class="icon-[lucide--sun] hidden h-4 w-4 dark:block" aria-hidden="true" ></span>
<span class="sr-only">
Toggle color theme
{themeToggleLabel}
</span>
</button>
@@ -220,16 +251,17 @@ component PublicHeader {
<span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span>
</a>
{/if}
</slot>
</div>
<!-- Mobile actions -->
<div class="flex items-center gap-2 lg:hidden">
<button
<button data-show="showThemeToggle && showMobileThemeToggle"
type="button"
data-wire-theme-toggle
aria-label="Toggle color theme"
title="Toggle color theme"
aria-label="{themeToggleLabel}"
title="{themeToggleLabel}"
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>
@@ -240,7 +272,7 @@ component PublicHeader {
<button
type="button"
@click="mobileMenuOpen = !mobileMenuOpen"
aria-label="{mobileMenuOpen ? 'Close navigation menu' : 'Open navigation menu'}"
aria-label="{mobileMenuOpen ? mobileMenuCloseLabel : mobileMenuOpenLabel}"
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"
@@ -258,7 +290,7 @@ component PublicHeader {
</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>
<button type="button" data-show="activeMenu !== ''" @click="activeMenu = ''" aria-label="{mobileMenuCloseLabel}" class="fixed inset-0 z-40 hidden cursor-default bg-transparent lg:block" class:hidden="activeMenu === ''" class:block="activeMenu !== ''" ></button>
<!-- Desktop mega menus -->
<div
@@ -302,7 +334,16 @@ component PublicHeader {
class:hidden="!mobileMenuOpen"
class:block="mobileMenuOpen"
>
{#if navigationItems.length > 0 || actionItems.length > 0}
<nav aria-label="{navigationAriaLabel}" class="border-t border-slate-200 bg-white px-5 py-5 shadow-xl dark:border-white/10 dark:bg-slate-950">
<div class="grid gap-2">
{#each navigationItems as item}<a href="{item.href}" target="{item.target || '_self'}" class="rounded-xl px-4 py-3 text-sm font-semibold text-slate-700 hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-white/5">{item.label}</a>{/each}
{#each actionItems as item}<a href="{item.href}" target="{item.target || '_self'}" class="wire-public-header-action wire-public-header-action--{item.variant || 'secondary'}">{item.label}</a>{/each}
</div>
</nav>
{:else}
<PublicMobileNavigation />
{/if}
</div>
</header>
}