ReviewOS

also looking at this

stacks/bunpress

fix(spa): repair client-side router and polish default theme

#71
Merged glennmichael123 wants to merge fix/spa-nav-and-theme-polish into main
9 files +1037 -170

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/bunpress/src/templates/features.stxmodified+3-16
Changes to packages/bunpress/src/templates/features.stx
@@ -1,20 +1,7 @@
1<div class="VPHomeFeatures" style="padding: 64px 24px; border-top: 1px solid var(--bp-c-divider);">
2 <div style="max-width: 1152px; margin: 0 auto;">
3 <div class="VPFeatures" style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 24px;">
1<div class="VPHomeFeatures">
2 <div class="VPHomeFeatures-inner">
3 <div class="VPFeatures">
44 {!! items !!}
55 </div>
66 </div>
77</div>
8
9<style>
10@media (min-width: 640px) {
11 .VPFeatures {
12 grid-template-columns: repeat(2, 1fr) !important;
13 }
14}
15@media (min-width: 960px) {
16 .VPFeatures {
17 grid-template-columns: repeat(3, 1fr) !important;
18 }
19}
20</style>
packages/bunpress/src/templates/layout-doc.stxmodified+23-19
Changes to packages/bunpress/src/templates/layout-doc.stx
@@ -14,25 +14,29 @@
1414<body>
1515 <div class="Layout">
1616 <!-- VPNav - Header -->
17 <header class="VPNav" style="position: fixed; top: 0; left: 0; right: 0; height: var(--bp-nav-height, 64px); background-color: var(--bp-nav-bg-color, var(--bp-c-bg)); border-bottom: 1px solid var(--bp-c-divider); z-index: var(--bp-z-index-nav, 30);">
18 <div style="max-width: var(--bp-layout-max-width, 1440px); margin: 0 auto; width: 100%; height: 100%; display: flex; align-items: center; justify-content: space-between; padding: 0 24px;">
19 <!-- Left side: Logo/Title + Search -->
20 <div style="display: flex; align-items: center; gap: 24px; flex: 1; min-width: 0;">
21 <a href="/" class="VPNavBarTitle" style="font-size: 16px; font-weight: 600; color: var(--bp-c-text-1); white-space: nowrap; text-decoration: none;">{{ title }}</a>
22 <div class="VPNavBarSearch" style="position: relative; display: flex; align-items: center; max-width: 260px; width: 100%;">
23 <svg style="position: absolute; left: 12px; width: 16px; height: 16px; color: var(--bp-c-text-3);" fill="none" stroke="currentColor" viewBox="0 0 24 24">
17 <header class="VPNav">
18 <div class="VPNavBar">
19 <div class="VPNavBarStart">
20 <button class="VPNavBarHamburger" type="button" aria-label="Toggle navigation" onclick="toggleSidebar()">
21 <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
22 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
23 </svg>
24 </button>
25 <a href="/" class="VPNavBarTitle">{{ title }}</a>
26 <div class="VPNavBarSearch">
27 <svg class="VPNavBarSearch-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2428 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
2529 </svg>
26 <input type="text" placeholder="Search" style="width: 100%; height: 32px; padding-left: 36px; padding-right: 48px; font-size: 13px; background-color: var(--bp-c-bg-alt); border: 1px solid var(--bp-c-divider); border-radius: 4px; color: var(--bp-c-text-1); outline: none; transition: border-color 0.25s, background-color 0.25s;" />
27 <kbd style="position: absolute; right: 8px; padding: 2px 6px; font-size: 11px; font-weight: 600; color: var(--bp-c-text-3); background-color: var(--bp-c-bg); border: 1px solid var(--bp-c-divider); border-radius: 4px;"> K</kbd>
30 <input type="text" class="VPNavBarSearch-input" placeholder="Search" />
31 <kbd class="VPNavBarSearch-kbd"> K</kbd>
2832 </div>
2933 </div>
3034
31 <!-- Right side: Navigation + Icons -->
32 <div style="display: flex; align-items: center; gap: 24px;">
33 {!! nav !!}
34 <div class="VPSocialLinks" style="display: flex; align-items: center; gap: 12px; padding-left: 24px; border-left: 1px solid var(--bp-c-divider);">
35 <!-- Theme Toggle -->
35 <div class="VPNavBarEnd">
36 <div class="VPNavBarMenu">
37 {!! nav !!}
38 </div>
39 <div class="VPSocialLinks">
3640 <button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle dark mode" title="Toggle dark mode">
3741 <svg class="sun-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
3842 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
@@ -41,8 +45,8 @@
4145 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
4246 </svg>
4347 </button>
44 <a href="https://github.com/stacksjs/bunpress" target="_blank" style="color: var(--bp-c-text-2); transition: color 0.25s;" onmouseover="this.style.color='var(--bp-c-text-1)'" onmouseout="this.style.color='var(--bp-c-text-2)'">
45 <svg style="width: 20px; height: 20px;" fill="currentColor" viewBox="0 0 24 24">
48 <a href="https://github.com/stacksjs/bunpress" target="_blank" rel="noopener external" aria-label="GitHub">
49 <svg fill="currentColor" viewBox="0 0 24 24">
4650 <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
4751 </svg>
4852 </a>
@@ -55,9 +59,9 @@
5559 {!! sidebar !!}
5660
5761 <!-- VPContent - Main content area -->
58 <main class="VPContent" style="position: fixed; top: var(--bp-nav-height, 64px); bottom: 0; overflow-y: auto; left: max(var(--bp-sidebar-width, 272px), calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + var(--bp-sidebar-width, 272px))); right: max(0px, calc((100vw - var(--bp-layout-max-width, 1440px)) / 2));">
59 <div class="VPDoc" style="padding: 32px 24px; padding-right: 32px;">
60 <div class="VPDocContent" style="max-width: 768px; margin: 0;">
62 <main class="VPContent VPContent--doc">
63 <div class="VPDoc">
64 <div class="VPDocContent">
6165 <article class="bp-doc">
6266 {!! content !!}
6367 </article>
packages/bunpress/src/templates/layout-page.stxmodified+10-8
Changes to packages/bunpress/src/templates/layout-page.stx
@@ -14,20 +14,22 @@
1414<body>
1515 <div class="Layout">
1616 <!-- VPNav - Header -->
17 <header class="VPNav" style="position: fixed; top: 0; left: 0; right: 0; height: var(--bp-nav-height, 64px); background-color: var(--bp-nav-bg-color, var(--bp-c-bg)); border-bottom: 1px solid var(--bp-c-divider); z-index: var(--bp-z-index-nav, 30);">
18 <div style="max-width: var(--bp-layout-max-width, 1440px); margin: 0 auto; width: 100%; height: 100%; display: flex; align-items: center; justify-content: space-between; padding: 0 24px;">
19 <div style="display: flex; align-items: center; gap: 24px; flex: 1; min-width: 0;">
20 <a href="/" class="VPNavBarTitle" style="font-size: 16px; font-weight: 600; color: var(--bp-c-text-1); white-space: nowrap; text-decoration: none;">{{ title }}</a>
17 <header class="VPNav">
18 <div class="VPNavBar">
19 <div class="VPNavBarStart">
20 <a href="/" class="VPNavBarTitle">{{ title }}</a>
2121 </div>
22 <div style="display: flex; align-items: center; gap: 24px;">
23 {!! nav !!}
22 <div class="VPNavBarEnd">
23 <div class="VPNavBarMenu">
24 {!! nav !!}
25 </div>
2426 </div>
2527 </div>
2628 </header>
2729
2830 <!-- VPContent - Full-width content without sidebar -->
29 <main class="VPContent" style="padding-top: var(--bp-nav-height, 64px);">
30 <div class="VPPage" style="padding: 48px 24px; max-width: 768px; margin: 0 auto;">
31 <main class="VPContent VPContent--page">
32 <div class="VPPage">
3133 <article class="bp-doc">
3234 {!! content !!}
3335 </article>
packages/bunpress/src/templates/sidebar-section.stxmodified+67-11
Changes to packages/bunpress/src/templates/sidebar-section.stx
@@ -1,27 +1,60 @@
1<div class="VPSidebarItem sidebar-section" style="margin-bottom: 16px;">
2 <button
3 style="width: 100%; display: flex; align-items: center; justify-content: space-between; padding: 8px 24px; font-size: 14px; font-weight: 600; color: var(--bp-c-text-1); background: transparent; border: none; cursor: pointer; transition: color 0.25s;"
4 onclick="toggleSection(this.parentElement)"
5 onmouseover="this.style.color='var(--bp-c-brand-1)'"
6 onmouseout="this.style.color='var(--bp-c-text-1)'"
7 >
1<div class="VPSidebarItem sidebar-section">
2 <button class="sidebar-section-toggle" onclick="toggleSection(this.parentElement)" type="button">
83 <span>{{ title }}</span>
9 <svg class="chevron" style="width: 16px; height: 16px; transition: transform 0.2s ease-in-out;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
4 <svg class="chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24">
105 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
116 </svg>
127 </button>
138 <div class="sidebar-items-wrapper">
14 <ul class="sidebar-items" style="list-style: none; margin: 4px 0 0 0; padding: 0;">
9 <ul class="sidebar-items">
1510 {!! items !!}
1611 </ul>
1712 </div>
1813</div>
1914
2015<style>
16.sidebar-section {
17 margin-bottom: 16px;
18}
19
20.sidebar-section-toggle {
21 width: 100%;
22 display: flex;
23 align-items: center;
24 justify-content: space-between;
25 padding: 8px 24px;
26 font-size: 14px;
27 font-weight: 600;
28 color: var(--bp-c-text-1);
29 background: transparent;
30 border: none;
31 cursor: pointer;
32 transition: color 0.25s;
33 font-family: inherit;
34 text-align: left;
35}
36
37.sidebar-section-toggle:hover {
38 color: var(--bp-c-brand-1);
39}
40
41.sidebar-section-toggle .chevron {
42 width: 16px;
43 height: 16px;
44 transition: transform 0.2s ease-in-out;
45 flex-shrink: 0;
46}
47
48.sidebar-items {
49 list-style: none;
50 margin: 4px 0 0 0;
51 padding: 0;
52}
53
2154.sidebar-items-wrapper {
2255 overflow: hidden;
2356 transition: max-height 0.3s ease-in-out, opacity 0.2s ease-in-out;
24 max-height: 500px;
57 max-height: 1000px;
2558 opacity: 1;
2659}
2760
@@ -30,9 +63,32 @@
3063 opacity: 0;
3164}
3265
33.sidebar-section.collapsed .chevron {
66.sidebar-section.collapsed .sidebar-section-toggle .chevron {
3467 transform: rotate(-90deg);
3568}
69
70.VPSidebarItem-link {
71 display: block;
72 padding: 6px 24px;
73 color: var(--bp-c-text-2);
74 text-decoration: none;
75 font-size: 14px;
76 line-height: 1.5;
77 transition: color 0.25s;
78 border-left: 2px solid transparent;
79 margin-left: 0;
80}
81
82.VPSidebarItem-link:hover {
83 color: var(--bp-c-brand-1);
84}
85
86.VPSidebarItem-link.is-active {
87 color: var(--bp-c-brand-1);
88 font-weight: 600;
89 border-left-color: var(--bp-c-brand-1);
90 padding-left: 22px;
91}
3692</style>
3793
3894<script>
packages/bunpress/src/themes/bun/index.tsmodified+3-0
Changes to packages/bunpress/src/themes/bun/index.ts
@@ -11,6 +11,8 @@
1111 * - Dark backgrounds: #0d0e11, #14151a, #282a36
1212 */
1313
14import { layoutCSS } from '../vitepress'
15
1416// CSS Variables - Exact values from bun.sh
1517const varsCSS = `/**
1618 * Bun Theme for BunPress
@@ -2036,6 +2038,7 @@ export function getBunThemeCSS(): string {
20362038/* Colors extracted from bun.sh */
20372039${varsCSS}
20382040${baseCSS}
2041${layoutCSS}
20392042${customBlockCSS}
20402043${codeGroupCSS}
20412044${bunExtrasCSS}
packages/bunpress/src/themes/vitepress/index.tsmodified+640-0
Changes to packages/bunpress/src/themes/vitepress/index.ts
@@ -1901,6 +1901,645 @@ const codeGroupCSS = `/**
19011901 border: none;
19021902}`
19031903
1904// Layout / chrome styles — classes referenced by layout-doc.stx, layout-page.stx, layout-home.stx,
1905// and the nav/sidebar generators in serve.ts. Keeps templates declarative and dark-mode aware.
1906export const layoutCSS = `/**
1907 * VitePress Theme for BunPress - Layout & Chrome
1908 * -------------------------------------------------------------------------- */
1909
1910.Layout {
1911 min-height: 100vh;
1912}
1913
1914/* VPNav — top bar */
1915.VPNav {
1916 position: fixed;
1917 top: 0;
1918 left: 0;
1919 right: 0;
1920 height: var(--bp-nav-height, 64px);
1921 background-color: var(--bp-nav-bg-color, var(--bp-c-bg));
1922 border-bottom: 1px solid var(--bp-c-divider);
1923 z-index: var(--bp-z-index-nav, 30);
1924 backdrop-filter: saturate(50%) blur(8px);
1925}
1926
1927.VPNavBar {
1928 max-width: var(--bp-layout-max-width, 1440px);
1929 margin: 0 auto;
1930 width: 100%;
1931 height: 100%;
1932 display: flex;
1933 align-items: center;
1934 justify-content: space-between;
1935 padding: 0 24px;
1936 gap: 24px;
1937}
1938
1939.VPNavBarStart {
1940 display: flex;
1941 align-items: center;
1942 gap: 24px;
1943 flex: 1;
1944 min-width: 0;
1945}
1946
1947.VPNavBarEnd {
1948 display: flex;
1949 align-items: center;
1950 gap: 24px;
1951 flex-shrink: 0;
1952}
1953
1954.VPNavBarTitle {
1955 font-size: 16px;
1956 font-weight: 600;
1957 color: var(--bp-c-text-1);
1958 white-space: nowrap;
1959 text-decoration: none;
1960 transition: color 0.25s;
1961}
1962
1963.VPNavBarTitle:hover {
1964 color: var(--bp-c-brand-1);
1965}
1966
1967.VPNavBarMenu {
1968 display: flex;
1969 align-items: center;
1970 gap: 24px;
1971}
1972
1973.VPNavBarMenu a,
1974.VPNavBarMenu .VPNavBarMenu-link {
1975 font-size: 14px;
1976 font-weight: 500;
1977 color: var(--bp-c-text-1);
1978 text-decoration: none;
1979 transition: color 0.25s;
1980 cursor: pointer;
1981}
1982
1983.VPNavBarMenu a:hover,
1984.VPNavBarMenu .VPNavBarMenu-link:hover,
1985.VPNavBarMenu a.is-active {
1986 color: var(--bp-c-brand-1);
1987}
1988
1989.VPNavBarMenu-group {
1990 position: relative;
1991}
1992
1993.VPNavBarMenu-group-button {
1994 display: inline-flex;
1995 align-items: center;
1996 gap: 4px;
1997 background: transparent;
1998 border: none;
1999 padding: 0;
2000 font: inherit;
2001 font-size: 14px;
2002 font-weight: 500;
2003 color: var(--bp-c-text-1);
2004 cursor: pointer;
2005 transition: color 0.25s;
2006}
2007
2008.VPNavBarMenu-group-button:hover {
2009 color: var(--bp-c-brand-1);
2010}
2011
2012.VPNavBarMenu-group-button .chevron {
2013 width: 12px;
2014 height: 12px;
2015 flex-shrink: 0;
2016 transition: transform 0.25s;
2017}
2018
2019.VPNavBarMenu-group:hover > .VPNavBarMenu-group-button .chevron {
2020 transform: rotate(180deg);
2021}
2022
2023.VPNavBarMenu-group-items {
2024 display: none;
2025 position: absolute;
2026 right: 0;
2027 top: 100%;
2028 margin-top: 8px;
2029 padding: 8px 0;
2030 min-width: 192px;
2031 background: var(--bp-c-bg);
2032 border: 1px solid var(--bp-c-divider);
2033 border-radius: 8px;
2034 box-shadow: var(--bp-shadow-3, 0 12px 32px rgba(0, 0, 0, 0.1));
2035 z-index: 10;
2036}
2037
2038.VPNavBarMenu-group:hover > .VPNavBarMenu-group-items {
2039 display: block;
2040}
2041
2042.VPNavBarMenu-group-items a {
2043 display: block;
2044 padding: 6px 16px;
2045 font-size: 13px;
2046 color: var(--bp-c-text-1);
2047 text-decoration: none;
2048 transition: color 0.25s, background-color 0.25s;
2049}
2050
2051.VPNavBarMenu-group-items a:hover {
2052 color: var(--bp-c-brand-1);
2053 background-color: var(--bp-c-bg-soft);
2054}
2055
2056/* Search */
2057.VPNavBarSearch {
2058 position: relative;
2059 display: flex;
2060 align-items: center;
2061 max-width: 260px;
2062 width: 100%;
2063}
2064
2065.VPNavBarSearch-icon {
2066 position: absolute;
2067 left: 12px;
2068 width: 16px;
2069 height: 16px;
2070 color: var(--bp-c-text-3);
2071 pointer-events: none;
2072}
2073
2074.VPNavBarSearch-input {
2075 width: 100%;
2076 height: 32px;
2077 padding: 0 48px 0 36px;
2078 font: inherit;
2079 font-size: 13px;
2080 background-color: var(--bp-c-bg-alt);
2081 border: 1px solid var(--bp-c-divider);
2082 border-radius: 4px;
2083 color: var(--bp-c-text-1);
2084 outline: none;
2085 transition: border-color 0.25s, background-color 0.25s;
2086}
2087
2088.VPNavBarSearch-input::placeholder {
2089 color: var(--bp-c-text-3);
2090}
2091
2092.VPNavBarSearch-input:hover,
2093.VPNavBarSearch-input:focus {
2094 border-color: var(--bp-c-brand-1);
2095 background-color: var(--bp-c-bg);
2096}
2097
2098.VPNavBarSearch-kbd {
2099 position: absolute;
2100 right: 8px;
2101 padding: 2px 6px;
2102 font-size: 11px;
2103 font-weight: 600;
2104 font-family: inherit;
2105 color: var(--bp-c-text-3);
2106 background-color: var(--bp-c-bg);
2107 border: 1px solid var(--bp-c-divider);
2108 border-radius: 4px;
2109 pointer-events: none;
2110}
2111
2112/* Social/icon links cluster */
2113.VPSocialLinks {
2114 display: flex;
2115 align-items: center;
2116 gap: 12px;
2117 padding-left: 24px;
2118 border-left: 1px solid var(--bp-c-divider);
2119}
2120
2121.VPSocialLinks > a {
2122 display: inline-flex;
2123 align-items: center;
2124 justify-content: center;
2125 width: 32px;
2126 height: 32px;
2127 color: var(--bp-c-text-2);
2128 border-radius: 4px;
2129 transition: color 0.25s, background-color 0.25s;
2130}
2131
2132.VPSocialLinks > a:hover {
2133 color: var(--bp-c-text-1);
2134 background-color: var(--bp-c-bg-soft);
2135}
2136
2137.VPSocialLinks > a svg {
2138 width: 20px;
2139 height: 20px;
2140}
2141
2142/* Content area */
2143.VPContent {
2144 flex: 1;
2145}
2146
2147.VPContent--doc {
2148 position: fixed;
2149 top: var(--bp-nav-height, 64px);
2150 bottom: 0;
2151 overflow-y: auto;
2152 left: max(var(--bp-sidebar-width, 272px), calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + var(--bp-sidebar-width, 272px)));
2153 right: max(0px, calc((100vw - var(--bp-layout-max-width, 1440px)) / 2));
2154}
2155
2156.VPContent--page {
2157 padding-top: var(--bp-nav-height, 64px);
2158}
2159
2160.VPDoc {
2161 padding: 32px 24px;
2162 padding-right: 32px;
2163}
2164
2165@media (min-width: 1280px) {
2166 .VPDoc {
2167 padding: 48px 32px 128px;
2168 }
2169}
2170
2171.VPDocContent {
2172 max-width: 768px;
2173 margin: 0;
2174}
2175
2176.VPPage {
2177 padding: 48px 24px;
2178 max-width: 768px;
2179 margin: 0 auto;
2180}
2181
2182@media (min-width: 1280px) {
2183 .VPPage {
2184 padding: 64px 32px;
2185 }
2186}
2187
2188/* Mobile sidebar drawer behaviour */
2189@media (max-width: 959px) {
2190 .VPNavBarSearch {
2191 display: none;
2192 }
2193 .VPSocialLinks {
2194 padding-left: 12px;
2195 gap: 8px;
2196 }
2197 .VPNavBarMenu {
2198 display: none;
2199 }
2200}
2201
2202/**
2203 * Hero (home layout) — used by hero.stx + serve.ts generateHero
2204 * -------------------------------------------------------------------------- */
2205
2206.VPHero-name {
2207 font-size: 20px;
2208 font-weight: 700;
2209 letter-spacing: -0.02em;
2210 line-height: 1.2;
2211 margin: 0 0 8px;
2212 background: linear-gradient(135deg, var(--bp-c-brand-1, #5672cd) 0%, var(--bp-c-brand-2, #8b9cf7) 100%);
2213 -webkit-background-clip: text;
2214 -webkit-text-fill-color: transparent;
2215 background-clip: text;
2216}
2217
2218.VPHero-text {
2219 font-size: 40px;
2220 font-weight: 800;
2221 letter-spacing: -0.02em;
2222 line-height: 1.1;
2223 color: var(--bp-c-text-1);
2224 margin: 0 0 8px;
2225}
2226
2227.VPHero-tagline {
2228 font-size: 18px;
2229 font-weight: 400;
2230 line-height: 1.6;
2231 color: var(--bp-c-text-2);
2232 margin: 12px 0 0;
2233}
2234
2235@media (min-width: 960px) {
2236 .VPHero-name {
2237 font-size: 24px;
2238 }
2239 .VPHero-text {
2240 font-size: 56px;
2241 }
2242 .VPHero-tagline {
2243 font-size: 20px;
2244 }
2245}
2246
2247.VPHero-actions {
2248 display: flex;
2249 flex-wrap: wrap;
2250 gap: 12px;
2251 margin-top: 28px;
2252}
2253
2254.VPButton {
2255 display: inline-flex;
2256 align-items: center;
2257 justify-content: center;
2258 padding: 0 24px;
2259 height: 40px;
2260 font-size: 14px;
2261 font-weight: 600;
2262 border-radius: 20px;
2263 text-decoration: none;
2264 transition: background-color 0.25s, color 0.25s, border-color 0.25s;
2265 border: 1px solid transparent;
2266 white-space: nowrap;
2267 cursor: pointer;
2268}
2269
2270.VPButton-brand {
2271 color: var(--bp-button-brand-text, #fff);
2272 background-color: var(--bp-c-brand-1);
2273 border-color: var(--bp-c-brand-1);
2274}
2275
2276.VPButton-brand:hover {
2277 background-color: var(--bp-c-brand-2);
2278 border-color: var(--bp-c-brand-2);
2279}
2280
2281.VPButton-alt {
2282 color: var(--bp-c-text-1);
2283 background-color: transparent;
2284 border-color: var(--bp-c-divider);
2285}
2286
2287.VPButton-alt:hover {
2288 border-color: var(--bp-c-text-2);
2289 color: var(--bp-c-brand-1);
2290}
2291
2292/**
2293 * Features grid — used by features.stx + serve.ts generateFeatures
2294 * -------------------------------------------------------------------------- */
2295
2296.VPHomeFeatures {
2297 padding: 48px 24px;
2298 border-top: 1px solid var(--bp-c-divider);
2299}
2300
2301.VPHomeFeatures-inner {
2302 max-width: 1152px;
2303 margin: 0 auto;
2304}
2305
2306.VPFeatures {
2307 display: grid;
2308 grid-template-columns: repeat(1, 1fr);
2309 gap: 16px;
2310}
2311
2312@media (min-width: 640px) {
2313 .VPFeatures {
2314 grid-template-columns: repeat(2, 1fr);
2315 gap: 24px;
2316 }
2317}
2318
2319@media (min-width: 960px) {
2320 .VPHomeFeatures {
2321 padding: 64px 32px;
2322 }
2323 .VPFeatures {
2324 grid-template-columns: repeat(3, 1fr);
2325 }
2326}
2327
2328.VPFeature {
2329 display: block;
2330 padding: 24px;
2331 background-color: var(--bp-c-bg-soft, var(--bp-c-bg-alt));
2332 border: 1px solid var(--bp-c-divider);
2333 border-radius: 12px;
2334 transition: border-color 0.25s, box-shadow 0.25s;
2335 text-decoration: none;
2336 color: inherit;
2337}
2338
2339.VPFeature:hover {
2340 border-color: var(--bp-c-brand-1);
2341 box-shadow: 0 2px 12px rgba(86, 114, 205, 0.08);
2342}
2343
2344.VPFeature-icon {
2345 width: 40px;
2346 height: 40px;
2347 display: flex;
2348 align-items: center;
2349 justify-content: center;
2350 border-radius: 8px;
2351 background: var(--bp-c-brand-soft, rgba(86, 114, 205, 0.1));
2352 color: var(--bp-c-brand-1);
2353 margin-bottom: 12px;
2354}
2355
2356.VPFeature-icon svg {
2357 width: 24px;
2358 height: 24px;
2359}
2360
2361.VPFeature-icon-text {
2362 font-size: 24px;
2363 font-weight: 700;
2364}
2365
2366.VPFeature-title {
2367 margin: 0 0 8px;
2368 font-size: 16px;
2369 font-weight: 600;
2370 line-height: 1.4;
2371 color: var(--bp-c-text-1);
2372}
2373
2374.VPFeature-details {
2375 margin: 0;
2376 font-size: 14px;
2377 line-height: 1.6;
2378 color: var(--bp-c-text-2);
2379}
2380
2381/**
2382 * Inline content — badges, external link icons
2383 * -------------------------------------------------------------------------- */
2384
2385.bp-badge {
2386 display: inline-block;
2387 padding: 2px 8px;
2388 font-size: 0.85em;
2389 font-weight: 600;
2390 border-radius: 4px;
2391 margin: 0 4px;
2392 vertical-align: middle;
2393 border: 1px solid transparent;
2394 line-height: 1.5;
2395}
2396
2397.bp-badge-tip {
2398 background: var(--bp-c-tip-soft, rgba(16, 185, 129, 0.14));
2399 color: var(--bp-c-tip-1, var(--bp-c-green-1));
2400 border-color: var(--bp-c-tip-2, var(--bp-c-green-2));
2401}
2402
2403.bp-badge-info {
2404 background: var(--bp-c-default-soft, var(--bp-c-gray-soft));
2405 color: var(--bp-c-text-1);
2406 border-color: var(--bp-c-divider);
2407}
2408
2409.bp-badge-warning {
2410 background: var(--bp-c-warning-soft, rgba(234, 179, 8, 0.14));
2411 color: var(--bp-c-warning-1, var(--bp-c-yellow-1));
2412 border-color: var(--bp-c-warning-2, var(--bp-c-yellow-2));
2413}
2414
2415.bp-badge-danger {
2416 background: var(--bp-c-danger-soft, rgba(244, 63, 94, 0.14));
2417 color: var(--bp-c-danger-1, var(--bp-c-red-1));
2418 border-color: var(--bp-c-danger-2, var(--bp-c-red-2));
2419}
2420
2421.external-link-icon {
2422 display: inline-block;
2423 margin-left: 4px;
2424 vertical-align: middle;
2425 width: 12px;
2426 height: 12px;
2427}
2428
2429/**
2430 * Polish: prose elements
2431 * -------------------------------------------------------------------------- */
2432
2433/* Subtle row hover on tables */
2434.bp-doc tr:hover {
2435 background-color: var(--bp-c-bg-soft);
2436}
2437
2438/* Mobile-safe table scroll */
2439.bp-doc table {
2440 width: 100%;
2441 max-width: 100%;
2442}
2443
2444/* Slightly stronger blockquote with brand-tinted accent */
2445.bp-doc blockquote {
2446 border-left-color: var(--bp-c-brand-1);
2447 padding: 8px 0 8px 16px;
2448}
2449
2450/* Code-block scrollbar */
2451.bp-doc [class*='language-'] pre::-webkit-scrollbar,
2452.bp-doc pre[data-lang]::-webkit-scrollbar {
2453 height: 6px;
2454 width: 6px;
2455}
2456.bp-doc [class*='language-'] pre::-webkit-scrollbar-thumb,
2457.bp-doc pre[data-lang]::-webkit-scrollbar-thumb {
2458 background-color: var(--bp-c-divider);
2459 border-radius: 3px;
2460}
2461.bp-doc [class*='language-'] pre::-webkit-scrollbar-thumb:hover,
2462.bp-doc pre[data-lang]::-webkit-scrollbar-thumb:hover {
2463 background-color: var(--bp-c-text-3);
2464}
2465
2466/* Heading anchor: keep it subtle */
2467.bp-doc .header-anchor {
2468 color: var(--bp-c-text-3);
2469}
2470.bp-doc .header-anchor:hover,
2471.bp-doc .header-anchor:focus {
2472 color: var(--bp-c-brand-1);
2473}
2474
2475/**
2476 * Mobile nav / sidebar drawer
2477 * -------------------------------------------------------------------------- */
2478
2479.VPNavBarHamburger {
2480 display: none;
2481 width: 32px;
2482 height: 32px;
2483 background: transparent;
2484 border: none;
2485 cursor: pointer;
2486 align-items: center;
2487 justify-content: center;
2488 color: var(--bp-c-text-2);
2489 border-radius: 4px;
2490 padding: 0;
2491 margin-left: -4px;
2492}
2493
2494.VPNavBarHamburger:hover {
2495 color: var(--bp-c-text-1);
2496 background-color: var(--bp-c-bg-soft);
2497}
2498
2499.VPNavBarHamburger svg {
2500 width: 20px;
2501 height: 20px;
2502}
2503
2504@media (max-width: 959px) {
2505 .VPNavBarHamburger {
2506 display: inline-flex;
2507 }
2508
2509 .VPSidebar {
2510 transform: translateX(-100%);
2511 transition: transform 0.25s ease, box-shadow 0.25s ease;
2512 z-index: var(--bp-z-index-sidebar, 25);
2513 background-color: var(--bp-c-bg-alt);
2514 box-shadow: none;
2515 }
2516
2517 .VPSidebar.is-open {
2518 transform: translateX(0);
2519 box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
2520 }
2521
2522 .VPSidebar-backdrop {
2523 position: fixed;
2524 inset: 0;
2525 background-color: rgba(0, 0, 0, 0.32);
2526 opacity: 0;
2527 pointer-events: none;
2528 transition: opacity 0.2s ease;
2529 z-index: calc(var(--bp-z-index-sidebar, 25) - 1);
2530 }
2531
2532 .VPSidebar-backdrop.is-open {
2533 opacity: 1;
2534 pointer-events: auto;
2535 }
2536
2537 .VPContent--doc {
2538 left: 0;
2539 }
2540}
2541`
2542
19042543/**
19052544 * Get all VitePress theme CSS combined
19062545 */
@@ -1909,6 +2548,7 @@ export function getVitePressThemeCSS(): string {
19092548/* VitePress Theme for BunPress */
19102549${varsCSS}
19112550${baseCSS}
2551${layoutCSS}
19122552${customBlockCSS}
19132553${codeGroupCSS}
19142554`