PageSourceSearch

https://boltscribe.ink/shared/components/header.js

js boltscribe.ink collected 2026-10-02 01:57:07 UTC 3,107 bytes, 90 lines download raw bytes

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.