fix(web): render v2 banner full width below header

This commit is contained in:
Dax Raad 2026-09-19 03:29:17 -04:00
parent f1aacaba22
commit 6da6d47aab
5 changed files with 209 additions and 62 deletions

View file

@ -296,7 +296,7 @@ export default defineConfig({
],
components: {
Hero: "./src/components/Hero.astro",
Banner: "./src/components/Banner.astro",
PageFrame: "./src/components/PageFrame.astro",
Head: "./src/components/Head.astro",
Header: "./src/components/Header.astro",
Footer: "./src/components/Footer.astro",

View file

@ -1,61 +0,0 @@
<a class="v2-banner" href="https://opencode.ai/v2">
<span class="badge">New</span>
<span class="text">OpenCode v2 is now available</span>
<span class="arrow" aria-hidden="true">&rarr;</span>
</a>
<style>
.v2-banner {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 12px 24px;
background: var(--color-background-interactive);
color: var(--color-text-strong) !important;
border-bottom: 1px solid var(--color-border-weak);
text-decoration: none;
font-size: 14px;
line-height: 1;
transition: background 0.15s ease;
}
.v2-banner:hover {
background: var(--color-background-interactive-weaker);
}
.badge {
padding: 4px 8px;
background: var(--color-background-strong);
color: var(--color-text-inverted);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.02em;
border-radius: 2px;
}
.text {
font-weight: 500;
}
.arrow {
color: var(--color-text);
transition: transform 0.15s ease;
}
.v2-banner:hover .arrow {
transform: translateX(4px);
}
@media (max-width: 30rem) {
.v2-banner {
padding: 10px 16px;
gap: 8px;
}
.badge {
display: none;
}
}
</style>

View file

@ -0,0 +1,97 @@
---
import MobileMenuToggle from "virtual:starlight/components/MobileMenuToggle"
import V2Banner from "./V2Banner.astro"
const { hasSidebar } = Astro.locals.starlightRoute
---
<div class="page sl-flex">
<header class="header"><slot name="header" /></header>
<V2Banner />
{
hasSidebar && (
<nav class="sidebar print:hidden" aria-label={Astro.locals.t("sidebarNav.accessibleLabel")}>
<MobileMenuToggle />
<div id="starlight__sidebar" class="sidebar-pane">
<div class="sidebar-content sl-flex">
<slot name="sidebar" />
</div>
</div>
</nav>
)
}
<div class="main-frame"><slot /></div>
</div>
<style>
@layer starlight.core {
.page {
flex-direction: column;
min-height: 100vh;
}
.header {
z-index: var(--sl-z-index-navbar);
position: fixed;
inset-inline-start: 0;
inset-block-start: 0;
width: 100%;
height: var(--sl-nav-height);
border-bottom: 1px solid var(--sl-color-hairline-shade);
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
padding-inline-end: var(--sl-nav-pad-x);
background-color: var(--sl-color-bg-nav);
}
:global([data-has-sidebar]) .header {
padding-inline-end: calc(var(--sl-nav-gap) + var(--sl-nav-pad-x) + var(--sl-menu-button-size));
}
.sidebar-pane {
visibility: var(--sl-sidebar-visibility, hidden);
position: fixed;
z-index: var(--sl-z-index-menu);
inset-block: calc(var(--sl-nav-height) + var(--v2-banner-height)) 0;
inset-inline-start: 0;
width: 100%;
background-color: var(--sl-color-black);
overflow-y: auto;
}
:global([aria-expanded="true"]) ~ .sidebar-pane {
--sl-sidebar-visibility: visible;
}
.sidebar-content {
height: 100%;
min-height: max-content;
padding: 1rem var(--sl-sidebar-pad-x) 0;
flex-direction: column;
gap: 1rem;
}
@media (min-width: 50rem) {
.sidebar-content::after {
content: "";
padding-bottom: 1px;
}
}
.main-frame {
padding-top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height) + var(--v2-banner-height));
padding-inline-start: var(--sl-content-inline-start);
}
@media (min-width: 50rem) {
:global([data-has-sidebar]) .header {
padding-inline-end: var(--sl-nav-pad-x);
}
.sidebar-pane {
--sl-sidebar-visibility: visible;
width: var(--sl-sidebar-width);
background-color: var(--sl-color-bg-sidebar);
border-inline-end: 1px solid var(--sl-color-hairline-shade);
}
}
}
</style>

View file

@ -0,0 +1,85 @@
<a class="v2-banner" href="https://opencode.ai/v2">
<span class="badge">New</span>
<span class="text">OpenCode v2 is now available</span>
<span class="arrow" aria-hidden="true">&rarr;</span>
</a>
<style>
.v2-banner {
--banner-bg: hsl(62, 84%, 88%);
--banner-bg-hover: hsl(62, 84%, 84%);
--banner-text: hsl(0, 5%, 12%);
--banner-badge-bg: hsl(0, 5%, 12%);
--banner-badge-text: hsl(0, 20%, 99%);
position: fixed;
top: var(--sl-nav-height);
inset-inline: 0;
z-index: var(--sl-z-index-navbar);
box-sizing: border-box;
height: var(--v2-banner-height);
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 0 24px;
background: var(--banner-bg);
color: var(--banner-text) !important;
text-decoration: none;
font-size: 14px;
line-height: 1;
transition: background 0.15s ease;
}
@media (prefers-color-scheme: dark) {
.v2-banner {
--banner-bg: hsl(60, 24%, 11%);
--banner-bg-hover: hsl(60, 24%, 14%);
--banner-text: hsl(62, 100%, 90%);
--banner-badge-bg: hsl(62, 100%, 90%);
--banner-badge-text: hsl(0, 9%, 7%);
}
}
.v2-banner:hover {
background: var(--banner-bg-hover);
}
.badge {
padding: 4px 8px;
background: var(--banner-badge-bg);
color: var(--banner-badge-text);
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
border-radius: 3px;
}
.text {
font-weight: 500;
}
.arrow {
transition: transform 0.15s ease;
}
.v2-banner:hover .arrow {
transform: translateX(4px);
}
:global(:root[data-has-hero]) .v2-banner {
display: none;
}
@media (max-width: 30rem) {
.v2-banner {
padding: 0 16px;
gap: 8px;
}
.badge {
display: none;
}
}
</style>

View file

@ -28,6 +28,32 @@
/* For the share component */
--sl-color-bg-surface: var(--sl-color-bg-nav);
--sl-color-divider: var(--sl-color-gray-5);
/* Fixed v2 announcement bar rendered below the header by PageFrame */
--v2-banner-height: 2.75rem;
}
:root[data-has-hero] {
--v2-banner-height: 0rem;
}
/* Shift fixed chrome below the v2 banner */
mobile-starlight-toc nav {
top: calc(var(--sl-nav-height) + var(--v2-banner-height) - 1px);
}
html {
scroll-padding-top: calc(1.5rem + var(--sl-nav-height) + var(--sl-mobile-toc-height) + var(--v2-banner-height));
}
@media (min-width: 72rem) {
.right-sidebar {
padding-top: calc(var(--sl-nav-height) + var(--v2-banner-height));
}
html {
scroll-padding-top: calc(1.5rem + var(--sl-nav-height) + var(--v2-banner-height));
}
}
body {