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
36 changes: 12 additions & 24 deletions apps/website/.vitepress/theme/Landing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ onMounted(() => {
<a class="navlink nav-hide" href="#philosophy">Philosophy</a>
<a class="navlink nav-hide" href="#projects" style="margin-right:6px">Projects</a>
<ClientOnly>
<button type="button" class="btv-toggle" :title="isDark ? 'Switch to light' : 'Switch to dark'" :aria-label="isDark ? 'Switch to light theme' : 'Switch to dark theme'" @click="toggleAppearance">
<button type="button" class="btv-toggle" :title="isDark ? 'Switch to light' : 'Switch to dark'" :aria-label="isDark ? 'Switch to light theme' : 'Switch to dark theme'" :aria-pressed="isDark" @click="toggleAppearance">
<svg v-if="isDark" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.5v2M12 19.5v2M4.8 4.8l1.4 1.4M17.8 17.8l1.4 1.4M2.5 12h2M19.5 12h2M4.8 19.2 6.2 17.8M17.8 6.2 19.2 4.8"/></svg>
<svg v-else width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 14.5A8 8 0 1 1 9.5 4 6.4 6.4 0 0 0 20 14.5Z"/></svg>
</button>
Expand Down Expand Up @@ -232,7 +232,6 @@ onMounted(() => {

<style scoped>
.btv {
--btv-glass: rgba(21, 16, 28, 0.66);
--btv-hover: rgba(255, 255, 255, 0.05);
--btv-pill: rgba(255, 255, 255, 0.04);
--btv-footer: rgba(0, 0, 0, 0.2);
Expand All @@ -242,28 +241,17 @@ onMounted(() => {
font-family: var(--sans);
}

/* Light mode (system preference or the header toggle) — scoped to the landing */
/* Light mode (system / toggle): surfaces, text and accent-as-text come from the
shared tokens (tokens.css :root:not(.dark)); only these landing-local
overlays — header/nav washes, pills, footer tint — flip here. */
:global(html:not(.dark)) .btv {
--bg: #fbf7fb;
--bg-grad: #f4e7f0;
--card: #ffffff;
--card-soft: #f6eff4;
--border: rgba(26, 12, 20, 0.1);
--border-2: rgba(26, 12, 20, 0.16);
--text: #241a22;
--muted: #6b5e68;
--faint: #9c8f99;
--accent: #c13c79;
--shadow-card: 0 20px 45px -28px rgba(142, 26, 82, 0.28);
--shadow-toast: 0 18px 40px -18px rgba(142, 26, 82, 0.2);
--btv-glass: rgba(251, 247, 251, 0.72);
--btv-hover: rgba(26, 12, 20, 0.05);
--btv-pill: rgba(26, 12, 20, 0.035);
--btv-footer: rgba(26, 12, 20, 0.025);
}
:global(html:not(.dark)) .btv-glow { opacity: 0.55; }

.btv-pink { color: var(--accent); }
.btv-pink { color: var(--text-accent); }
.btv-toggle {
display: inline-flex; align-items: center; justify-content: center;
width: 38px; height: 38px;
Expand All @@ -277,7 +265,7 @@ onMounted(() => {
.btv-head {
position: sticky; top: 0; z-index: 50;
backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
background: var(--btv-glass);
background: var(--glass);
border-bottom: 1px solid var(--border);
}
.btv-head-inner { max-width: 1180px; margin: 0 auto; padding: 0 28px; height: 68px; display: flex; align-items: center; justify-content: space-between; gap: 24px; }
Expand Down Expand Up @@ -307,7 +295,7 @@ onMounted(() => {
/* Sections */
.btv-section { max-width: 1180px; margin: 0 auto; padding: 64px 28px 40px; }
.btv-narrow { padding: 34px 28px 8px; }
.btv-eyebrow { margin: 0; font-family: var(--mono); font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--accent); }
.btv-eyebrow { margin: 0; font-family: var(--mono); font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text-accent); }
.btv-h2 { margin: 14px 0 0; font-weight: 800; letter-spacing: -1px; line-height: 1.08; font-size: clamp(28px, 4vw, 40px); }
.btv-h2-wide { max-width: 680px; }
.btv-section-lead { margin: 16px 0 0; max-width: 640px; font-size: 16.5px; line-height: 1.65; color: var(--muted); }
Expand All @@ -316,7 +304,7 @@ onMounted(() => {
.btv-prin { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; margin-top: 34px; }
.btv-prin-card { background: var(--card); border: 1px solid var(--border); border-radius: 16px; padding: 22px; transition: transform .2s ease, border-color .2s ease; }
.btv-prin-card:hover { transform: translateY(-3px); border-color: var(--border-2); }
.btv-prin-num { width: 38px; height: 38px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: rgba(224,88,154,0.12); border: 1px solid rgba(224,88,154,0.25); color: var(--accent); font-family: var(--mono); font-weight: 600; font-size: 15px; }
.btv-prin-num { width: 38px; height: 38px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: var(--accent-wash); border: 1px solid var(--accent-line); color: var(--text-accent); font-family: var(--mono); font-weight: 600; font-size: 15px; }
.btv-prin-title { margin: 16px 0 0; font-weight: 700; font-size: 18px; letter-spacing: -0.3px; color: var(--text); }
.btv-prin-body { margin: 9px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--muted); }

Expand All @@ -328,10 +316,10 @@ onMounted(() => {
.btv-pcard-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.btv-pcard-id { display: flex; align-items: center; gap: 11px; min-width: 0; }
.btv-logo { display: block; flex: none; }
.btv-tag { display: inline-flex; align-items: center; font-family: var(--mono); font-size: 11.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--accent); background: rgba(224,88,154,0.1); border: 1px solid rgba(224,88,154,0.22); padding: 5px 10px; border-radius: 999px; }
.btv-tag { display: inline-flex; align-items: center; font-family: var(--mono); font-size: 11.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-accent); background: var(--accent-wash); border: 1px solid var(--accent-line); padding: 5px 10px; border-radius: 999px; }
.btv-stars { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; color: var(--faint); }
.btv-pname { margin: 18px 0 0; font-weight: 800; font-size: 23px; letter-spacing: -0.6px; color: var(--text); }
.btv-pkg { display: inline-block; margin: 7px 0 0; font-family: var(--mono); font-size: 13px; color: var(--accent); background: none; padding: 0; }
.btv-pkg { display: inline-block; margin: 7px 0 0; font-family: var(--mono); font-size: 13px; color: var(--text-accent); background: none; padding: 0; }
.btv-blurb { margin: 14px 0 0; min-height: 92px; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
.btv-points { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.btv-points li { display: flex; align-items: flex-start; gap: 9px; font-size: 14px; line-height: 1.4; color: var(--text); }
Expand All @@ -345,7 +333,7 @@ onMounted(() => {
.btv-foot-a { display: inline-flex; align-items: center; gap: 7px; text-decoration: none; color: var(--text); font-weight: 700; font-size: 14px; }
.btv-foot-muted { color: var(--muted); }
.repolink { transition: color .15s; }
.repolink:hover { color: var(--accent); }
.repolink:hover { color: var(--text-accent); }

/* CTA banner */
.btv-cta-wrap { padding: 30px 28px 80px; }
Expand All @@ -362,7 +350,7 @@ onMounted(() => {
.btv-foot-col { display: flex; flex-direction: column; gap: 11px; }
.btv-foot-h { margin: 0 0 4px; font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--faint); font-weight: 700; }
.foot-link { color: var(--muted); text-decoration: none; font-size: 14px; transition: color .15s; }
.foot-link:hover { color: var(--accent); }
.foot-link:hover { color: var(--text-accent); }
.btv-foot-bottom { max-width: 1180px; margin: 0 auto; padding: 18px 28px 34px; border-top: 1px solid var(--border); display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: space-between; font-size: 13px; color: var(--faint); }
.btv-foot-muted2 { color: var(--muted); }
.btv-foot-mono { font-family: var(--mono); font-size: 12px; color: var(--faint); }
Expand Down
10 changes: 7 additions & 3 deletions packages/theme/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@btravstack/theme",
"version": "1.0.0",
"version": "1.1.0",
"description": "Shared VitePress theme and design tokens for btravstack sites",
"license": "MIT",
"author": "Benoit TRAVERS",
Expand All @@ -11,7 +11,9 @@
"url": "git+https://github.com/btravstack/btravstack.github.io.git",
"directory": "packages/theme"
},
"files": ["dist"],
"files": [
"dist"
],
"exports": {
".": {
"types": "./dist/index.d.mts",
Expand All @@ -20,7 +22,9 @@
"./style.css": "./dist/style.css",
"./tokens.css": "./dist/tokens.css"
},
"sideEffects": ["**/*.css"],
"sideEffects": [
"**/*.css"
],
"publishConfig": {
"access": "public"
},
Expand Down
112 changes: 51 additions & 61 deletions packages/theme/src/style.css
Original file line number Diff line number Diff line change
@@ -1,86 +1,76 @@
/*
* @btravstack/theme — VitePress style entry.
*
* Maps the btravstack design tokens onto VitePress's own `--vp-*` theme
* variables so every btravstack site (this website + the docs sites) shares
* one look. Pulled in automatically by the theme's index.ts; consumers can
* also import it directly as `@btravstack/theme/style.css`.
* Maps the btravstack design tokens onto VitePress's own `--vp-*` variables so
* every btravstack site (the website + the docs sites) shares one look.
* Because the semantic tokens (--bg, --text, --text-accent, …) flip per scheme
* in tokens.css, this mapping is written once and adapts automatically:
* - dark → the btravstack plum surfaces, pink links
* - light → clean warm-white surfaces, brand darkened to deep beetroot
* (--text-accent) so links/headings pass WCAG-AA on white
*
* Theming covers BOTH color schemes, so it's safe to let VitePress follow
* the visitor's OS preference (its default, `appearance: true`):
* - dark → adopts the btravstack surface palette
* - light → keeps VitePress's light surfaces, with the brand darkened to
* the deep beetroot so links/headings pass WCAG-AA on white.
* The `:root:root` selector raises specificity to (0,2,0) so the mapping wins
* over VitePress's own `:root` / `.dark` defaults regardless of load order.
*/
@import "./fonts.css";
@import "./tokens.css";

/* ── Brand defaults + typography (both schemes) ────────────────── */
/* `:root:root` / `:root.dark` raise specificity to (0,2,0) so these win
over VitePress's own `:root` / `.dark` defaults regardless of the order
the remote @import lands in the cascade. */
:root:root {
--vp-c-brand-1: var(--accent);
--vp-c-brand-2: var(--bt-magenta);
--vp-c-brand-3: var(--accent-deep);
--vp-c-brand-soft: rgba(var(--accent-rgb), 0.14);
--vp-c-brand: var(--accent); /* legacy alias */
/* Surfaces / text / dividers — scheme-aware via the semantic tokens */
--vp-c-bg: var(--bg);
--vp-c-bg-alt: var(--card);
--vp-c-bg-soft: var(--card-soft);
--vp-c-bg-elv: var(--card);

--vp-c-text-1: var(--text);
--vp-c-text-2: var(--muted);
--vp-c-text-3: var(--faint);

--vp-c-divider: var(--border);
--vp-c-border: var(--border-2);
--vp-c-gutter: var(--border);

/* Brand — links/active use accent-as-TEXT (darkens on light for AA) */
--vp-c-brand-1: var(--text-accent);
--vp-c-brand-2: var(--bt-pink-soft);
--vp-c-brand-3: var(--accent-deep);
--vp-c-brand-soft: rgba(var(--accent-rgb), 0.16);
--vp-c-brand: var(--text-accent); /* legacy alias */

/* Inline code — accent-as-text so it stays readable on the (scheme-aware)
code inset: pink on dark, deep beetroot on the light code wash */
--vp-code-color: var(--text-accent);
--vp-code-bg: var(--code-bg);

--vp-font-family-base: var(--sans);
--vp-font-family-mono: var(--mono);

/* Solid brand buttons — dark ink on the pink fill, readable in both schemes */
--vp-button-brand-bg: var(--accent);
--vp-button-brand-text: var(--accent-contrast);
--vp-button-brand-border: transparent;
--vp-button-brand-hover-bg: var(--bt-magenta);
--vp-button-brand-hover-text: var(--accent-contrast);
/* Solid brand buttons — dark ink on the pink FILL, readable in both schemes */
--vp-button-brand-bg: var(--accent);
--vp-button-brand-text: var(--accent-contrast);
--vp-button-brand-border: transparent;
--vp-button-brand-hover-bg: var(--bt-magenta);
--vp-button-brand-hover-text: var(--accent-contrast);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-active-bg: var(--accent-deep);
--vp-button-brand-active-text: var(--bt-cream);
--vp-button-brand-active-bg: var(--accent-deep);
--vp-button-brand-active-text: var(--bt-cream);
--vp-button-brand-active-border: transparent;

/* Custom-block (admonition) tints */
--vp-custom-block-tip-bg: rgba(var(--green-rgb), 0.08);
--vp-custom-block-tip-border: rgba(var(--green-rgb), 0.30);
--vp-custom-block-tip-text: var(--text-green);
--vp-custom-block-warning-bg: rgba(var(--accent-rgb), 0.08);
--vp-custom-block-warning-border: var(--accent-line);
--vp-custom-block-warning-text: var(--text-accent);

/* Home hero: gradient name + beetroot glow behind the logo */
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(120deg, var(--accent), var(--bt-pink-soft));
--vp-home-hero-name-background: linear-gradient(120deg, var(--text-accent), var(--bt-pink-soft));
--vp-home-hero-image-background-image: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.30), transparent 72%);
--vp-home-hero-image-filter: blur(8px);
}

/* ── Light scheme: darken the brand so it passes WCAG-AA on white ── */
:root:not(.dark) {
--vp-c-brand-1: var(--accent-deep); /* link / active text — ~7:1 on white */
--vp-c-brand-2: var(--bt-deep-2); /* hover, a touch darker */
--vp-c-brand-3: var(--accent-deep);
--vp-c-brand-soft: rgba(var(--accent-rgb), 0.10);
/* deeper gradient so the hero name reads on a light background */
--vp-home-hero-name-background: linear-gradient(120deg, var(--accent-deep), var(--bt-magenta));
}

/* ── Dark scheme: btravstack surfaces (matches the landing page) ── */
:root.dark {
--vp-c-bg: var(--bg);
--vp-c-bg-alt: var(--card);
--vp-c-bg-soft: var(--card-soft);
--vp-c-bg-elv: var(--card);

--vp-c-text-1: var(--text);
--vp-c-text-2: var(--muted);
--vp-c-text-3: var(--faint);

--vp-c-divider: var(--border);
--vp-c-border: var(--border-2);
--vp-c-gutter: var(--border);

--vp-c-brand-1: var(--accent); /* pink reads great on dark */
--vp-c-brand-2: var(--bt-pink-soft);
--vp-c-brand-soft: rgba(var(--accent-rgb), 0.16);

/* Inline + block code */
--vp-code-color: var(--bt-pink-soft);
--vp-code-bg: rgba(0, 0, 0, 0.35);
}

/* ── Playful flourishes — shared across every btravstack site ───── */

/* Home hero: a soft beetroot glow + a gently floating logo */
Expand Down
Loading