662 lines
18 KiB
Plaintext
662 lines
18 KiB
Plaintext
---
|
|
// Custom navigation component to add Products and API Reference links
|
|
// This overrides the default Starlight Header component
|
|
import Search from '@astrojs/starlight/components/Search.astro';
|
|
import ThemeSelect from '@astrojs/starlight/components/ThemeSelect.astro';
|
|
import { Icon } from '@astrojs/starlight/components';
|
|
|
|
// Determine if we're on a docs page based on the current path
|
|
const currentPath = Astro.url.pathname;
|
|
const isDocsPage = currentPath.startsWith('/jan/') ||
|
|
currentPath.startsWith('/mobile/') ||
|
|
currentPath.startsWith('/server/') ||
|
|
currentPath.startsWith('/local-server/') ||
|
|
currentPath === '/' ||
|
|
currentPath === '/index' ||
|
|
currentPath === '/docs' ||
|
|
currentPath === '/docs/';
|
|
---
|
|
|
|
<div class="sl-nav-wrapper">
|
|
<nav class="sl-nav" aria-label="Main">
|
|
<!-- Left side with title and links -->
|
|
<div class="sl-nav__left">
|
|
<!-- Site title/logo -->
|
|
<a href="https://jan.ai" class="sl-nav__title">
|
|
👋 Jan
|
|
</a>
|
|
|
|
<!-- Main navigation links - hide on mobile for docs pages -->
|
|
<div class={`sl-nav__links ${isDocsPage ? 'docs-page' : 'custom-page'}`}>
|
|
<a href="/products" class="sl-nav__link" data-nav-item="products">
|
|
Products
|
|
</a>
|
|
<a href="/jan" class="sl-nav__link" data-nav-item="docs">
|
|
Docs
|
|
</a>
|
|
<a href="/handbook" class="sl-nav__link" data-nav-item="handbook">
|
|
Handbook
|
|
</a>
|
|
<a href="/blog" class="sl-nav__link" data-nav-item="blog">
|
|
Blog
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Center search -->
|
|
<div class="sl-nav__center">
|
|
<div class="sl-nav__search">
|
|
<Search />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right side items -->
|
|
<div class="sl-nav__end">
|
|
<!-- Changelog and API Reference links -->
|
|
<a href="/changelog" class={`sl-nav__link sl-nav__api-link ${isDocsPage ? 'docs-page' : 'custom-page'}`} data-nav-item="changelog">
|
|
Changelog
|
|
</a>
|
|
<a href="/api-reference" class={`sl-nav__link sl-nav__api-link ${isDocsPage ? 'docs-page' : 'custom-page'}`} data-nav-item="api">
|
|
API Reference
|
|
</a>
|
|
|
|
<!-- Theme toggle - always visible on desktop -->
|
|
<div class="sl-nav__theme">
|
|
<ThemeSelect />
|
|
</div>
|
|
|
|
<!-- Social links -->
|
|
<div class="sl-nav__social">
|
|
<a href="https://github.com/menloresearch/jan" class="sl-nav__social-link" aria-label="GitHub">
|
|
<Icon name="github"/>
|
|
</a>
|
|
<a href="https://twitter.com/jandotai" class="sl-nav__social-link" aria-label="X">
|
|
<Icon name="x.com"/>
|
|
</a>
|
|
<a href="https://discord.com/invite/FTk2MvZwJH" class="sl-nav__social-link" aria-label="Discord">
|
|
<Icon name="discord"/>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Mobile hamburger menu - only for custom pages -->
|
|
{!isDocsPage && (
|
|
<div class="sl-nav__hamburger">
|
|
<button id="hamburger-btn" class="hamburger-button" aria-label="Toggle navigation menu">
|
|
<span class="hamburger-icon">☰</span>
|
|
</button>
|
|
<div id="hamburger-menu" class="hamburger-menu">
|
|
<a href="/products" class="hamburger-link">Products</a>
|
|
<a href="/jan" class="hamburger-link">Docs</a>
|
|
<a href="/handbook" class="hamburger-link">Handbook</a>
|
|
<a href="/blog" class="hamburger-link">Blog</a>
|
|
<a href="/changelog" class="hamburger-link">Changelog</a>
|
|
<a href="/api-reference" class="hamburger-link">API Reference</a>
|
|
<div class="hamburger-social">
|
|
<a href="https://github.com/menloresearch/jan" class="hamburger-social-link" aria-label="GitHub">
|
|
<Icon name="github"/>
|
|
</a>
|
|
<a href="https://twitter.com/jandotai" class="hamburger-social-link" aria-label="X">
|
|
<Icon name="x.com"/>
|
|
</a>
|
|
<a href="https://discord.com/invite/FTk2MvZwJH" class="hamburger-social-link" aria-label="Discord">
|
|
<Icon name="discord"/>
|
|
</a>
|
|
</div>
|
|
<div class="hamburger-theme">
|
|
<ThemeSelect />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
|
|
<style>
|
|
/* Base navigation styles */
|
|
.sl-nav-wrapper {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 999; /* High z-index to stay above ToC and other elements */
|
|
background: var(--sl-color-bg-nav);
|
|
border-bottom: 1px solid var(--sl-color-hairline);
|
|
backdrop-filter: blur(10px);
|
|
-webkit-backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.sl-nav {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
padding: 0.75rem 1rem;
|
|
max-width: 100%;
|
|
margin: 0 auto;
|
|
height: var(--sl-nav-height, 3.5rem);
|
|
}
|
|
|
|
.sl-nav__center {
|
|
flex: 1;
|
|
display: flex;
|
|
justify-content: center;
|
|
max-width: 600px;
|
|
margin: 0 1rem;
|
|
}
|
|
|
|
.sl-nav__left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.sl-nav__title {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
color: var(--sl-color-white);
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.sl-nav__title:hover {
|
|
color: var(--sl-color-text-accent);
|
|
}
|
|
|
|
.sl-nav__links {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.sl-nav__link {
|
|
color: var(--sl-color-gray-3);
|
|
text-decoration: none;
|
|
font-size: 0.9375rem;
|
|
transition: color 0.2s ease;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.sl-nav__link:hover {
|
|
color: var(--sl-color-white);
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* Light theme adjustments - better contrast */
|
|
html[data-theme="light"] .sl-nav__link {
|
|
color: #374151; /* Darker gray for better readability */
|
|
}
|
|
|
|
html[data-theme="light"] .sl-nav__link:hover {
|
|
color: var(--sl-color-accent);
|
|
}
|
|
|
|
html[data-theme="light"] .sl-nav__title {
|
|
color: #111827; /* Very dark gray, almost black */
|
|
}
|
|
|
|
/* Active link styling */
|
|
.sl-nav__link.active {
|
|
color: var(--sl-color-text-accent);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Light theme active link */
|
|
html[data-theme="light"] .sl-nav__link.active {
|
|
color: var(--sl-color-text-accent);
|
|
}
|
|
|
|
.sl-nav__end {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.sl-nav__search {
|
|
width: 100%;
|
|
max-width: 400px;
|
|
position: relative;
|
|
}
|
|
|
|
/* Fix search input styling for light mode */
|
|
.sl-nav__search :global(input) {
|
|
width: 100%;
|
|
padding: 0.5rem 1rem;
|
|
}
|
|
|
|
/* Fix search bar in light mode with more specific selectors */
|
|
html[data-theme="light"] .sl-nav__search :global(.pagefind-ui__search-input),
|
|
html[data-theme="light"] .sl-nav__search :global(input[type="search"]),
|
|
html[data-theme="light"] .sl-nav__search :global(input) {
|
|
background: #f9fafb !important;
|
|
background-color: #f9fafb !important;
|
|
border: 1px solid #d1d5db !important;
|
|
color: #111827 !important;
|
|
}
|
|
|
|
html[data-theme="light"] .sl-nav__search :global(.pagefind-ui__search-input:focus),
|
|
html[data-theme="light"] .sl-nav__search :global(input[type="search"]:focus),
|
|
html[data-theme="light"] .sl-nav__search :global(input:focus) {
|
|
background: #ffffff !important;
|
|
background-color: #ffffff !important;
|
|
border-color: var(--sl-color-accent) !important;
|
|
color: #111827 !important;
|
|
}
|
|
|
|
html[data-theme="light"] .sl-nav__search :global(.pagefind-ui__search-input::placeholder),
|
|
html[data-theme="light"] .sl-nav__search :global(input::placeholder) {
|
|
color: #9ca3af !important;
|
|
}
|
|
|
|
.sl-nav__social {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.sl-nav__social-link {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.375rem;
|
|
color: var(--sl-color-gray-3);
|
|
transition: color 0.2s ease;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.sl-nav__social-link:hover {
|
|
color: var(--sl-color-white);
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* Light theme social links - better contrast */
|
|
html[data-theme="light"] .sl-nav__social-link {
|
|
color: #6b7280; /* Medium gray for icons */
|
|
}
|
|
|
|
html[data-theme="light"] .sl-nav__social-link:hover {
|
|
color: var(--sl-color-accent);
|
|
}
|
|
|
|
/* Theme selector container */
|
|
.sl-nav__theme {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
/* Hide only the "Select theme" label text, keep dropdown visible */
|
|
.sl-nav__theme :global(starlight-theme-select) {
|
|
position: relative;
|
|
}
|
|
|
|
/* Hide only the screen reader text */
|
|
.sl-nav__theme :global(starlight-theme-select .sr-only) {
|
|
position: absolute !important;
|
|
width: 1px !important;
|
|
height: 1px !important;
|
|
padding: 0 !important;
|
|
margin: -1px !important;
|
|
overflow: hidden !important;
|
|
clip: rect(0, 0, 0, 0) !important;
|
|
white-space: nowrap !important;
|
|
border: 0 !important;
|
|
}
|
|
|
|
/* Style the select dropdown with visible text */
|
|
.sl-nav__theme :global(starlight-theme-select select) {
|
|
font-size: 0.875rem !important;
|
|
color: var(--sl-color-text) !important;
|
|
background: transparent !important;
|
|
border: none !important;
|
|
cursor: pointer !important;
|
|
padding-right: 1.5rem !important;
|
|
}
|
|
|
|
/* Ensure options are visible with proper contrast */
|
|
.sl-nav__theme :global(starlight-theme-select option) {
|
|
font-size: 0.875rem !important;
|
|
color: var(--sl-color-black) !important;
|
|
background: var(--sl-color-white) !important;
|
|
}
|
|
|
|
/* Light mode select text color */
|
|
html[data-theme="light"] .sl-nav__theme :global(starlight-theme-select select) {
|
|
color: var(--sl-color-gray-5) !important;
|
|
}
|
|
|
|
/* Hide the icon to prevent overlap with text */
|
|
.sl-nav__theme :global(starlight-theme-select svg) {
|
|
display: none;
|
|
}
|
|
|
|
/* Hamburger menu styles */
|
|
.sl-nav__hamburger {
|
|
display: none;
|
|
position: relative; /* Changed from static to contain the menu properly */
|
|
}
|
|
|
|
.hamburger-button {
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--sl-color-white);
|
|
font-size: 1.5rem;
|
|
cursor: pointer;
|
|
padding: 0.375rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
/* Fix hamburger button visibility in light mode */
|
|
html[data-theme="light"] .hamburger-button {
|
|
color: #374151; /* Darker gray for better visibility */
|
|
}
|
|
|
|
.hamburger-button:hover {
|
|
color: var(--sl-color-text-accent);
|
|
}
|
|
|
|
html[data-theme="light"] .hamburger-button:hover {
|
|
color: var(--sl-color-text-accent);
|
|
}
|
|
|
|
.hamburger-menu {
|
|
display: none;
|
|
position: absolute;
|
|
top: calc(100% + 0.5rem); /* Add small gap below navbar */
|
|
right: 0;
|
|
background: var(--sl-color-bg-nav);
|
|
border: 1px solid var(--sl-color-hairline);
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
min-width: 200px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
z-index: 1000; /* Ensure menu stays above other content */
|
|
}
|
|
|
|
/* Light mode menu background */
|
|
html[data-theme="light"] .hamburger-menu {
|
|
background: var(--sl-color-bg);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.hamburger-menu.show {
|
|
display: block;
|
|
}
|
|
|
|
.hamburger-link {
|
|
display: block;
|
|
padding: 0.5rem 1rem;
|
|
color: var(--sl-color-gray-3);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease, background 0.2s ease;
|
|
border-radius: 0.25rem;
|
|
}
|
|
|
|
/* Light mode hamburger links */
|
|
html[data-theme="light"] .hamburger-link {
|
|
color: #374151; /* Consistent with nav links */
|
|
}
|
|
|
|
.hamburger-link:hover {
|
|
color: var(--sl-color-white);
|
|
background: var(--sl-color-gray-6);
|
|
}
|
|
|
|
html[data-theme="light"] .hamburger-link:hover {
|
|
color: var(--sl-color-accent);
|
|
background: var(--sl-color-gray-6);
|
|
}
|
|
|
|
.hamburger-social {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem 1rem;
|
|
margin-top: 0.5rem;
|
|
border-top: 1px solid var(--sl-color-hairline);
|
|
}
|
|
|
|
.hamburger-social-link {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.375rem;
|
|
color: var(--sl-color-gray-3);
|
|
transition: color 0.2s ease;
|
|
text-decoration: none;
|
|
}
|
|
|
|
html[data-theme="light"] .hamburger-social-link {
|
|
color: #6b7280; /* Consistent with nav social links */
|
|
}
|
|
|
|
.hamburger-social-link:hover {
|
|
color: var(--sl-color-white);
|
|
}
|
|
|
|
html[data-theme="light"] .hamburger-social-link:hover {
|
|
color: var(--sl-color-accent);
|
|
}
|
|
|
|
.hamburger-theme {
|
|
padding: 0.5rem 1rem;
|
|
margin-top: 0.5rem;
|
|
border-top: 1px solid var(--sl-color-hairline);
|
|
}
|
|
|
|
/* Search component integration styles */
|
|
.sl-nav__search :global(.pagefind-ui) {
|
|
--pagefind-ui-scale: 0.9;
|
|
}
|
|
|
|
.sl-nav__search :global(.pagefind-ui__search-input) {
|
|
background: var(--sl-color-gray-6);
|
|
border: 1px solid var(--sl-color-gray-5);
|
|
color: var(--sl-color-white);
|
|
border-radius: 0.375rem;
|
|
font-size: 0.875rem;
|
|
padding: 0.375rem 1rem;
|
|
transition: border-color 0.2s ease, background 0.2s ease;
|
|
}
|
|
|
|
/* Override any Starlight defaults for search in dark mode */
|
|
html[data-theme="dark"] .sl-nav__search :global(.pagefind-ui__search-input),
|
|
html[data-theme="dark"] .sl-nav__search :global(input[type="search"]),
|
|
html[data-theme="dark"] .sl-nav__search :global(input) {
|
|
background: #1f2937 !important;
|
|
background-color: #1f2937 !important;
|
|
border: 1px solid #374151 !important;
|
|
color: #f3f4f6 !important;
|
|
}
|
|
|
|
.sl-nav__search :global(.pagefind-ui__search-input:hover) {
|
|
border-color: var(--sl-color-gray-4);
|
|
background: var(--sl-color-gray-5);
|
|
}
|
|
|
|
.sl-nav__search :global(.pagefind-ui__search-input:focus) {
|
|
outline: none;
|
|
border-color: var(--sl-color-text-accent);
|
|
background: var(--sl-color-bg);
|
|
}
|
|
|
|
.sl-nav__search :global(.pagefind-ui__search-input::placeholder) {
|
|
color: var(--sl-color-gray-3);
|
|
}
|
|
|
|
/* Responsive styles */
|
|
|
|
/* Tablet view */
|
|
@media (max-width: 900px) {
|
|
.sl-nav__links {
|
|
gap: 1rem;
|
|
}
|
|
|
|
.sl-nav__link {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.sl-nav__social {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Mobile view - differentiate between docs and custom pages */
|
|
@media (max-width: 768px) {
|
|
.sl-nav {
|
|
padding: 0.5rem 1rem;
|
|
}
|
|
|
|
.sl-nav__center {
|
|
margin: 0 0.5rem;
|
|
}
|
|
|
|
/* For docs pages - hide custom nav items on mobile, let Starlight handle it */
|
|
.sl-nav__links.docs-page {
|
|
display: none;
|
|
}
|
|
|
|
.sl-nav__api-link.docs-page {
|
|
display: none;
|
|
}
|
|
|
|
/* For custom pages - hide nav items but show hamburger */
|
|
.sl-nav__links.custom-page {
|
|
display: none;
|
|
}
|
|
|
|
.sl-nav__api-link.custom-page {
|
|
display: none;
|
|
}
|
|
|
|
.sl-nav__theme {
|
|
display: none;
|
|
}
|
|
|
|
/* Show hamburger only for custom pages */
|
|
.sl-nav__hamburger {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
/* Small mobile */
|
|
@media (max-width: 640px) {
|
|
.sl-nav {
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.sl-nav__left {
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.sl-nav__center {
|
|
flex: 1;
|
|
margin: 0 0.5rem;
|
|
}
|
|
|
|
.sl-nav__end {
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.sl-nav__title {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.sl-nav__search :global(.pagefind-ui__search-input) {
|
|
padding: 0.25rem 0.75rem;
|
|
font-size: 0.8125rem;
|
|
}
|
|
}
|
|
|
|
/* Make sure content doesn't jump */
|
|
:global(body) {
|
|
padding-top: 0;
|
|
}
|
|
|
|
:global(.sl-layout) {
|
|
padding-top: 0;
|
|
}
|
|
|
|
/* Adjust main content positioning */
|
|
:global(main.sl-content) {
|
|
margin-top: 0;
|
|
}
|
|
|
|
:global(.sl-content__inner) {
|
|
padding-top: 1rem;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Add active state highlighting based on current page
|
|
const currentPath = window.location.pathname;
|
|
const links = document.querySelectorAll('.sl-nav__link');
|
|
|
|
links.forEach(link => {
|
|
const href = link.getAttribute('href');
|
|
if (href) {
|
|
// Check for exact match or if current path starts with the link href
|
|
if (currentPath === href ||
|
|
(href !== '/' && currentPath.startsWith(href))) {
|
|
link.classList.add('active');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Theme handling for custom pages
|
|
// Listen for theme changes from Starlight's ThemeSelect
|
|
const observeThemeChanges = () => {
|
|
const observer = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutation) => {
|
|
if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {
|
|
const newTheme = document.documentElement.getAttribute('data-theme');
|
|
// Theme is already set by Starlight, we just need to ensure it persists
|
|
localStorage.setItem('starlight-theme', newTheme === 'dark' ? 'dark' : 'light');
|
|
}
|
|
});
|
|
});
|
|
|
|
observer.observe(document.documentElement, {
|
|
attributes: true,
|
|
attributeFilter: ['data-theme']
|
|
});
|
|
};
|
|
|
|
observeThemeChanges();
|
|
|
|
// Hamburger menu functionality (only for custom pages)
|
|
const hamburgerBtn = document.getElementById('hamburger-btn');
|
|
const hamburgerMenu = document.getElementById('hamburger-menu');
|
|
|
|
if (hamburgerBtn && hamburgerMenu) {
|
|
// Toggle menu on button click
|
|
hamburgerBtn.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
hamburgerMenu.classList.toggle('show');
|
|
});
|
|
|
|
// Close menu when clicking outside
|
|
document.addEventListener('click', function(e) {
|
|
if (!hamburgerBtn.contains(e.target) && !hamburgerMenu.contains(e.target)) {
|
|
hamburgerMenu.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
// Close menu when clicking a link
|
|
const hamburgerLinks = hamburgerMenu.querySelectorAll('.hamburger-link');
|
|
hamburgerLinks.forEach(link => {
|
|
link.addEventListener('click', function() {
|
|
hamburgerMenu.classList.remove('show');
|
|
});
|
|
});
|
|
|
|
// Close menu on escape key
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape' && hamburgerMenu.classList.contains('show')) {
|
|
hamburgerMenu.classList.remove('show');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|