Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ npm install @webaseui/core @webaseui/svelte
import { WeBaseButton, WeBaseCard } from '@webaseui/svelte';
</script>

<WeBaseCard>
<h2>WeBaseUI</h2>
<WeBaseButton>Continue</WeBaseButton>
<WeBaseCard title="WeBaseUI">
<p>Components are imported from the package root.</p>
<WeBaseButton label="Continue" />
</WeBaseCard>
```

Expand All @@ -42,6 +42,16 @@ npm run check:consumer

`npm run check` validates the generated package artifacts and public exports. `npm run check:consumer` packs both workspaces and builds an isolated Svelte app from the tarballs, catching errors that workspace links can hide.

## Documentation app

The canonical component catalogue now lives in `apps/docs` and consumes the same public package roots as downstream applications. Run it locally with:

```sh
npm run dev --workspace @webaseui/docs
```

Its production build is part of `npm run check`, so documentation examples cannot drift into code that no longer compiles. The production portfolio remains an independent registry consumer and deployment proof.

For a user-facing change, create a Changeset:

```sh
Expand Down
13 changes: 13 additions & 0 deletions apps/docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="WeBaseUI tokens, Svelte components, and usage guidance." />
<title>WeBaseUI — Svelte component library</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
20 changes: 20 additions & 0 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@webaseui/docs",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite"
},
"dependencies": {
"@webaseui/core": "0.1.0",
"@webaseui/svelte": "0.2.0",
"svelte": "^5.56.8"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^7.2.0",
"typescript": "^6.0.3",
"vite": "^8.1.5"
}
}
180 changes: 180 additions & 0 deletions apps/docs/src/App.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<script lang="ts">
import {
WeBaseAlert,
WeBaseBadge,
WeBaseButton,
WeBaseCard,
WeBaseCheck,
WeBaseDivider,
WeBaseField,
WeBaseIcon,
WeBaseIconButton,
WeBaseLoader,
WeBaseProgress,
WeBaseRadio,
WeBaseSectionHeader,
WeBaseSwitch,
WeBaseTextarea,
WeBaseTooltip
} from '@webaseui/svelte';

const components = [
['Accordion', 'Disclosure'], ['Alert', 'Feedback'], ['Badge', 'Status'],
['Breadcrumbs', 'Navigation'], ['Button', 'Action'], ['Card', 'Surface'],
['Check', 'Selection'], ['Dialog', 'Overlay'], ['Divider', 'Structure'],
['EmptyState', 'Content'], ['Field', 'Form'], ['Icon', 'Foundation'],
['IconButton', 'Action'], ['Loader', 'Feedback'], ['Pagination', 'Navigation'],
['Progress', 'Feedback'], ['Radio', 'Selection'], ['SectionHeader', 'Structure'],
['Select', 'Form'], ['Skeleton', 'Feedback'], ['Slider', 'Form'],
['Switch', 'Selection'], ['Tabs', 'Navigation'], ['Textarea', 'Form'],
['Toast', 'Feedback'], ['Tooltip', 'Overlay']
] as const;

const tokens = [
['Canvas', '--webase-color-canvas'],
['Surface', '--webase-color-surface'],
['Ink', '--webase-color-ink'],
['Muted ink', '--webase-color-ink-muted'],
['Brand', '--webase-color-brand'],
['Brand tint', '--webase-color-brand-tint'],
['Success', '--webase-color-success'],
['Warning', '--webase-color-warning'],
['Error', '--webase-color-error']
] as const;

let dark = $state(false);
let subscribed = $state(true);
let selected = $state('stable');
let title = $state('Field notes');
let notes = $state('Keep the public contract small, visible, and deliberate.');

$effect(() => {
document.documentElement.dataset.theme = dark ? 'dark' : 'light';
});
</script>

<svelte:head>
<meta name="theme-color" content={dark ? '#101722' : '#f5f4ed'} />
</svelte:head>

