feat: add reusable public chrome and named environments

This commit is contained in:
2026-07-20 00:03:35 +05:30
parent f72aec7c8c
commit 1745d8d676
5 changed files with 136 additions and 58 deletions
+27 -4
View File
@@ -47,6 +47,7 @@ Usage:
Add an app to the current workspace Add an app to the current workspace
wrnexus gateway [--port=3000] Serve every workspace app behind one port, routed by domain wrnexus gateway [--port=3000] Serve every workspace app behind one port, routed by domain
wrnexus production [workspace-dir] Build, migrate, and serve the complete production workspace wrnexus production [workspace-dir] Build, migrate, and serve the complete production workspace
wrnexus <environment> [workspace-dir] Run a configured workspace environment (development/staging/custom)
wrnexus generate <type> <name> Scaffold a page | component | api | schema wrnexus generate <type> <name> Scaffold a page | component | api | schema
wrnexus generate routes | docker | mobile wrnexus generate routes | docker | mobile
Generate routes or scaffold deployment targets Generate routes or scaffold deployment targets
@@ -195,10 +196,32 @@ async function main(): Promise<void> {
case "-h": case "-h":
help(); help();
break; break;
default: default: {
console.error(`Unknown command: ${command}\n`); const { loadWorkspaceConfig, runGateway, runProduction } = await import("./workspace.ts");
help(); const workspaceRoot = rest.find((a) => !a.startsWith("--")) ?? ".";
process.exit(1); try {
const workspace = await loadWorkspaceConfig(resolve(workspaceRoot));
const knownEnvironments = new Set([
"development",
"production",
workspace.defaultEnvironment,
...Object.keys(workspace.environments ?? {}),
]);
if (!knownEnvironments.has(command)) throw new Error("unknown-environment-command");
const environmentArgs = rest.filter((arg) => arg !== workspaceRoot);
environmentArgs.push(`--environment=${command}`);
if (command === "development") {
await runGateway(workspaceRoot, environmentArgs);
} else {
await runProduction(workspaceRoot, environmentArgs);
}
} catch (error) {
if (error instanceof Error && error.message !== "unknown-environment-command") throw error;
console.error(`Unknown command or workspace environment: ${command}\n`);
help();
process.exit(1);
}
}
} }
} }
+7 -1
View File
@@ -412,7 +412,12 @@ export async function runGateway(root: string, args: string[]): Promise<void> {
await startGateway({ await startGateway({
port, port,
hostname, hostname,
mode: environment === "production" ? "production" : "development", mode:
environment === "production" ||
args.includes("--prod") ||
process.env.NODE_ENV === "production"
? "production"
: "development",
environment, environment,
security: resolved.security, security: resolved.security,
apps: resolved.apps.map((app) => ({ apps: resolved.apps.map((app) => ({
@@ -506,6 +511,7 @@ export async function runProduction(root: string, args: string[]): Promise<void>
if (!gatewayArgs.some((arg) => arg.startsWith("--environment="))) { if (!gatewayArgs.some((arg) => arg.startsWith("--environment="))) {
gatewayArgs.push(`--environment=${environment}`); gatewayArgs.push(`--environment=${environment}`);
} }
if (!gatewayArgs.includes("--prod")) gatewayArgs.push("--prod");
if (!gatewayArgs.some((arg) => arg.startsWith("--host="))) gatewayArgs.push("--host=0.0.0.0"); if (!gatewayArgs.some((arg) => arg.startsWith("--host="))) gatewayArgs.push("--host=0.0.0.0");
if (!gatewayArgs.some((arg) => arg.startsWith("--port="))) gatewayArgs.push("--port=3000"); if (!gatewayArgs.some((arg) => arg.startsWith("--port="))) gatewayArgs.push("--port=3000");
await runGateway(workspaceRoot, gatewayArgs); await runGateway(workspaceRoot, gatewayArgs);
+22 -15
View File
@@ -1,12 +1,19 @@
component AnnouncementBar { component AnnouncementBar {
props { props {
class = "" class: string = ""
badge = "New" badge: string = "New"
message = "WrNexus Organizations is now available." message: string = "WrNexus Organizations is now available."
description = "Build secure multi-tenant applications with teams, roles, domains, and enterprise SSO." description: string = "Build secure multi-tenant applications with teams, roles, domains, and enterprise SSO."
href = "/organizations" href: string = "/organizations"
actionLabel = "Explore organizations" actionLabel: string = "Explore organizations"
ariaLabel = "Announcement" ariaLabel: string = "Announcement"
badgeIcon: string = "icon-[lucide--sparkles]"
actionIcon: string = "icon-[lucide--arrow-right]"
dismissLabel: string = "Dismiss announcement"
showBadge: boolean = true
showDescription: boolean = true
showAction: boolean = true
dismissible: boolean = true
} }
state visible = true state visible = true
@@ -33,10 +40,10 @@ component AnnouncementBar {
> >
<div class="flex min-w-0 flex-1 items-center justify-center gap-3"> <div class="flex min-w-0 flex-1 items-center justify-center gap-3">
<!-- Badge --> <!-- Badge -->
<span <span data-show="showBadge"
class="hidden shrink-0 items-center gap-1.5 rounded-full bg-indigo-600 px-2.5 py-1 text-[10px] font-bold uppercase tracking-[0.12em] text-white shadow-sm sm:inline-flex" class="hidden shrink-0 items-center gap-1.5 rounded-full bg-indigo-600 px-2.5 py-1 text-[10px] font-bold uppercase tracking-[0.12em] text-white shadow-sm sm:inline-flex"
> >
<span class="icon-[lucide--sparkles] h-3 w-3" aria-hidden="true" ></span> <span class="{badgeIcon} h-3 w-3" aria-hidden="true" ></span>
{badge} {badge}
</span> </span>
@@ -49,24 +56,24 @@ component AnnouncementBar {
{message} {message}
</span> </span>
<span class="hidden md:inline"> <span data-show="showDescription" class="hidden md:inline">
{description} {description}
</span> </span>
</p> </p>
<!-- CTA --> <!-- CTA -->
<a <a data-show="showAction"
href="{href}" href="{href}"
class="group hidden shrink-0 items-center gap-1.5 text-xs font-bold text-indigo-700 transition hover:text-indigo-900 dark:text-indigo-300 dark:hover:text-indigo-200 sm:inline-flex" class="group hidden shrink-0 items-center gap-1.5 text-xs font-bold text-indigo-700 transition hover:text-indigo-900 dark:text-indigo-300 dark:hover:text-indigo-200 sm:inline-flex"
> >
{actionLabel} {actionLabel}
<span class="icon-[lucide--arrow-right] h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span> <span class="{actionIcon} h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span>
</a> </a>
</div> </div>
<!-- Mobile CTA --> <!-- Mobile CTA -->
<a <a data-show="showAction"
href="{href}" href="{href}"
aria-label="{actionLabel}" aria-label="{actionLabel}"
class="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-indigo-100 text-indigo-700 transition hover:bg-indigo-200 dark:bg-indigo-500/15 dark:text-indigo-300 dark:hover:bg-indigo-500/25 sm:hidden" class="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-indigo-100 text-indigo-700 transition hover:bg-indigo-200 dark:bg-indigo-500/15 dark:text-indigo-300 dark:hover:bg-indigo-500/25 sm:hidden"
@@ -75,10 +82,10 @@ component AnnouncementBar {
</a> </a>
<!-- Close --> <!-- Close -->
<button <button data-show="dismissible"
type="button" type="button"
@click="visible = false" @click="visible = false"
aria-label="Dismiss announcement" aria-label="{dismissLabel}"
class="grid h-8 w-8 shrink-0 place-items-center rounded-lg text-slate-500 transition hover:bg-indigo-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-400 dark:hover:bg-white/10 dark:hover:text-white" class="grid h-8 w-8 shrink-0 place-items-center rounded-lg text-slate-500 transition hover:bg-indigo-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-400 dark:hover:bg-white/10 dark:hover:text-white"
> >
<span class="icon-[lucide--x] h-4 w-4" aria-hidden="true" ></span> <span class="icon-[lucide--x] h-4 w-4" aria-hidden="true" ></span>
+34 -17
View File
@@ -1,6 +1,22 @@
component PublicFooter { component PublicFooter {
props { props {
class: string = "" class: string = ""
homeHref: string = "/"
brandName: string = "WrNexus"
brandTagline: string = "Identity Cloud"
brandAriaLabel: string = "WrNexus home"
newsletterEyebrow: string = "WrNexus updates"
newsletterTitle: string = "Identity insights delivered to your inbox"
newsletterDescription: string = "Get product updates, security guidance, implementation strategies, and practical identity architecture resources."
newsletterAction: string = "/api/newsletter/subscribe"
newsletterButtonLabel: string = "Subscribe"
newsletterPlaceholder: string = "Enter your work email"
newsletterSuccessMessage: string = "Thanks. Please check your inbox to confirm your subscription."
copyrightText: string = "© 2026 WrNexus. All rights reserved."
attributionText: string = "Built by WorkRoot Workspace."
showNewsletter: boolean = true
showSocialLinks: boolean = true
showThemeToggle: boolean = true
} }
state email = "" state email = ""
state newsletterSubmitted = false state newsletterSubmitted = false
@@ -23,7 +39,7 @@ component PublicFooter {
<div class="relative w-full px-5 py-12 sm:px-8 lg:px-10 lg:py-16 xl:px-12"> <div class="relative w-full px-5 py-12 sm:px-8 lg:px-10 lg:py-16 xl:px-12">
<!-- Newsletter and CTA --> <!-- Newsletter and CTA -->
<section <section data-show="showNewsletter"
aria-labelledby="footer-newsletter-title" aria-labelledby="footer-newsletter-title"
class="relative overflow-hidden rounded-3xl border border-indigo-200 bg-linear-to-br from-indigo-50 via-white to-violet-50 p-6 shadow-xl shadow-indigo-950/5 dark:border-indigo-500/20 dark:from-indigo-500/10 dark:via-slate-900 dark:to-violet-500/10 sm:p-8 lg:p-10" class="relative overflow-hidden rounded-3xl border border-indigo-200 bg-linear-to-br from-indigo-50 via-white to-violet-50 p-6 shadow-xl shadow-indigo-950/5 dark:border-indigo-500/20 dark:from-indigo-500/10 dark:via-slate-900 dark:to-violet-500/10 sm:p-8 lg:p-10"
> >
@@ -38,26 +54,25 @@ component PublicFooter {
> >
<span class="icon-[lucide--mail-plus] h-3.5 w-3.5" aria-hidden="true" ></span> <span class="icon-[lucide--mail-plus] h-3.5 w-3.5" aria-hidden="true" ></span>
WrNexus updates {newsletterEyebrow}
</span> </span>
<h2 <h2
id="footer-newsletter-title" id="footer-newsletter-title"
class="mt-5 max-w-2xl text-2xl font-bold tracking-tight text-slate-950 dark:text-white sm:text-3xl" class="mt-5 max-w-2xl text-2xl font-bold tracking-tight text-slate-950 dark:text-white sm:text-3xl"
> >
Identity insights delivered to your inbox {newsletterTitle}
</h2> </h2>
<p class="mt-3 max-w-2xl text-sm leading-6 text-slate-600 dark:text-slate-400 sm:text-base"> <p class="mt-3 max-w-2xl text-sm leading-6 text-slate-600 dark:text-slate-400 sm:text-base">
Get product updates, security guidance, implementation {newsletterDescription}
strategies, and practical identity architecture resources.
</p> </p>
</div> </div>
<div> <div>
<form <form
method="post" method="post"
action="/api/newsletter/subscribe" action="{newsletterAction}"
@submit="newsletterSubmitted = true" @submit="newsletterSubmitted = true"
class="rounded-2xl border border-slate-200 bg-white/80 p-2 shadow-lg shadow-slate-950/5 backdrop-blur-sm dark:border-white/10 dark:bg-white/5" class="rounded-2xl border border-slate-200 bg-white/80 p-2 shadow-lg shadow-slate-950/5 backdrop-blur-sm dark:border-white/10 dark:bg-white/5"
> >
@@ -79,7 +94,7 @@ component PublicFooter {
autocomplete="email" autocomplete="email"
required required
bind:value="email" bind:value="email"
placeholder="Enter your work email" placeholder="{newsletterPlaceholder}"
class="h-12 w-full rounded-xl border border-transparent bg-transparent pl-11 pr-4 text-sm text-slate-950 outline-none transition placeholder:text-slate-400 focus:border-indigo-300 focus:bg-white focus:ring-4 focus:ring-indigo-500/10 dark:text-white dark:focus:border-indigo-500/30 dark:focus:bg-slate-900" class="h-12 w-full rounded-xl border border-transparent bg-transparent pl-11 pr-4 text-sm text-slate-950 outline-none transition placeholder:text-slate-400 focus:border-indigo-300 focus:bg-white focus:ring-4 focus:ring-indigo-500/10 dark:text-white dark:focus:border-indigo-500/30 dark:focus:bg-slate-900"
/> />
</div> </div>
@@ -88,7 +103,7 @@ component PublicFooter {
type="submit" type="submit"
class="group inline-flex h-12 shrink-0 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-5 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-900" class="group inline-flex h-12 shrink-0 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-5 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-900"
> >
Subscribe {newsletterButtonLabel}
<span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-1" aria-hidden="true" ></span> <span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-1" aria-hidden="true" ></span>
</button> </button>
@@ -114,7 +129,7 @@ component PublicFooter {
> >
<span class="icon-[lucide--circle-check] h-4 w-4 shrink-0" aria-hidden="true" ></span> <span class="icon-[lucide--circle-check] h-4 w-4 shrink-0" aria-hidden="true" ></span>
Thanks. Please check your inbox to confirm your subscription. {newsletterSuccessMessage}
</div> </div>
</div> </div>
</div> </div>
@@ -126,8 +141,8 @@ component PublicFooter {
<!-- Brand --> <!-- Brand -->
<div> <div>
<a <a
href="/" href="{homeHref}"
aria-label="WrNexus home" aria-label="{brandAriaLabel}"
class="group inline-flex items-center gap-3 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500" class="group inline-flex items-center gap-3 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500"
> >
<span <span
@@ -138,13 +153,13 @@ component PublicFooter {
<span> <span>
<span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white"> <span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white">
WrNexus {brandName}
</span> </span>
<span <span
class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400" class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400"
> >
Identity Cloud {brandTagline}
</span> </span>
</span> </span>
</a> </a>
@@ -169,7 +184,7 @@ component PublicFooter {
</div> </div>
<!-- Social links --> <!-- Social links -->
<div class="mt-6 flex items-center gap-2"> <div data-show="showSocialLinks" class="mt-6 flex items-center gap-2">
<a <a
href="https://github.com/wrnexus" href="https://github.com/wrnexus"
target="_blank" target="_blank"
@@ -217,6 +232,7 @@ component PublicFooter {
aria-label="Footer navigation" aria-label="Footer navigation"
class="grid grid-cols-2 gap-x-6 gap-y-10 sm:grid-cols-3 xl:grid-cols-5" class="grid grid-cols-2 gap-x-6 gap-y-10 sm:grid-cols-3 xl:grid-cols-5"
> >
<slot name="navigation">
<!-- Product --> <!-- Product -->
<div> <div>
<h3 class="text-sm font-bold text-slate-950 dark:text-white"> <h3 class="text-sm font-bold text-slate-950 dark:text-white">
@@ -531,6 +547,7 @@ component PublicFooter {
</li> </li>
</ul> </ul>
</div> </div>
</slot>
</nav> </nav>
</div> </div>
@@ -542,13 +559,13 @@ component PublicFooter {
class="flex flex-col gap-2 text-xs text-slate-500 dark:text-slate-400 sm:flex-row sm:items-center sm:gap-4" class="flex flex-col gap-2 text-xs text-slate-500 dark:text-slate-400 sm:flex-row sm:items-center sm:gap-4"
> >
<p> <p>
© 2026 WrNexus. All rights reserved. {copyrightText}
</p> </p>
<span class="hidden h-1 w-1 rounded-full bg-slate-300 dark:bg-slate-700 sm:block"></span> <span class="hidden h-1 w-1 rounded-full bg-slate-300 dark:bg-slate-700 sm:block"></span>
<p> <p>
Built by WorkRoot Workspace. {attributionText}
</p> </p>
</div> </div>
@@ -581,7 +598,7 @@ component PublicFooter {
Legal Legal
</a> </a>
<button <button data-show="showThemeToggle"
type="button" type="button"
data-open-cookie-preferences data-open-cookie-preferences
class="footer-bottom-link" class="footer-bottom-link"
+46 -21
View File
@@ -1,6 +1,27 @@
component PublicHeader { component PublicHeader {
props { props {
class: string = "" class: string = ""
homeHref: string = "/"
brandName: string = "WrNexus"
brandTagline: string = "Identity Cloud"
brandAriaLabel: string = "WrNexus home"
brandIcon: string = "icon-[lucide--blocks]"
pricingLabel: string = "Pricing"
pricingHref: string = "/pricing"
statusLabel: string = "All systems operational"
statusHref: string = "/status"
signInLabel: string = "Sign in"
signInHref: string = "/sign-in"
primaryLabel: string = "Start free"
primaryHref: string = "/sign-up"
showStatus: boolean = true
showThemeToggle: boolean = true
showSignIn: boolean = true
showPrimaryAction: boolean = true
productLabel: string = "Product"
solutionsLabel: string = "Solutions"
developersLabel: string = "Developers"
resourcesLabel: string = "Resources"
} }
state activeMenu = "" state activeMenu = ""
state mobileMenuOpen = false state mobileMenuOpen = false
@@ -25,25 +46,25 @@ component PublicHeader {
<!-- Brand --> <!-- Brand -->
<a <a
href="/" href="{homeHref}"
aria-label="WrNexus home" aria-label="{brandAriaLabel}"
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" 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 <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" 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 class="{brandIcon} h-5 w-5" aria-hidden="true" ></span>
</span> </span>
<span class="min-w-0"> <span class="min-w-0">
<span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white"> <span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white">
WrNexus {brandName}
</span> </span>
<span <span
class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400" class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400"
> >
Identity Cloud {brandTagline}
</span> </span>
</span> </span>
</a> </a>
@@ -53,6 +74,7 @@ component PublicHeader {
aria-label="Main navigation" aria-label="Main navigation"
class="hidden items-center gap-1 lg:flex" class="hidden items-center gap-1 lg:flex"
> >
<slot name="navigation">
<!-- Product --> <!-- Product -->
<button <button
type="button" type="button"
@@ -69,7 +91,7 @@ component PublicHeader {
class:dark:text-slate-300="activeMenu !== 'product'" class:dark:text-slate-300="activeMenu !== 'product'"
class:dark:hover:bg-white/5="activeMenu !== 'product'" class:dark:hover:bg-white/5="activeMenu !== 'product'"
> >
Product {productLabel}
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'product'" aria-hidden="true" ></span> <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'product'" aria-hidden="true" ></span>
</button> </button>
@@ -92,7 +114,7 @@ component PublicHeader {
class:dark:hover:bg-white/5="activeMenu !== 'solutions'" class:dark:hover:bg-white/5="activeMenu !== 'solutions'"
class:dark:hover:text-white="activeMenu !== 'solutions'" class:dark:hover:text-white="activeMenu !== 'solutions'"
> >
Solutions {solutionsLabel}
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'solutions'" aria-hidden="true" ></span> <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'solutions'" aria-hidden="true" ></span>
</button> </button>
@@ -115,7 +137,7 @@ component PublicHeader {
class:dark:hover:bg-white/5="activeMenu !== 'developers'" class:dark:hover:bg-white/5="activeMenu !== 'developers'"
class:dark:hover:text-white="activeMenu !== 'developers'" class:dark:hover:text-white="activeMenu !== 'developers'"
> >
Developers {developersLabel}
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'developers'" aria-hidden="true" ></span> <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'developers'" aria-hidden="true" ></span>
</button> </button>
@@ -138,23 +160,25 @@ component PublicHeader {
class:dark:hover:bg-white/5="activeMenu !== 'resources'" class:dark:hover:bg-white/5="activeMenu !== 'resources'"
class:dark:hover:text-white="activeMenu !== 'resources'" class:dark:hover:text-white="activeMenu !== 'resources'"
> >
Resources {resourcesLabel}
<span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'resources'" aria-hidden="true" ></span> <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'resources'" aria-hidden="true" ></span>
</button> </button>
<a <a
href="/pricing" href="{pricingHref}"
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" 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 {pricingLabel}
</a> </a>
</slot>
</nav> </nav>
<!-- Desktop actions --> <!-- Desktop actions -->
<div class="hidden items-center gap-2 lg:flex"> <div class="hidden items-center gap-2 lg:flex">
<a <slot name="actions">
href="/status" <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" 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="relative flex h-2 w-2">
@@ -162,10 +186,10 @@ component PublicHeader {
<span class="relative inline-flex h-2 w-2 rounded-full bg-emerald-500"></span> <span class="relative inline-flex h-2 w-2 rounded-full bg-emerald-500"></span>
</span> </span>
All systems operational {statusLabel}
</a> </a>
<button <button data-show="showThemeToggle"
type="button" type="button"
data-wire-theme-toggle data-wire-theme-toggle
aria-label="Toggle color theme" aria-label="Toggle color theme"
@@ -181,21 +205,22 @@ component PublicHeader {
</span> </span>
</button> </button>
<a <a data-show="showSignIn"
href="/sign-in" href="{signInHref}"
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" 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 {signInLabel}
</a> </a>
<a <a data-show="showPrimaryAction"
href="/sign-up" href="{primaryHref}"
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" 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 {primaryLabel}
<span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span> <span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-0.5" aria-hidden="true" ></span>
</a> </a>
</slot>
</div> </div>
<!-- Mobile actions --> <!-- Mobile actions -->