feat: add feature plugin tests and validation for feature flags

This commit is contained in:
2026-06-21 03:14:19 +07:00
parent ecc958c9f0
commit 1ee76faf55
65 changed files with 4992 additions and 415 deletions
@@ -1,5 +1,8 @@
import { defineLayerConfig } from '../../../src/index.ts'
// Northwind — a reseller brand. It inherits the entire shell (header, footer, profile, router,
// Tailwind setup) from `main` and changes only three things: its logo, its theme.css tokens and
// its Landing page. It also drops the billing page entirely.
export default defineLayerConfig({
name: 'brand',
extends: ['../main'],
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vite-layers — brand</title>
<title>Northwind — Cloud Platform</title>
</head>
<body>
<div id="app"></div>
+11 -1
View File
@@ -1 +1,11 @@
BRAND_LOGO_OVERRIDE
<svg xmlns="http://www.w3.org/2000/svg" width="148" height="28" viewBox="0 0 148 28" fill="none" role="img" aria-label="Northwind">
<defs>
<linearGradient id="nw" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#10b981"/>
<stop offset="1" stop-color="#0ea5e9"/>
</linearGradient>
</defs>
<circle cx="14" cy="14" r="12" fill="url(#nw)"/>
<path d="M14 6 L17 17 L14 14.5 L11 17 Z" fill="#fff"/>
<text x="32" y="19.5" font-family="Inter, system-ui, sans-serif" font-size="16" font-weight="700" letter-spacing="-0.4" fill="#0b231b">Northwind</text>
</svg>

Before

Width:  |  Height:  |  Size: 19 B

After

Width:  |  Height:  |  Size: 590 B

@@ -0,0 +1,14 @@
/* Northwind — a reseller brand. Light, emerald→sky, with rounder corners. This file is the only
styling difference from Acme: it shadows main/src/assets/theme.css through the layer resolver. */
:root {
--c-canvas: #f6fbf8;
--c-surface: #ffffff;
--c-ink: #0b231b;
--c-muted: #5b7a6e;
--c-line: #dcebe3;
--c-brand: #10b981;
--c-on-brand: #ffffff;
--c-accent: #0ea5e9;
--c-radius: 1.25rem;
--c-font: "Inter", ui-sans-serif, system-ui, sans-serif;
}
@@ -1,9 +0,0 @@
<script setup lang="ts">
const title = 'BRAND_HEADER_OVERRIDE'
const p2p = __FEATURES__.p2p
</script>
<template>
<header>{{ title }}</header>
<p v-if="p2p">p2p</p>
</template>
@@ -0,0 +1,80 @@
<script setup lang="ts">
// Northwind's landing — overrides main/src/pages/Landing.vue via the layer resolver. Its own copy,
// layout and imagery; the surrounding header/footer/profile stay shared with every other brand.
const points = [
'Bring your own cloud — deploy into your existing accounts.',
'Granular roles and SSO included on every tier.',
'Usage-based pricing that scales down as well as up.',
'Migrate from anywhere with first-party importers.',
]
const regions = ['us-east', 'eu-west', 'ap-south', 'sa-east']
</script>
<template>
<div>
<!-- Split hero -->
<section class="mx-auto grid max-w-6xl items-center gap-12 px-6 pt-16 pb-20 lg:grid-cols-2">
<div>
<span class="inline-flex items-center gap-2 rounded-full border border-line bg-surface px-3 py-1 text-xs font-medium text-muted">
<span class="h-1.5 w-1.5 rounded-full bg-brand" /> Trusted by 2,400+ teams
</span>
<h1 class="mt-6 text-balance text-5xl font-semibold tracking-tight text-ink">
Infrastructure that feels like home
</h1>
<p class="mt-5 max-w-lg text-balance text-lg text-muted">
Northwind runs your apps where your data already lives. No lock-in, no surprises just a calmer way to operate.
</p>
<div class="mt-8 flex items-center gap-3">
<a href="#/profile" class="rounded-full bg-brand px-5 py-2.5 text-sm font-semibold text-on-brand shadow-sm transition hover:opacity-90">
Open dashboard
</a>
<a href="#/" class="rounded-full border border-line bg-surface px-5 py-2.5 text-sm font-semibold text-ink transition hover:bg-ink/4">
Book a demo
</a>
</div>
</div>
<!-- Product preview card -->
<div class="rounded-card border border-line bg-surface p-2 shadow-xl shadow-brand/5">
<div class="rounded-[calc(var(--c-radius)-0.5rem)] bg-linear-to-br from-brand to-accent p-6 text-on-brand">
<p class="text-sm opacity-80">Cluster health</p>
<p class="mt-1 text-3xl font-semibold">All systems nominal</p>
<div class="mt-6 grid grid-cols-4 gap-2">
<div v-for="r in regions" :key="r" class="rounded-xl bg-on-brand/15 px-2 py-3 text-center backdrop-blur">
<p class="text-[11px] uppercase tracking-wide opacity-80">{{ r }}</p>
<p class="mt-1 text-sm font-semibold">99.9%</p>
</div>
</div>
</div>
<div class="flex items-center justify-between px-4 py-3">
<p class="text-sm text-muted">Last deploy</p>
<p class="text-sm font-medium text-ink">2 minutes ago</p>
</div>
</div>
</section>
<!-- Value checklist -->
<section class="border-y border-line bg-surface">
<div class="mx-auto max-w-6xl px-6 py-16">
<h2 class="max-w-xl text-balance text-3xl font-semibold tracking-tight text-ink">Built for teams that own their stack</h2>
<ul class="mt-8 grid gap-4 sm:grid-cols-2">
<li v-for="p in points" :key="p" class="flex items-start gap-3 rounded-card border border-line bg-canvas p-4">
<span class="mt-0.5 grid h-6 w-6 shrink-0 place-items-center rounded-full bg-brand/10 text-brand">
<svg viewBox="0 0 24 24" class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13l4 4L19 7" /></svg>
</span>
<span class="text-sm text-ink">{{ p }}</span>
</li>
</ul>
</div>
</section>
<!-- CTA -->
<section class="mx-auto max-w-6xl px-6 py-20 text-center">
<h2 class="text-balance text-3xl font-semibold tracking-tight text-ink">Move in this week</h2>
<p class="mx-auto mt-3 max-w-md text-balance text-muted">Import your first workload and we'll match your current bill for 90 days.</p>
<a href="#/profile" class="mt-7 inline-block rounded-full bg-brand px-6 py-2.5 text-sm font-semibold text-on-brand shadow-sm transition hover:opacity-90">
Get started free
</a>
</section>
</div>
</template>