<header class="site-header">
<a class="brand" href="#top" aria-label="WeBaseUI home">
<span class="seal" aria-hidden="true"><WeBaseIcon name="sparkles" size={18} /></span>
<span><strong>WeBaseUI</strong><small>Svelte component library</small></span>
</a>
<nav aria-label="Documentation">
<a href="#tokens">Tokens</a>
<a href="#components">Components</a>
<a href="#install">Install</a>
<label class="theme-control">
<span>{dark ? 'Dark' : 'Light'}</span>
<WeBaseSwitch label="Toggle dark theme" bind:checked={dark} />
</label>
</nav>
</header>

<main id="top">
<section class="hero">
<p class="kicker">Public proof / 0.2</p>
<h1>Interfaces with<br /><em>a registered mark.</em></h1>
<p class="hero-copy">A compact foundation of namespaced tokens and accessible Svelte 5 components, designed to travel between products without losing its character.</p>
<div class="hero-actions">
<WeBaseButton label="Explore components" variant="ink" icon="arrow-down" onclick={() => document.querySelector('#components')?.scrollIntoView({ behavior: 'smooth' })} />
<a href="https://github.com/WeOpen/WeBaseUI">View source ↗</a>
</div>
<dl class="ledger">
<div><dt>Components</dt><dd>26</dd></div>
<div><dt>Framework</dt><dd>Svelte 5</dd></div>
<div><dt>Tokens</dt><dd>--webase-*</dd></div>
<div><dt>License</dt><dd>MIT</dd></div>
</dl>
</section>

