All files / website/src/layout Layout.js

0% Statements 0/274
0% Branches 0/1
0% Functions 0/1
0% Lines 0/274

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
// Layout.js - shared layout for static site
export function Layout({
  title = 'Coherent.js',
  sidebar = [],
  currentPath = '/',
  baseHref = '/',
}) {
  return {
    html: {
      children: [
        {
          head: {
            children: [
              { meta: { charset: 'utf-8' } },
              {
                meta: {
                  name: 'viewport',
                  content: 'width=device-width, initial-scale=1',
                },
              },
              {
                meta: {
                  name: 'description',
                  content:
                    'Coherent.js — Lightweight, fast SSR with object-based components and great DX.',
                },
              },
              { meta: { name: 'theme-color', content: '#0b0e14' } },
              { title: { text: title } },
              { base: { href: baseHref } },
              {
                link: {
                  rel: 'icon',
                  type: 'image/svg+xml',
                  href: './favicon.svg',
                },
              },
              { link: { rel: 'stylesheet', href: './styles.css' } },
              ...(currentPath === 'playground'
                ? [{ script: { src: './playground.js', defer: true } }]
                : []),
              ...(currentPath === 'performance'
                ? [{ script: { src: './performance.js', defer: true } }]
                : []),
            ],
          },
        },
        {
          body: {
            children: [
              {
                header: {
                  className: 'site-header',
                  children: [
                    {
                      a: {
                        className: 'logo-link',
                        href: baseHref,
                        children: [
                          {
                            img: {
                              src: './coherent-logo.svg',
                              alt: 'Coherent.js',
                              className: 'logo-svg',
                              width: '180',
                              height: '50',
                            },
                          },
                        ],
                      },
                    },
                    {
                      button: {
                        className: 'menu-button',
                        'aria-label': 'Toggle menu',
                        text: '☰',
                        onclick: 'document.body.classList.toggle("menu-open");',
                      },
                    },
                    {
                      nav: {
                        className: 'top-nav',
                        children: [
                          {
                            a: {
                              href: baseHref,
                              className: currentPath === '' ? 'active' : '',
                              text: 'Home',
                            },
                          },
                          {
                            a: {
                              href: 'docs',
                              className: currentPath.startsWith('docs')
                                ? 'active'
                                : '',
                              text: 'Docs',
                            },
                          },
                          {
                            a: {
                              href: 'examples',
                              className: currentPath.startsWith('examples')
                                ? 'active'
                                : '',
                              text: 'Examples',
                            },
                          },
                          {
                            a: {
                              href: 'playground',
                              className: currentPath.startsWith('playground')
                                ? 'active'
                                : '',
                              text: 'Playground',
                            },
                          },
                          {
                            a: {
                              href: 'performance',
                              className: currentPath.startsWith('performance')
                                ? 'active'
                                : '',
                              text: 'Performance',
                            },
                          },
                          {
                            a: {
                              href: 'coverage',
                              className: currentPath.startsWith('coverage')
                                ? 'active'
                                : '',
                              text: 'Coverage',
                            },
                          },
                          {
                            a: {
                              href: 'changelog',
                              className: currentPath.startsWith('changelog')
                                ? 'active'
                                : '',
                              text: 'Changelog',
                            },
                          },
                        ],
                      },
                    },
                    {
                      div: {
                        className: 'header-tools',
                        children: [
                          {
                            input: {
                              type: 'search',
                              placeholder: 'Search docs…',
                              className: 'search',
                            },
                          },
                          {
                            button: {
                              className: 'button',
                              id: 'theme-toggle',
                              text: 'Theme',
                              onclick: `
                    var current = document.documentElement.getAttribute('data-theme') || 'dark';
                    var next = current === 'light' ? 'dark' : 'light';
                    document.documentElement.setAttribute('data-theme', next);
                    try { localStorage.setItem('theme', next); } catch(e) {}
                  `,
                            },
                          },
                        ],
                      },
                    },
                  ],
                },
              },
              {
                main: {
                  className: (function () {
                    const isDocs =
                      typeof currentPath === 'string' &&
                      currentPath.startsWith('docs');
                    return isDocs ? 'container docs' : 'container single';
                  })(),
                  children: (function () {
                    const isDocs =
                      typeof currentPath === 'string' &&
                      currentPath.startsWith('docs');
                    const nodes = [];
                    if (isDocs) {
                      nodes.push({
                        aside: {
                          className: 'sidebar',
                          children: buildSidebar(sidebar),
                        },
                      });
                    }
                    nodes.push({
                      article: {
                        className: 'content',
                        children: [
                          isDocs
                            ? {
                                nav: {
                                  className: 'breadcrumbs',
                                  text: '[[[COHERENT_BREADCRUMBS_PLACEHOLDER]]]',
                                },
                              }
                            : null,
                          {
                            div: {
                              id: 'coherent-content-placeholder',
                              text: '[[[COHERENT_CONTENT_PLACEHOLDER]]]',
                            },
                          },
                        ].filter(Boolean),
                      },
                    });
                    if (isDocs) {
                      nodes.push({
                        aside: {
                          className: 'toc',
                          children: [
                            {
                              div: {
                                id: 'coherent-toc-placeholder',
                                text: '[[[COHERENT_TOC_PLACEHOLDER]]]',
                              },
                            },
                          ],
                        },
                      });
                    }
                    return nodes;
                  })(),
                },
              },
              {
                footer: {
                  className: 'site-footer',
                  children: [
                    {
                      p: {
                        text: `© ${new Date().getFullYear()} Coherent.js`,
                      },
                    },
                  ],
                },
              },
            ],
          },
        },
      ],
    },
  };
}
 
function buildSidebar(groups) {
  if (!Array.isArray(groups) || groups.length === 0) return [];
  return groups.map((group) => ({
    section: {
      children: [
        { h4: { text: group.title } },
        {
          ul: {
            children: (group.items || []).map((item) => ({
              li: { children: [{ a: { href: item.href, text: item.label } }] },
            })),
          },
        },
      ],
    },
  }));
}