import { FASTElement, Observable, html, css, repeat, when } from '@microsoft/fast-element';
export interface NavItem {
label: string;
href: string;
}
const hamburgerSvg = html`
`;
const closeSvg = html`
`;
/**
*
* Top navigation bar with site title, nav links, and dark/light theme toggle.
*/
export class StarlightHeader extends FASTElement {
siteTitle = '';
nav: NavItem[] = [];
currentPath = '';
navOpen = false;
hasSidebar = false;
_theme = 'light';
private _initialized = false;
override connectedCallback(): void {
super.connectedCallback();
if (!this._initialized && typeof localStorage !== 'undefined') {
const stored = localStorage.getItem('sl-theme') ?? 'light';
this._theme = stored;
if (typeof document !== 'undefined') {
document.documentElement.setAttribute('data-theme', stored);
}
this._initialized = true;
}
}
toggleTheme() {
const next = this._theme === 'light' ? 'dark' : 'light';
this._theme = next;
if (typeof localStorage !== 'undefined') {
localStorage.setItem('sl-theme', next);
}
if (typeof document !== 'undefined') {
document.documentElement.setAttribute('data-theme', next);
}
}
toggleNav() {
this.dispatchEvent(
new CustomEvent('sl-nav-toggle', { bubbles: true, composed: true }),
);
}
}
Observable.defineProperty(StarlightHeader.prototype, 'siteTitle');
Observable.defineProperty(StarlightHeader.prototype, 'nav');
Observable.defineProperty(StarlightHeader.prototype, 'currentPath');
Observable.defineProperty(StarlightHeader.prototype, 'navOpen');
Observable.defineProperty(StarlightHeader.prototype, 'hasSidebar');
Observable.defineProperty(StarlightHeader.prototype, '_theme');
const template = html`
${when(x => x.hasSidebar, html`
`)}
${x => x.siteTitle}
`;
const styles = css`
:host {
display: block;
position: sticky;
top: 0;
z-index: 100;
}
header {
height: var(--sl-nav-height, 3.5rem);
background-color: var(--sl-color-bg-nav, #fff);
border-bottom: 1px solid var(--sl-color-border, #e8e8e8);
display: flex;
align-items: center;
padding: 0 var(--sl-content-pad-x, 1.5rem);
gap: 1rem;
}
.menu-btn {
display: none;
appearance: none;
background: none;
border: 1px solid var(--sl-color-border, #e8e8e8);
border-radius: var(--sl-border-radius, 0.375rem);
width: 2.25rem;
height: 2.25rem;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--sl-color-text, #23262f);
transition: background-color 0.15s;
flex-shrink: 0;
padding: 0;
}
.menu-btn:hover { background-color: var(--sl-color-gray-2, #e8e8e8); }
.menu-btn svg { width: 1.1rem; height: 1.1rem; }
@media (max-width: 72rem) {
.menu-btn { display: flex; }
}
.site-title {
font-size: var(--sl-text-lg, 1.125rem);
font-weight: 700;
color: var(--sl-color-text, #23262f);
text-decoration: none;
white-space: nowrap;
}
.site-title:hover { opacity: 0.85; }
nav {
display: flex;
align-items: center;
gap: 0.25rem;
flex: 1;
}
nav a {
padding: 0.35rem 0.75rem;
font-size: var(--sl-text-sm, 0.875rem);
font-weight: 500;
color: var(--sl-color-gray-5, #4b4b4b);
text-decoration: none;
border-radius: var(--sl-border-radius, 0.375rem);
transition: color 0.15s, background-color 0.15s;
}
nav a:hover {
color: var(--sl-color-text, #23262f);
background-color: var(--sl-color-gray-2, #e8e8e8);
}
nav a[aria-current='page'] {
color: var(--sl-color-accent, #7c3aed);
background-color: var(--sl-color-accent-low, #ede9fe);
}
.theme-toggle {
margin-left: auto;
appearance: none;
background: none;
border: 1px solid var(--sl-color-border, #e8e8e8);
border-radius: var(--sl-border-radius, 0.375rem);
width: 2.25rem;
height: 2.25rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 1rem;
color: var(--sl-color-text, #23262f);
transition: background-color 0.15s;
flex-shrink: 0;
}
.theme-toggle:hover { background-color: var(--sl-color-gray-2, #e8e8e8); }
`;
StarlightHeader.define({ name: 'starlight-header', template, styles });
export default StarlightHeader;