<section id="tokens" class="section">
<WeBaseSectionHeader kicker="01 / Foundation" title="Tokens" note="The core package is plain CSS. Every public variable uses the --webase-* namespace." />
<div class="token-grid">
{#each tokens as [label, token]}
<article>
<span class="swatch" style={`--swatch: var(${token})`}></span>
<strong>{label}</strong>
<code>{token}</code>
</article>
{/each}
</div>
</section>

<section id="components" class="section">
<WeBaseSectionHeader kicker="02 / Instruments" title="Components" note="The catalogue below is imported from the package root, exactly as a consumer imports it." />

<div class="specimen-grid">
<article class="specimen specimen-wide">
<header><span>Actions</span><WeBaseBadge label="Stable" dot /></header>
<div class="canvas action-row">
<WeBaseButton label="Save specimen" variant="ink" icon="check" />
<WeBaseButton label="Open archive" variant="outline" icon="arrow-up-right" />
<WeBaseButton label="Add note" variant="quiet" icon="plus" />
<WeBaseIconButton label="Bookmark" icon="bookmark" bind:pressed={subscribed} />
<WeBaseTooltip label="Details" text="Tooltips remain dismissible with Escape." />
</div>
</article>

<article class="specimen">
<header><span>Content surface</span><WeBaseBadge label="Composable" /></header>
<div class="canvas">
<WeBaseCard eyebrow="Specimen" title="A portable surface">
<p>Children and footer are Svelte 5 snippets supplied by the consumer.</p>
{#snippet footer()}<small>Updated 04 Aug</small>{/snippet}
</WeBaseCard>
</div>
</article>

<article class="specimen">
<header><span>Feedback</span><WeBaseBadge label="Live" variant="experiment" /></header>
<div class="canvas feedback-stack">
<WeBaseAlert title="Package connected" message="The docs app consumes the local public package boundary." tone="success" />
<WeBaseProgress value={72} label="Contract coverage" />
<WeBaseLoader label="Checking" />
</div>
</article>

<article class="specimen specimen-wide">
<header><span>Forms and selection</span><WeBaseBadge label="Keyboard ready" /></header>
<div class="canvas form-grid">
<WeBaseField label="Specimen title" bind:value={title} help="Public labels stay concise." />
<WeBaseTextarea label="Notes" bind:value={notes} />
<div class="choice-stack">
<WeBaseCheck label="Receive release notes" bind:checked={subscribed} />
<WeBaseRadio name="channel" label="Stable channel" value="stable" bind:selected />
<WeBaseRadio name="channel" label="Preview channel" value="preview" bind:selected />
</div>
</div>
</article>
</div>

<WeBaseDivider label="Public exports" />
<div class="component-index">
{#each components as [name, group], index}
<article>
<span>{String(index + 1).padStart(2, '0')}</span>
<strong>WeBase{name}</strong>
<small>{group}</small>
</article>
{/each}
</div>
</section>

<section id="install" class="section install">
<WeBaseSectionHeader kicker="03 / Distribution" title="Install" note="Tokens and framework adapters are versioned independently." />
<div class="install-grid">
<pre><code>npm install @webaseui/core @webaseui/svelte</code></pre>
<pre><code>{`import '@webaseui/core/theme.css';
import { WeBaseButton } from '@webaseui/svelte';`}</code></pre>
</div>
<p>React support remains intentionally deferred until a real consumer defines its runtime and accessibility requirements.</p>
</section>
</main>

<footer>
<span>WeOpen / WeBaseUI</span>
<span>Core 0.1.0 · Svelte 0.2.0</span>
</footer>
76 changes: 76 additions & 0 deletions apps/docs/src/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@import '@webaseui/core/theme.css';

* { box-sizing: border-box; }
html { scroll-behavior: smooth; background: var(--paper); }
body { margin: 0; color: var(--ink); background: var(--paper); font-family: var(--font); }
a { color: inherit; }
button, input, textarea { font: inherit; }

.site-header { position: sticky; top: 0; z-index: 20; display: flex; max-width: 1440px; min-height: 74px; align-items: center; justify-content: space-between; gap: 24px; margin: 0 auto; padding: 12px clamp(20px, 5vw, 72px); border-bottom: 1px solid var(--hairline); background: color-mix(in srgb, var(--paper) 94%, transparent); backdrop-filter: blur(16px); }
.brand { display: inline-flex; align-items: center; gap: 11px; text-decoration: none; }
.brand > span:last-child { display: grid; gap: 2px; }
.brand strong { font-family: var(--sans); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; }
.brand small { color: var(--ink-muted); font-family: var(--mono); font-size: 8px; letter-spacing: .08em; text-transform: uppercase; }
.seal { display: grid; width: 38px; height: 38px; place-items: center; border: 1px solid var(--brand); border-radius: 50%; color: var(--brand); box-shadow: inset 0 0 0 3px var(--paper), inset 0 0 0 4px color-mix(in srgb, var(--brand) 32%, transparent); transform: rotate(-7deg); }
.site-header nav { display: flex; align-items: center; gap: clamp(12px, 2vw, 26px); font-family: var(--sans); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; }
.site-header nav > a { text-decoration: none; }
.site-header nav > a:hover { color: var(--brand); }
.theme-control { display: flex; align-items: center; gap: 8px; color: var(--ink-muted); }
.theme-control .ds-switch-copy { display: none; }

main { max-width: 1180px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 72px); }
.hero { padding: clamp(90px, 14vw, 180px) 0 90px; }
.kicker { margin: 0 0 22px; color: var(--brand); font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; }
h1 { max-width: 900px; margin: 0; font-size: clamp(56px, 9vw, 112px); font-weight: 500; letter-spacing: -.075em; line-height: .82; }
h1 em { color: var(--brand); font-weight: 400; }
.hero-copy { max-width: 610px; margin: 34px 0 0; color: var(--ink-soft); font-size: clamp(17px, 2vw, 21px); line-height: 1.55; }
.hero-actions { display: flex; align-items: center; gap: 22px; margin-top: 34px; }
.hero-actions > a { color: var(--brand); font-family: var(--sans); font-size: 10px; letter-spacing: .09em; text-transform: uppercase; text-underline-offset: 5px; }
.ledger { display: grid; grid-template-columns: repeat(4, 1fr); margin: 76px 0 0; border-block: 1px solid var(--hairline-strong); }
.ledger div { padding: 18px; border-right: 1px solid var(--hairline); }
.ledger div:last-child { border: 0; }
.ledger dt { color: var(--ink-muted); font-family: var(--mono); font-size: 8px; letter-spacing: .12em; text-transform: uppercase; }
.ledger dd { margin: 8px 0 0; color: var(--brand); font-size: 22px; }
.section { scroll-margin-top: 82px; padding: 90px 0; border-top: 1px solid var(--hairline-strong); }

.token-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.token-grid article { display: grid; grid-template-columns: 54px 1fr; gap: 3px 14px; align-items: center; padding: 14px; border: 1px solid var(--hairline); background: var(--surface); }
.swatch { grid-row: 1 / 3; width: 54px; height: 54px; border: 1px solid var(--hairline-strong); background: var(--swatch); }
.token-grid strong { font-family: var(--sans); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; }
code { color: var(--brand); font-family: var(--mono); font-size: 10px; }

.specimen-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.specimen { min-width: 0; border: 1px solid var(--hairline-strong); background: var(--surface); box-shadow: 7px 7px 0 color-mix(in srgb, var(--brand) 9%, transparent); }
.specimen-wide { grid-column: 1 / -1; }
.specimen > header { display: flex; min-height: 54px; align-items: center; justify-content: space-between; gap: 16px; padding: 10px 14px; border-bottom: 1px solid var(--hairline); color: var(--brand); font-family: var(--mono); font-size: 9px; letter-spacing: .1em; text-transform: uppercase; }
.canvas { padding: 24px; }
.action-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.feedback-stack, .choice-stack { display: grid; gap: 16px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
.form-grid .choice-stack { grid-column: 1 / -1; grid-template-columns: repeat(3, 1fr); }
.component-index { display: grid; grid-template-columns: repeat(2, 1fr); border-top: 1px solid var(--hairline-strong); }
.component-index article { display: grid; grid-template-columns: 34px 1fr auto; align-items: center; gap: 12px; min-height: 52px; padding: 0 14px; border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
.component-index article:nth-child(2n) { border-right: 0; }
.component-index span, .component-index small { color: var(--ink-muted); font-family: var(--mono); font-size: 8px; letter-spacing: .08em; text-transform: uppercase; }
.component-index strong { font-family: var(--sans); font-size: 11px; font-weight: 500; letter-spacing: .04em; }

.install-grid { display: grid; grid-template-columns: .8fr 1.2fr; gap: 16px; }
pre { min-width: 0; margin: 0; padding: 22px; overflow: auto; border: 1px solid var(--hairline-strong); background: var(--surface); box-shadow: 6px 6px 0 color-mix(in srgb, var(--brand) 9%, transparent); }
pre code { color: var(--ink); line-height: 1.7; }
.install > p { max-width: 68ch; margin: 30px 0 0; color: var(--ink-muted); line-height: 1.6; }
footer { display: flex; max-width: 1180px; justify-content: space-between; gap: 24px; margin: 0 auto; padding: 30px clamp(20px, 5vw, 72px) 60px; border-top: 1px solid var(--hairline); color: var(--ink-muted); font-family: var(--mono); font-size: 9px; letter-spacing: .09em; text-transform: uppercase; }

@media (max-width: 760px) {
.site-header nav > a, .theme-control > span { display: none; }
.hero { padding-top: 90px; }
.ledger { grid-template-columns: 1fr 1fr; }
.ledger div:nth-child(2) { border-right: 0; }
.ledger div:nth-child(-n + 2) { border-bottom: 1px solid var(--hairline); }
.token-grid, .specimen-grid, .form-grid, .install-grid { grid-template-columns: 1fr; }
.specimen-wide { grid-column: auto; }
.form-grid .choice-stack { grid-column: auto; grid-template-columns: 1fr; }
.component-index { grid-template-columns: 1fr; }
.component-index article, .component-index article:nth-child(2n) { border-right: 0; }
}

@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
5 changes: 5 additions & 0 deletions apps/docs/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { mount } from 'svelte';
import App from './App.svelte';
import './app.css';

mount(App, { target: document.getElementById('app')! });
5 changes: 5 additions & 0 deletions apps/docs/svelte.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

export default {
preprocess: vitePreprocess()
};
13 changes: 13 additions & 0 deletions apps/docs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"target": "ES2022"
},
"include": [
"src/**/*.ts",
"src/**/*.svelte",
"vite.config.ts"
]
}
6 changes: 6 additions & 0 deletions apps/docs/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
plugins: [svelte()]
});
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading