1import { html } from '../lib/html.js'; 2 3/** 4 * Header component - html-first pattern for SSR/CSR compatibility 5 * 6 * @param {Function} html - html template function (uhtml or uhtml-ssr) 7 * @param {Object} state - Application state 8 * @param {Object} state.route - Route state 9 * @param {string} state.route.path - Current path 10 * @param {Object} state.auth - Auth state 11 * @param {boolean} state.auth.isLoggedIn - Whether user is logged in 12 * @param {Object} state.auth.user - User data 13 * @param {string} state.auth.user.email - User email 14 * @param {Object} actions - Action handlers 15 * @param {Function} actions.navigate - Navigation handler 16 * @param {Function} actions.onLogout - Logout handler 17 */ 18export const Header = (html, state, actions) => { 19 const { path } = state.route || { path: '/' }; 20 const { isLoggedIn, user } = state.auth || { isLoggedIn: false, user: null }; 21 const userEmail = user?.email || ''; 22 23 // Determine header type based on path 24 // No header for landing page (it has its own header) 25 if (path === '/') return null; 26 27 // Auth header for authenticated pages 28 const authPaths = ['/dashboard', '/subscription', '/settings']; 29 const isAuthPath = authPaths.includes(path); 30 31 // Minimal header for auth pages 32 const minimalPaths = ['/login', '/register', '/authorize-device', '/auth/reset-password']; 33 const isMinimalPath = minimalPaths.includes(path); 34 35 // Create click handler function if actions.navigate is provided 36 const createClickHandler = (targetPath) => actions.navigate ? (e) => { 37 e.preventDefault(); 38 actions.navigate(targetPath); 39 } : null; 40 41 const Logo = () => html` 42 <a href="/" ?onclick=${createClickHandler('/')}> 43 <img src="/assets/logo-quill.svg" alt="Bolt Scribe" width="40" height="40"> 44 <span>Bolt Scribe</span> 45 </a> 46 `; 47 48 // Minimal header (login, register, password reset, authorize device) 49 if (isMinimalPath) { 50 return html` 51 <header> 52 ${Logo()} 53 </header> 54 `; 55 } 56 57 // Auth header (dashboard, subscription, settings) 58 if (isAuthPath) { 59 return html` 60 <header> 61 ${Logo()} 62 <nav> 63 <a href="/dashboard" ?onclick=${createClickHandler('/dashboard')}>Dashboard</a> 64 <a href="/subscription" ?onclick=${createClickHandler('/subscription')}>Subscription</a> 65 <a href="/settings" ?onclick=${createClickHandler('/settings')}>Settings</a> 66 <span>${userEmail}</span> 67 <button onclick=${actions.onLogout || null}>Sign Out</button> 68 </nav> 69 </header> 70 `; 71 } 72 73 // Public header (privacy, terms, etc.) 74 return html` 75 <header> 76 ${Logo()} 77 <nav> 78 <a href="/#features">Features</a> 79 <a href="/#pricing">Pricing</a> 80 ${isLoggedIn 81 ? html`<a href="/dashboard" ?onclick=${createClickHandler('/dashboard')}>Go to Dashboard</a>` 82 : html` 83 <a href="/login" ?onclick=${createClickHandler('/login')}>Sign In</a> 84 <a href="/register" ?onclick=${createClickHandler('/register')}>Get Started</a> 85 ` 86 } 87 </nav> 88 </header> 89 `; 90};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.