@nexpress/theme-default 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/footer.tsx","../src/header.tsx","../src/shell.tsx","../src/styles.ts","../src/templates/page-default.tsx","../src/templates/page-landing.tsx","../src/templates/page-sidebar.tsx","../src/templates/page-wide.tsx","../src/templates/post-default.tsx","../src/components/post-card.tsx","../src/templates/post-list.tsx","../src/components/social-links.tsx","../src/components/pagination.tsx"],"sourcesContent":["import { defineTheme } from \"@nexpress/theme\";\n\nimport { DefaultFooter } from \"./footer.js\";\nimport { DefaultHeader } from \"./header.js\";\nimport { DefaultShell } from \"./shell.js\";\nimport { defaultThemeCss } from \"./styles.js\";\nimport { PageDefaultTemplate } from \"./templates/page-default.js\";\nimport { PageLandingTemplate } from \"./templates/page-landing.js\";\nimport { PageSidebarTemplate } from \"./templates/page-sidebar.js\";\nimport { PageWideTemplate } from \"./templates/page-wide.js\";\nimport { PostDefaultTemplate } from \"./templates/post-default.js\";\nimport { PostListTemplate } from \"./templates/post-list.js\";\n\n/**\n * `@nexpress/theme-default` — v0.1-era baseline theme.\n *\n * **Status (v0.2):** kept for back-compat. The v0.2 reference\n * themes are `theme-magazine` / `theme-docs` / `theme-portfolio`\n * — they exercise the new contract surfaces (manifest.requires,\n * settingsSchema, blocks, patterns, navLocations, archives,\n * routes, seo). New sites should start from one of those.\n *\n * `theme-default` doesn't declare v0.2 surfaces: operators using\n * it skip the no-code-customization workflow (no admin auto-\n * form for theme settings, no `theme:install` data-shape\n * checks, no theme-shipped blocks/patterns). It remains a valid\n * `defineTheme` caller — production sites pinned to v0.1 keep\n * working — but consider migrating to a v0.2 reference if you\n * want operator-tunable settings.\n *\n * Production-grade defaults: sticky header with a mobile drawer,\n * a four-column footer (brand / sitemap / resources / newsletter)\n * with optional social icons, post list / detail templates that\n * surface excerpt / cover / tags / reading time, and three page\n * templates (default centered column, edge-to-edge wide, marketing\n * landing, doc-style sidebar). All CSS is theme-owned so the\n * framework drops it as a single `<style data-np-theme=\"default\">`\n * tag at SSR time — no extra round-trip.\n *\n * Sites brand by overriding the design tokens (`--np-color-*` etc).\n */\nexport const defaultTheme = defineTheme({\n manifest: {\n id: \"default\",\n name: \"NexPress Default\",\n version: \"0.1.0\",\n description:\n \"Production-grade baseline theme. Sticky header with mobile drawer, four-column footer, blog list / detail templates, landing + sidebar page variants, dark-mode parity, social + newsletter slots in the footer.\",\n author: { name: \"NexPress\" },\n nexpress: { minVersion: \"0.1.0\" },\n },\n impl: {\n shell: DefaultShell,\n slots: {\n header: DefaultHeader,\n footer: DefaultFooter,\n },\n css: defaultThemeCss,\n templates: {\n pages: {\n default: {\n label: \"Default\",\n description: \"Centered content container with the standard reading width.\",\n component: PageDefaultTemplate,\n },\n wide: {\n label: \"Wide\",\n description:\n \"Edge-to-edge layout with no max-width. Best for galleries and immersive media.\",\n component: PageWideTemplate,\n },\n landing: {\n label: \"Landing\",\n description:\n \"Marketing-style template — full-bleed hero from the first block, then sections render edge-to-edge so Hero / FeatureGrid / CTA blocks span the viewport.\",\n component: PageLandingTemplate,\n },\n sidebar: {\n label: \"Sidebar\",\n description:\n \"Two-column layout with a sticky right sidebar. Suited to docs / knowledge bases. Sites can populate the aside with a `sidebar` field on their pages collection.\",\n component: PageSidebarTemplate,\n },\n },\n posts: {\n default: {\n label: \"Article\",\n description:\n \"Centered article column with cover image, tags, byline, reading time, and Lexical body.\",\n component: PostDefaultTemplate,\n },\n list: {\n label: \"List view\",\n description:\n \"Blog-index template: one feature card on top, then a 3-column grid (collapses on phones). Suitable for any collection that ships PostCard-shaped docs.\",\n component: PostListTemplate,\n },\n },\n },\n },\n});\n\nexport { DefaultShell } from \"./shell.js\";\nexport { DefaultHeader } from \"./header.js\";\nexport { DefaultFooter } from \"./footer.js\";\nexport { MemberStatusWidget } from \"./components/member-status-widget.js\";\nexport { MobileNav } from \"./components/mobile-nav.js\";\nexport { SocialLinks } from \"./components/social-links.js\";\nexport { NewsletterForm } from \"./components/newsletter-form.js\";\nexport { PostCard, type PostCardDoc, type PostCardProps } from \"./components/post-card.js\";\nexport { Pagination, type PaginationProps } from \"./components/pagination.js\";\nexport { PageLandingTemplate } from \"./templates/page-landing.js\";\nexport { PageSidebarTemplate } from \"./templates/page-sidebar.js\";\nexport { PostDefaultTemplate } from \"./templates/post-default.js\";\nexport { PostListTemplate } from \"./templates/post-list.js\";\nexport { defaultThemeCss } from \"./styles.js\";\n","/**\n * The default theme's footer surface. Re-exported as\n * `DefaultFooter` for the slot wiring; the actual layout lives\n * in `components/footer-columns.tsx` so the slot stays a thin\n * pass-through and the footer can be embedded by sites that\n * compose their own shell.\n */\nexport { DefaultFooter } from \"./components/footer-columns.js\";\n","import { getI18nConfig } from \"@nexpress/core\";\nimport type { NpNavItem } from \"@nexpress/core\";\nimport { getCachedNavigation, resolveAvailableLocales } from \"@nexpress/next\";\nimport { headers } from \"next/headers\";\nimport Link from \"next/link\";\n\nimport { DarkModeToggle } from \"./components/dark-mode-toggle.js\";\nimport { LanguagePicker } from \"./components/language-picker.js\";\nimport { MemberStatusWidget } from \"./components/member-status-widget.js\";\nimport { MobileNav } from \"./components/mobile-nav.js\";\n\n/**\n * Default theme header — server component. Reads the\n * `header` navigation menu and renders the desktop / mobile\n * surfaces in one go:\n *\n * - Desktop (≥768px): inline link list, search bar, lang\n * picker, dark toggle, member widget.\n * - Mobile (<768px): the inline list collapses (CSS-only) and\n * a hamburger button opens a slide-in drawer (`<MobileNav />`,\n * a small client component that owns its own open/closed\n * state). The same nav items feed both surfaces — markup is\n * server-rendered once and reused.\n *\n * The header is `position: sticky` (see styles.ts) so the search\n * + member widget stay reachable as the page scrolls.\n */\nexport async function DefaultHeader() {\n const headerNav = await getCachedNavigation(\"header\");\n const i18n = getI18nConfig();\n const showLanguagePicker = (i18n?.locales.length ?? 0) > 1;\n\n let availableLocales: string[] | null = null;\n if (showLanguagePicker) {\n const headerList = await headers();\n const pathname = headerList.get(\"x-np-pathname\");\n if (pathname) {\n try {\n availableLocales = await resolveAvailableLocales(pathname);\n } catch {\n availableLocales = null;\n }\n }\n }\n\n return (\n <header className=\"np-site-header\">\n <div className=\"np-site-header-inner\">\n <Link href=\"/\" className=\"np-site-logo\">\n NexPress\n </Link>\n <nav className=\"np-site-nav-desktop\" aria-label=\"Primary\">\n <ul className=\"np-site-nav\">\n {headerNav.map((item: NpNavItem, index: number) => (\n <li key={`nav-${index.toString()}`} className=\"np-site-nav-item\">\n {item.url ? <Link href={item.url}>{item.label}</Link> : <span>{item.label}</span>}\n {item.children && item.children.length > 0 ? (\n <ul className=\"np-site-subnav\">\n {item.children.map((child: NpNavItem, childIndex: number) => (\n <li key={`nav-${index.toString()}-${childIndex.toString()}`}>\n {child.url ? <Link href={child.url}>{child.label}</Link> : <span>{child.label}</span>}\n </li>\n ))}\n </ul>\n ) : null}\n </li>\n ))}\n </ul>\n </nav>\n <div className=\"np-site-header-tools\">\n <form\n action=\"/search\"\n method=\"GET\"\n role=\"search\"\n className=\"np-site-search\"\n >\n <label className=\"sr-only\" htmlFor=\"np-site-search-input\">\n Search\n </label>\n <input\n id=\"np-site-search-input\"\n type=\"search\"\n name=\"q\"\n placeholder=\"Search…\"\n autoComplete=\"off\"\n className=\"np-site-search-input\"\n />\n </form>\n {showLanguagePicker && i18n ? (\n <LanguagePicker\n locales={i18n.locales}\n availableLocales={availableLocales ?? undefined}\n />\n ) : null}\n <DarkModeToggle />\n <MemberStatusWidget />\n <MobileNav items={headerNav} />\n </div>\n </div>\n </header>\n );\n}\n","import { NpColorSchemeScript } from \"@nexpress/theme\";\nimport type { ReactNode } from \"react\";\n\nimport type { NpThemeShellProps } from \"@nexpress/theme\";\n\n/**\n * Default theme shell — wraps every (site) route. The shell\n * also owns this theme's color-mode policy: it mounts\n * `<NpColorSchemeScript />` so the saved `np-color-scheme`\n * cookie / `prefers-color-scheme` choice is applied to\n * `<html data-theme=\"…\">` before first paint, and the dark\n * variants ride on the rules in `defaultThemeCss`.\n *\n * Dark mode is no longer auto-wired by the framework — every\n * theme decides whether to ship light/dark switching, what\n * tokens it flips, and how the toggle UX looks. Themes that\n * want a different policy (no dark mode, time-of-day,\n * seasonal palette, …) simply omit this script and the\n * dark CSS overrides.\n */\nexport function DefaultShell({ children }: NpThemeShellProps): ReactNode {\n return (\n <>\n <NpColorSchemeScript />\n {children}\n </>\n );\n}\n","/**\n * Layout-level CSS for `@nexpress/theme-default`. Production polish\n * lives here: sticky header with mobile drawer, four-column footer\n * with social + newsletter, post detail / list, page templates\n * (default / wide / landing / sidebar), pagination, and a typography\n * ramp that holds together across page widths.\n *\n * Design tokens come from `--np-color-*` / `--np-radius-*` /\n * `--np-font-*` (set in apps/web/src/app/globals.css and switched\n * by `[data-theme=\"dark\"]` further down). Themes that want a\n * different palette override the same custom properties — this\n * file is structural.\n *\n * The framework injects this string as a `<style data-np-theme=\"default\">`\n * tag at SSR time so the rules race the document with no extra\n * stylesheet round-trip.\n */\nexport const defaultThemeCss = `\n/* ----------------------------------------------------------------\n * Typography ramp\n * --------------------------------------------------------------- */\n.np-page,\n.np-post,\n.np-post-list {\n --np-content-max: 1100px;\n --np-content-max-wide: 1300px;\n}\n.np-page h1,\n.np-post-title,\n.np-post-list-header h1 {\n font-size: clamp(2rem, 4vw, 2.75rem);\n line-height: 1.15;\n letter-spacing: -0.02em;\n font-weight: 800;\n margin: 0 0 1rem;\n}\n.np-page h2,\n.np-post-body h2 {\n font-size: clamp(1.4rem, 2.4vw, 1.75rem);\n letter-spacing: -0.015em;\n margin: 2.5rem 0 1rem;\n}\n.np-page h3,\n.np-post-body h3 {\n font-size: 1.25rem;\n margin: 2rem 0 0.75rem;\n}\n.np-page p,\n.np-post-body p {\n font-size: 1.0625rem;\n line-height: 1.7;\n margin: 0 0 1rem;\n}\n.np-post-body a {\n color: var(--np-color-primary, #4f46e5);\n text-decoration: underline;\n text-underline-offset: 0.2em;\n}\n.np-post-body code {\n background: var(--np-color-muted, #f1f5f9);\n padding: 0.1em 0.35em;\n border-radius: 4px;\n font-size: 0.95em;\n}\n.np-post-body pre {\n background: var(--np-color-muted, #f1f5f9);\n padding: 1rem;\n border-radius: var(--np-radius-md, 0.5rem);\n overflow-x: auto;\n font-size: 0.875rem;\n line-height: 1.6;\n}\n.np-post-body blockquote {\n border-inline-start: 3px solid var(--np-color-primary, #4f46e5);\n margin: 1.5rem 0;\n padding: 0.25rem 0 0.25rem 1rem;\n color: var(--np-color-muted-foreground, #64748b);\n font-style: italic;\n}\n.np-post-body img {\n max-width: 100%;\n height: auto;\n border-radius: var(--np-radius-md, 0.5rem);\n}\n\n/* ----------------------------------------------------------------\n * Header — sticky desktop bar + mobile drawer\n * --------------------------------------------------------------- */\n.np-site-header {\n position: sticky;\n top: 0;\n z-index: 30;\n background: color-mix(in oklch, var(--np-color-background, #fff) 92%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border-bottom: 1px solid var(--np-color-border, #e5e7eb);\n}\n.np-site-header-inner {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n max-width: 1200px;\n margin: 0 auto;\n padding: 0.85rem 1.5rem;\n}\n.np-site-logo {\n font-weight: 800;\n font-size: 1.15rem;\n text-decoration: none;\n color: inherit;\n letter-spacing: -0.02em;\n white-space: nowrap;\n}\n.np-site-nav-desktop {\n flex: 1;\n}\n.np-site-nav {\n display: flex;\n align-items: center;\n gap: 1.4rem;\n list-style: none;\n padding: 0;\n margin: 0;\n}\n.np-site-nav a {\n color: var(--np-color-muted-foreground, #64748b);\n text-decoration: none;\n font-size: 0.9375rem;\n font-weight: 500;\n transition: color 0.15s ease;\n}\n.np-site-nav a:hover {\n color: var(--np-color-foreground, #0f172a);\n}\n/* Sub-menu — desktop hover dropdown. Hidden until parent <li> is\n * hovered or focus enters the subtree. Shallow drop, neutral\n * surface so it inherits theme tokens automatically. */\n.np-site-nav-item {\n position: relative;\n}\n.np-site-subnav {\n position: absolute;\n top: 100%;\n left: 0;\n display: none;\n min-width: 11rem;\n padding: 0.5rem 0;\n margin: 0;\n list-style: none;\n background: var(--np-color-card, #fff);\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n box-shadow: 0 4px 16px -8px rgba(0, 0, 0, 0.08);\n z-index: 10;\n}\n.np-site-nav-item:hover > .np-site-subnav,\n.np-site-nav-item:focus-within > .np-site-subnav {\n display: block;\n}\n.np-site-subnav li {\n padding: 0;\n}\n.np-site-subnav a {\n display: block;\n padding: 0.4rem 1rem;\n font-size: 0.875rem;\n}\n.np-site-header-tools {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-inline-start: auto;\n}\n.np-site-search {\n display: contents;\n}\n.np-site-search-input {\n padding: 0.4rem 0.75rem;\n font: inherit;\n font-size: 0.875rem;\n color: inherit;\n background: var(--np-color-muted, #f8fafc);\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n width: 12rem;\n transition: border-color 0.15s ease, box-shadow 0.15s ease, width 0.15s ease;\n}\n.np-site-search-input:focus {\n outline: none;\n border-color: var(--np-color-ring, #4f46e5);\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--np-color-ring, #4f46e5) 20%, transparent);\n width: 14rem;\n}\n\n/* Mobile drawer machinery */\n.np-mobile-nav-toggle {\n display: none;\n align-items: center;\n justify-content: center;\n width: 2.25rem;\n height: 2.25rem;\n padding: 0;\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n.np-mobile-nav-toggle:hover {\n background: var(--np-color-muted, #f8fafc);\n}\n.np-mobile-nav-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: 40;\n}\n.np-mobile-nav-drawer {\n position: fixed;\n top: 0;\n inset-inline-end: 0;\n width: min(20rem, 85vw);\n height: 100dvh;\n background: var(--np-color-background, #fff);\n border-inline-start: 1px solid var(--np-color-border, #e5e7eb);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.2s ease;\n display: flex;\n flex-direction: column;\n}\n.np-mobile-nav-drawer[data-open=\"true\"] {\n transform: translateX(0);\n}\n.np-mobile-nav-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.25rem;\n border-bottom: 1px solid var(--np-color-border, #e5e7eb);\n}\n.np-mobile-nav-drawer-label {\n font-weight: 700;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n font-size: 0.75rem;\n color: var(--np-color-muted-foreground, #64748b);\n}\n.np-mobile-nav-close {\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 0.25rem;\n border-radius: var(--np-radius-md, 0.5rem);\n}\n.np-mobile-nav-close:hover {\n background: var(--np-color-muted, #f8fafc);\n}\n.np-mobile-nav-list {\n list-style: none;\n margin: 0;\n padding: 0.75rem 0;\n overflow-y: auto;\n flex: 1;\n}\n.np-mobile-subnav,\n.np-site-footer-subnav {\n list-style: none;\n margin: 0;\n padding-left: 1.25rem;\n}\n.np-mobile-subnav a {\n font-size: 0.9375rem;\n}\n.np-site-footer-subnav a {\n font-size: 0.85rem;\n opacity: 0.85;\n}\n.np-mobile-nav-list a {\n display: block;\n padding: 0.85rem 1.25rem;\n text-decoration: none;\n color: inherit;\n font-size: 1rem;\n border-bottom: 1px solid color-mix(in oklch, var(--np-color-border, #e5e7eb) 50%, transparent);\n}\n.np-mobile-nav-list a:hover {\n background: var(--np-color-muted, #f8fafc);\n}\n\n@media (max-width: 768px) {\n .np-site-nav-desktop,\n .np-site-search,\n .np-site-search-input {\n display: none;\n }\n .np-mobile-nav-toggle {\n display: inline-flex;\n }\n}\n@media (min-width: 769px) {\n .np-mobile-nav-drawer,\n .np-mobile-nav-overlay {\n display: none;\n }\n}\n\n/* ----------------------------------------------------------------\n * Footer — 4-column grid, social strip, newsletter signup\n * --------------------------------------------------------------- */\n.np-site-footer {\n margin-top: 6rem;\n background: var(--np-color-muted, #f8fafc);\n border-top: 1px solid var(--np-color-border, #e5e7eb);\n}\n.np-site-footer-inner {\n max-width: 1200px;\n margin: 0 auto;\n padding: 3rem 1.5rem 1.5rem;\n}\n.np-site-footer-grid {\n display: grid;\n grid-template-columns: 1.4fr 1fr 1fr 1.2fr;\n gap: 2.5rem;\n align-items: start;\n}\n@media (max-width: 768px) {\n .np-site-footer-grid {\n grid-template-columns: 1fr 1fr;\n gap: 2rem;\n }\n .np-site-footer-brand,\n .np-site-footer-subscribe {\n grid-column: span 2;\n }\n}\n@media (max-width: 480px) {\n .np-site-footer-grid {\n grid-template-columns: 1fr;\n }\n .np-site-footer-brand,\n .np-site-footer-subscribe {\n grid-column: span 1;\n }\n}\n.np-site-footer-col { min-width: 0; }\n.np-site-footer-logo {\n font-weight: 800;\n font-size: 1.15rem;\n text-decoration: none;\n color: inherit;\n letter-spacing: -0.02em;\n}\n.np-site-footer-tagline {\n margin: 0.5rem 0 1rem;\n color: var(--np-color-muted-foreground, #64748b);\n font-size: 0.9rem;\n line-height: 1.5;\n}\n.np-site-footer-heading {\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.12em;\n color: var(--np-color-muted-foreground, #64748b);\n margin: 0 0 0.85rem;\n font-weight: 700;\n}\n.np-site-footer-links {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 0.55rem;\n font-size: 0.9rem;\n}\n.np-site-footer-links a {\n color: var(--np-color-muted-foreground, #64748b);\n text-decoration: none;\n transition: color 0.15s ease;\n}\n.np-site-footer-links a:hover {\n color: var(--np-color-foreground, #0f172a);\n}\n.np-site-footer-social {\n list-style: none;\n margin: 1rem 0 0;\n padding: 0;\n display: flex;\n gap: 0.5rem;\n}\n.np-site-footer-social a {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.25rem;\n height: 2.25rem;\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n color: var(--np-color-muted-foreground, #64748b);\n text-decoration: none;\n transition: all 0.15s ease;\n}\n.np-site-footer-social a:hover {\n color: var(--np-color-foreground, #0f172a);\n border-color: var(--np-color-foreground, #0f172a);\n transform: translateY(-1px);\n}\n.np-site-footer-subscribe-blurb {\n margin: 0 0 0.75rem;\n font-size: 0.85rem;\n color: var(--np-color-muted-foreground, #64748b);\n}\n.np-site-footer-subscribe-form {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.np-site-footer-subscribe-form input[type=\"email\"] {\n padding: 0.55rem 0.75rem;\n font: inherit;\n font-size: 0.9rem;\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n background: var(--np-color-background, #fff);\n color: inherit;\n}\n.np-site-footer-subscribe-form input[type=\"email\"]:focus {\n outline: none;\n border-color: var(--np-color-ring, #4f46e5);\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--np-color-ring, #4f46e5) 20%, transparent);\n}\n.np-site-footer-subscribe-form button {\n padding: 0.55rem 0.75rem;\n font: inherit;\n font-size: 0.9rem;\n font-weight: 600;\n background: var(--np-color-foreground, #0f172a);\n color: var(--np-color-background, #fff);\n border: none;\n border-radius: var(--np-radius-md, 0.5rem);\n cursor: pointer;\n transition: opacity 0.15s ease;\n}\n.np-site-footer-subscribe-form button:hover { opacity: 0.9; }\n.np-site-footer-subscribe-form button:disabled { opacity: 0.6; cursor: progress; }\n.np-site-footer-subscribe-success {\n margin: 0;\n font-size: 0.9rem;\n color: var(--np-color-foreground, #0f172a);\n background: color-mix(in oklch, var(--np-color-primary, #4f46e5) 12%, transparent);\n padding: 0.6rem 0.75rem;\n border-radius: var(--np-radius-md, 0.5rem);\n}\n.np-site-footer-subscribe-error {\n margin: 0;\n font-size: 0.8rem;\n color: var(--np-color-destructive, #b91c1c);\n}\n.np-site-footer-bottom {\n margin-top: 2.5rem;\n padding-top: 1.25rem;\n border-top: 1px solid color-mix(in oklch, var(--np-color-border, #e5e7eb) 70%, transparent);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n flex-wrap: wrap;\n}\n.np-site-footer-copy {\n margin: 0;\n font-size: 0.8rem;\n color: var(--np-color-muted-foreground, #64748b);\n}\n.np-site-footer-meta {\n display: flex;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: 1rem;\n font-size: 0.8rem;\n}\n.np-site-footer-meta a {\n color: var(--np-color-muted-foreground, #64748b);\n text-decoration: none;\n}\n.np-site-footer-meta a:hover { color: var(--np-color-foreground, #0f172a); }\n\n/* ----------------------------------------------------------------\n * Page templates: default, wide, landing, sidebar\n * --------------------------------------------------------------- */\n.np-page-default {\n max-width: var(--np-content-max);\n margin: 0 auto;\n padding: 3rem 1.5rem 4rem;\n}\n.np-page-wide {\n max-width: none;\n margin: 0;\n padding: 0;\n}\n.np-page-landing {\n max-width: none;\n margin: 0;\n padding: 0;\n}\n.np-page-landing-blocks > * + * { margin-top: 0; }\n.np-page-landing-hero {\n max-width: var(--np-content-max-wide);\n margin: 0 auto;\n padding: 6rem 1.5rem 4rem;\n text-align: center;\n}\n.np-page-landing-intro {\n font-size: clamp(1.1rem, 1.6vw, 1.25rem);\n color: var(--np-color-muted-foreground, #64748b);\n max-width: 38rem;\n margin: 1rem auto 0;\n line-height: 1.6;\n}\n.np-page-sidebar {\n max-width: var(--np-content-max-wide);\n margin: 0 auto;\n padding: 3rem 1.5rem 4rem;\n display: grid;\n grid-template-columns: minmax(0, 1fr) 18rem;\n gap: 3rem;\n}\n@media (max-width: 900px) {\n .np-page-sidebar { grid-template-columns: 1fr; }\n .np-page-sidebar-aside { order: -1; }\n}\n.np-page-sidebar-aside {\n position: sticky;\n top: 5rem;\n align-self: start;\n font-size: 0.9rem;\n}\n.np-page-sidebar-placeholder {\n border: 1px dashed var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n padding: 1rem;\n}\n.np-page-sidebar-placeholder-label {\n margin: 0 0 0.5rem;\n font-weight: 600;\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n color: var(--np-color-muted-foreground, #64748b);\n}\n.np-page-sidebar-placeholder-hint {\n margin: 0;\n color: var(--np-color-muted-foreground, #64748b);\n font-size: 0.85rem;\n line-height: 1.5;\n}\n.np-page-sidebar-placeholder code {\n background: var(--np-color-muted, #f1f5f9);\n padding: 0.1em 0.3em;\n border-radius: 3px;\n font-size: 0.9em;\n}\n\n/* ----------------------------------------------------------------\n * Post detail\n * --------------------------------------------------------------- */\n.np-post-default {\n max-width: var(--np-content-max);\n margin: 0 auto;\n padding: 2.5rem 1.5rem 4rem;\n}\n.np-post-cover {\n margin: 0 0 2rem;\n aspect-ratio: 16 / 9;\n border-radius: var(--np-radius-lg, 0.75rem);\n overflow: hidden;\n}\n.np-post-cover img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n.np-post-header { margin-bottom: 2rem; }\n.np-post-tags {\n list-style: none;\n margin: 0 0 0.75rem;\n padding: 0;\n display: flex;\n flex-wrap: wrap;\n gap: 0.4rem;\n}\n.np-post-tags a,\n.np-post-tags span {\n display: inline-block;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n padding: 0.25rem 0.6rem;\n border-radius: 999px;\n background: var(--np-color-muted, #f1f5f9);\n color: var(--np-color-muted-foreground, #64748b);\n text-decoration: none;\n}\n.np-post-tags a:hover { color: var(--np-color-foreground, #0f172a); }\n.np-post-excerpt {\n font-size: 1.125rem;\n color: var(--np-color-muted-foreground, #64748b);\n margin: 0 0 1.25rem;\n line-height: 1.6;\n}\n.np-post-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n font-size: 0.875rem;\n color: var(--np-color-muted-foreground, #64748b);\n border-top: 1px solid var(--np-color-border, #e5e7eb);\n padding-top: 1rem;\n}\n.np-post-meta-author {\n font-weight: 600;\n color: var(--np-color-foreground, #0f172a);\n}\n.np-post-body > * + * { margin-top: 1rem; }\n\n/* ----------------------------------------------------------------\n * Post list (blog index)\n * --------------------------------------------------------------- */\n.np-post-list {\n max-width: var(--np-content-max-wide);\n margin: 0 auto;\n padding: 3rem 1.5rem 4rem;\n}\n.np-post-list-header {\n margin-bottom: 2.5rem;\n text-align: center;\n}\n.np-post-list-header h1 { margin: 0; }\n.np-post-list-intro {\n margin: 0.75rem auto 0;\n max-width: 38rem;\n color: var(--np-color-muted-foreground, #64748b);\n font-size: 1.05rem;\n line-height: 1.6;\n}\n.np-post-list-feature { margin-bottom: 2rem; }\n.np-post-list-feature .np-post-card { display: block; }\n.np-post-list-feature .np-post-card-link {\n display: grid;\n grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);\n gap: 0;\n align-items: stretch;\n background: var(--np-color-card, #fff);\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-lg, 0.75rem);\n overflow: hidden;\n text-decoration: none;\n color: inherit;\n transition: border-color 0.15s ease, transform 0.2s ease;\n}\n.np-post-list-feature .np-post-card-link:hover {\n border-color: var(--np-color-foreground, #0f172a);\n transform: translateY(-2px);\n}\n.np-post-list-feature .np-post-card-cover {\n aspect-ratio: 16 / 10;\n margin: 0;\n overflow: hidden;\n}\n.np-post-list-feature .np-post-card-cover img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.np-post-list-feature .np-post-card-body {\n padding: 1.75rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n justify-content: center;\n}\n.np-post-list-feature .np-post-card-title {\n font-size: clamp(1.4rem, 2.4vw, 1.85rem);\n margin: 0;\n letter-spacing: -0.015em;\n}\n@media (max-width: 768px) {\n .np-post-list-feature .np-post-card-link { grid-template-columns: 1fr; }\n .np-post-list-feature .np-post-card-cover { aspect-ratio: 16 / 9; }\n}\n.np-post-list-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));\n gap: 1.5rem;\n}\n.np-post-card {\n background: var(--np-color-card, #fff);\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-lg, 0.75rem);\n overflow: hidden;\n transition: border-color 0.15s ease, transform 0.2s ease;\n}\n.np-post-card:hover {\n border-color: var(--np-color-foreground, #0f172a);\n transform: translateY(-2px);\n}\n.np-post-card-link {\n display: block;\n text-decoration: none;\n color: inherit;\n}\n.np-post-card-cover {\n margin: 0;\n aspect-ratio: 16 / 9;\n overflow: hidden;\n background: var(--np-color-muted, #f1f5f9);\n}\n.np-post-card-cover img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.np-post-card-body {\n padding: 1.25rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.np-post-card-title {\n margin: 0;\n font-size: 1.15rem;\n line-height: 1.3;\n letter-spacing: -0.01em;\n}\n.np-post-card-excerpt {\n margin: 0;\n font-size: 0.9rem;\n color: var(--np-color-muted-foreground, #64748b);\n line-height: 1.55;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.np-post-card-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.6rem;\n font-size: 0.78rem;\n color: var(--np-color-muted-foreground, #64748b);\n margin-top: 0.25rem;\n}\n.np-post-list-empty header {\n text-align: center;\n padding: 4rem 1.5rem;\n color: var(--np-color-muted-foreground, #64748b);\n}\n.np-post-list-empty h1 { color: var(--np-color-foreground, #0f172a); }\n\n/* ----------------------------------------------------------------\n * Pagination\n * --------------------------------------------------------------- */\n.np-pagination {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n margin: 3rem auto 0;\n}\n.np-pagination-step,\n.np-pagination-page,\n.np-pagination-gap {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 2.25rem;\n height: 2.25rem;\n padding: 0 0.6rem;\n font-size: 0.875rem;\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n text-decoration: none;\n color: inherit;\n background: transparent;\n transition: all 0.15s ease;\n}\n.np-pagination-page:hover,\n.np-pagination-step:hover { border-color: var(--np-color-foreground, #0f172a); }\n.np-pagination-current {\n background: var(--np-color-foreground, #0f172a);\n color: var(--np-color-background, #fff);\n border-color: var(--np-color-foreground, #0f172a);\n}\n.np-pagination-disabled {\n color: var(--np-color-muted-foreground, #94a3b8);\n border-color: var(--np-color-border, #e5e7eb);\n pointer-events: none;\n}\n.np-pagination-pages {\n list-style: none;\n display: flex;\n gap: 0.4rem;\n margin: 0;\n padding: 0;\n}\n.np-pagination-gap {\n border-color: transparent;\n cursor: default;\n}\n\n/* ----------------------------------------------------------------\n * Color-mode toggle (Phase 11.5) + language picker (12.6)\n * --------------------------------------------------------------- */\n.np-color-scheme-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.25rem;\n height: 2.25rem;\n padding: 0;\n border: 1px solid var(--np-color-border, #e5e7eb);\n border-radius: var(--np-radius-md, 0.5rem);\n background: transparent;\n color: inherit;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.np-color-scheme-toggle:hover {\n background: var(--np-color-muted, #f8fafc);\n border-color: var(--np-color-muted-foreground, #94a3b8);\n}\n.np-color-scheme-toggle:focus-visible {\n outline: 2px solid var(--np-color-ring, #4f46e5);\n outline-offset: 2px;\n}\n.np-color-scheme-toggle-placeholder {\n width: 2.25rem;\n height: 2.25rem;\n border: 1px solid transparent;\n}\n.np-language-picker {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n.np-language-picker-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 2rem;\n height: 1.85rem;\n padding: 0 0.55rem;\n border-radius: var(--np-radius-md, 0.5rem);\n text-decoration: none;\n color: inherit;\n opacity: 0.6;\n transition: opacity 0.15s ease, background 0.15s ease;\n}\n.np-language-picker-link:hover {\n opacity: 1;\n background: var(--np-color-muted, #f8fafc);\n}\n.np-language-picker-link[data-active=\"true\"] {\n opacity: 1;\n font-weight: 600;\n background: var(--np-color-muted, #f8fafc);\n}\n\n/* ----------------------------------------------------------------\n * Dark mode — re-skin the design tokens\n * --------------------------------------------------------------- */\n[data-theme=\"dark\"] {\n --np-color-background: oklch(0.145 0.004 285.823);\n --np-color-foreground: oklch(0.985 0.001 106.423);\n --np-color-muted: oklch(0.215 0.006 286.033);\n --np-color-muted-foreground: oklch(0.711 0.008 285.879);\n --np-color-border: oklch(0.269 0.006 286.033);\n --np-color-card: oklch(0.18 0.005 285.5);\n --np-color-card-foreground: oklch(0.985 0.001 106.423);\n --np-color-accent: oklch(0.269 0.006 286.033);\n --np-color-accent-foreground: oklch(0.985 0.001 106.423);\n}\n`.trim();\n","import { renderBlocks } from \"@nexpress/blocks\";\nimport type { NpPageBlocks } from \"@nexpress/blocks\";\n\nimport type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\n/**\n * Default page template — the historical NexPress page render.\n * Wraps the page's blocks (or a fallback heading) in\n * `<div className=\"np-page\">`. Used when a `pages` document\n * doesn't pick a specific template, or as the fallback when\n * the chosen template id doesn't resolve.\n */\nexport function PageDefaultTemplate({ doc, blockCtx }: NpTemplateRenderProps) {\n const blocks = (doc as { blocks?: NpPageBlocks }).blocks;\n const title = (doc as { title?: string }).title;\n return (\n <div className=\"np-page np-page-default\">\n {blocks ? renderBlocks(blocks, { ctx: blockCtx }) : <h1>{title ?? \"Untitled\"}</h1>}\n </div>\n );\n}\n","import { renderBlocks } from \"@nexpress/blocks\";\nimport type { NpPageBlocks } from \"@nexpress/blocks\";\n\nimport type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\n/**\n * Landing-page template — full-bleed hero from the doc's first\n * block, then the rest of the blocks render edge-to-edge so each\n * one (Hero / FeatureGrid / CTA / Pricing) can use the full\n * viewport width. The page's `title` and `seoDescription` form a\n * fallback hero when the doc has no blocks yet.\n *\n * For pages where the operator wants a single max-width column\n * and a sticky table of contents, pick the \"default\" template\n * instead.\n */\nexport function PageLandingTemplate({ doc, blockCtx }: NpTemplateRenderProps) {\n const blocks = (doc as { blocks?: NpPageBlocks }).blocks;\n const title = (doc as { title?: string }).title ?? \"Untitled\";\n const intro = (doc as { seoDescription?: string }).seoDescription;\n\n return (\n <div className=\"np-page np-page-landing\">\n {blocks && blocks.length > 0 ? (\n <div className=\"np-page-landing-blocks\">{renderBlocks(blocks, { ctx: blockCtx })}</div>\n ) : (\n <section className=\"np-page-landing-hero\">\n <h1>{title}</h1>\n {intro ? <p className=\"np-page-landing-intro\">{intro}</p> : null}\n </section>\n )}\n </div>\n );\n}\n","import { renderBlocks } from \"@nexpress/blocks\";\nimport type { NpPageBlocks } from \"@nexpress/blocks\";\n\nimport type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\n/**\n * Page template with a sticky sidebar on the right. Suited to\n * documentation / knowledge-base pages — the main column carries\n * the body, the aside carries supporting links / version pickers\n * / contributor cards.\n *\n * The aside is sourced from `doc.sidebar` (free-form blocks) when\n * present; sites that don't model a sidebar field on their pages\n * collection just see the main column. We keep the aside slot\n * always-rendered (with a fallback \"On this page\" placeholder) so\n * the layout doesn't reflow when an editor toggles the field.\n */\nexport function PageSidebarTemplate({ doc, blockCtx }: NpTemplateRenderProps) {\n const blocks = (doc as { blocks?: NpPageBlocks }).blocks;\n const sidebar = (doc as { sidebar?: NpPageBlocks }).sidebar;\n const title = (doc as { title?: string }).title ?? \"Untitled\";\n\n return (\n <div className=\"np-page np-page-sidebar\">\n <article className=\"np-page-sidebar-main\">\n {blocks ? renderBlocks(blocks, { ctx: blockCtx }) : <h1>{title}</h1>}\n </article>\n <aside className=\"np-page-sidebar-aside\" aria-label=\"Page sidebar\">\n {sidebar && sidebar.length > 0 ? (\n renderBlocks(sidebar, { ctx: blockCtx })\n ) : (\n <div className=\"np-page-sidebar-placeholder\">\n <p className=\"np-page-sidebar-placeholder-label\">On this page</p>\n <p className=\"np-page-sidebar-placeholder-hint\">\n Add a <code>sidebar</code> field to your pages collection to fill\n this column with secondary blocks.\n </p>\n </div>\n )}\n </aside>\n </div>\n );\n}\n","import { renderBlocks } from \"@nexpress/blocks\";\nimport type { NpPageBlocks } from \"@nexpress/blocks\";\n\nimport type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\n/**\n * Wide page template — drops the centered max-width\n * container so blocks render edge-to-edge. Useful for\n * landing pages, hero-led marketing pages, embedded media\n * grids.\n *\n * The `np-page-wide` class is what the CSS hooks into to\n * remove the default `np-page`'s max-width constraint;\n * theme CSS sets `.np-page-wide { max-width: none }` so\n * the rule is theme-owned (a different theme's wide variant\n * could use a different breakpoint).\n */\nexport function PageWideTemplate({ doc, blockCtx }: NpTemplateRenderProps) {\n const blocks = (doc as { blocks?: NpPageBlocks }).blocks;\n const title = (doc as { title?: string }).title;\n return (\n <div className=\"np-page np-page-wide\">\n {blocks ? renderBlocks(blocks, { ctx: blockCtx }) : <h1>{title ?? \"Untitled\"}</h1>}\n </div>\n );\n}\n","import { renderRichText } from \"@nexpress/editor/server\";\nimport type { NpRichTextContent } from \"@nexpress/editor\";\nimport Link from \"next/link\";\n\nimport type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\n/**\n * Post detail template. Produces a centered article column with\n * a small meta header (date / author / reading time) and the\n * Lexical body. Renders defensively — sites can attach extra\n * fields (cover, tags, related) and the template surfaces what\n * exists without breaking when fields are missing.\n *\n * The hero / cover image, when present, sits above the title in\n * a constrained 16:9 frame so portrait images don't blow up the\n * viewport. Tags render as small badges at the top of the meta\n * row when the doc carries them; otherwise we skip the row.\n */\n\ninterface PostDoc {\n title?: string;\n excerpt?: string;\n content?: NpRichTextContent;\n publishedAt?: string | Date;\n author?: { name?: string; slug?: string } | string;\n readingTime?: number | string;\n cover?: { url?: string; alt?: string } | string | null;\n tags?: Array<string | { label?: string; slug?: string }> | null;\n}\n\nfunction coverUrl(value: PostDoc[\"cover\"]): string | null {\n if (!value) return null;\n if (typeof value === \"string\") return value;\n return value.url ?? null;\n}\n\nfunction coverAlt(value: PostDoc[\"cover\"], fallback: string): string {\n if (value && typeof value === \"object\" && value.alt) return value.alt;\n return fallback;\n}\n\nfunction authorLabel(author: PostDoc[\"author\"]): string | null {\n if (!author) return null;\n if (typeof author === \"string\") return author;\n return author.name ?? null;\n}\n\nfunction tagItems(tags: PostDoc[\"tags\"]) {\n if (!tags || tags.length === 0) return [] as Array<{ label: string; slug?: string }>;\n return tags.map((tag) => {\n if (typeof tag === \"string\") return { label: tag };\n return { label: tag.label ?? tag.slug ?? \"tag\", slug: tag.slug };\n });\n}\n\nfunction formatDate(value: PostDoc[\"publishedAt\"]): string | null {\n if (!value) return null;\n try {\n const d = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(d.getTime())) return null;\n return d.toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n } catch {\n return null;\n }\n}\n\nfunction readingTimeLabel(value: PostDoc[\"readingTime\"]): string | null {\n if (!value && value !== 0) return null;\n if (typeof value === \"number\") return `${value.toString()} min read`;\n return value;\n}\n\nexport function PostDefaultTemplate({ doc }: NpTemplateRenderProps) {\n const post = doc as PostDoc;\n const title = post.title ?? \"Untitled\";\n const cover = coverUrl(post.cover);\n const author = authorLabel(post.author);\n const date = formatDate(post.publishedAt);\n const reading = readingTimeLabel(post.readingTime);\n const tags = tagItems(post.tags);\n\n return (\n <article className=\"np-post np-post-default\">\n {cover ? (\n <figure className=\"np-post-cover\">\n <img src={cover} alt={coverAlt(post.cover, title)} />\n </figure>\n ) : null}\n <header className=\"np-post-header\">\n {tags.length > 0 ? (\n <ul className=\"np-post-tags\">\n {tags.map((tag) => (\n <li key={tag.slug ?? tag.label}>\n {tag.slug ? (\n <Link href={`/tags/${tag.slug}`}>{tag.label}</Link>\n ) : (\n <span>{tag.label}</span>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n <h1 className=\"np-post-title\">{title}</h1>\n {post.excerpt ? <p className=\"np-post-excerpt\">{post.excerpt}</p> : null}\n <div className=\"np-post-meta\">\n {author ? (\n <span className=\"np-post-meta-author\">By {author}</span>\n ) : null}\n {date ? (\n <time\n className=\"np-post-meta-date\"\n dateTime={String(post.publishedAt)}\n >\n {date}\n </time>\n ) : null}\n {reading ? (\n <span className=\"np-post-meta-reading\">{reading}</span>\n ) : null}\n </div>\n </header>\n <div className=\"np-post-body\">\n {post.content ? renderRichText(post.content) : null}\n </div>\n </article>\n );\n}\n","/**\n * Card representation of a post in a list / grid context. Used\n * by the post-list template's grid + the related-posts strip on\n * post detail.\n *\n * Renders a small card with title, optional cover image, excerpt,\n * date, and reading time when those fields exist on the doc.\n * Stays defensive on field shapes — sites can fork the posts\n * collection schema, so we use type guards rather than a hard\n * shape requirement.\n */\n\nimport Link from \"next/link\";\n\nexport interface PostCardDoc {\n id?: string;\n slug?: string;\n title?: string;\n excerpt?: string;\n cover?: { url?: string; alt?: string } | string | null;\n publishedAt?: string | Date;\n readingTime?: number | string;\n author?: { name?: string } | string;\n}\n\nexport interface PostCardProps {\n doc: PostCardDoc;\n /** Visual variant. \"grid\" is the default; \"feature\" is bigger and lets the cover image stretch. */\n variant?: \"grid\" | \"feature\";\n}\n\nfunction coverImageUrl(cover: PostCardDoc[\"cover\"]): string | null {\n if (!cover) return null;\n if (typeof cover === \"string\") return cover;\n return cover.url ?? null;\n}\n\nfunction coverAlt(cover: PostCardDoc[\"cover\"], fallback: string): string {\n if (cover && typeof cover === \"object\" && cover.alt) return cover.alt;\n return fallback;\n}\n\nfunction formatDate(value: PostCardDoc[\"publishedAt\"]): string | null {\n if (!value) return null;\n try {\n const d = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(d.getTime())) return null;\n return d.toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n } catch {\n return null;\n }\n}\n\nfunction readingTimeLabel(value: PostCardDoc[\"readingTime\"]): string | null {\n if (!value && value !== 0) return null;\n if (typeof value === \"number\") return `${value.toString()} min read`;\n return value;\n}\n\nfunction authorName(author: PostCardDoc[\"author\"]): string | null {\n if (!author) return null;\n if (typeof author === \"string\") return author;\n return author.name ?? null;\n}\n\nfunction postHref(doc: PostCardDoc): string {\n if (doc.slug) {\n return doc.slug.startsWith(\"/\") ? doc.slug : `/blog/${doc.slug}`;\n }\n return \"#\";\n}\n\nexport function PostCard({ doc, variant = \"grid\" }: PostCardProps) {\n const href = postHref(doc);\n const cover = coverImageUrl(doc.cover);\n const date = formatDate(doc.publishedAt);\n const reading = readingTimeLabel(doc.readingTime);\n const author = authorName(doc.author);\n const title = doc.title ?? \"Untitled\";\n return (\n <article\n className={`np-post-card${variant === \"feature\" ? \" np-post-card-feature\" : \"\"}`}\n >\n <Link href={href} className=\"np-post-card-link\">\n {cover ? (\n <div className=\"np-post-card-cover\">\n <img src={cover} alt={coverAlt(doc.cover, title)} loading=\"lazy\" />\n </div>\n ) : null}\n <div className=\"np-post-card-body\">\n <h3 className=\"np-post-card-title\">{title}</h3>\n {doc.excerpt ? (\n <p className=\"np-post-card-excerpt\">{doc.excerpt}</p>\n ) : null}\n <div className=\"np-post-card-meta\">\n {author ? <span>{author}</span> : null}\n {date ? <time dateTime={String(doc.publishedAt)}>{date}</time> : null}\n {reading ? <span>{reading}</span> : null}\n </div>\n </div>\n </Link>\n </article>\n );\n}\n","import type { NpTemplateRenderProps } from \"@nexpress/theme\";\n\nimport { PostCard, type PostCardDoc } from \"../components/post-card.js\";\n\n/**\n * Blog index template. Picks one feature post (newest, or a\n * doc explicitly flagged with `featured: true`) and lays the\n * rest as a 3-column grid that collapses to 1 column on phones.\n *\n * The template is collection-agnostic — sites can route any\n * collection through it (e.g. /resources, /case-studies). The\n * doc shape we expect is `{ docs: PostCardDoc[] }`; templates\n * that need pagination metadata can render `<Pagination />`\n * around their own data fetch in the route handler.\n */\ninterface PostListDoc {\n docs?: PostCardDoc[];\n /** Page heading shown above the grid. Defaults to \"Posts\". */\n heading?: string;\n /** Optional paragraph beneath the heading. */\n intro?: string;\n}\n\nexport function PostListTemplate({ doc }: NpTemplateRenderProps) {\n const data = doc as PostListDoc;\n const heading = data.heading ?? \"Posts\";\n const intro = data.intro;\n const all = data.docs ?? [];\n if (all.length === 0) {\n return (\n <section className=\"np-post-list np-post-list-empty\">\n <header>\n <h1>{heading}</h1>\n <p>No posts yet — once you publish from the admin, they'll appear here.</p>\n </header>\n </section>\n );\n }\n const [feature, ...rest] = all;\n\n return (\n <section className=\"np-post-list\">\n <header className=\"np-post-list-header\">\n <h1>{heading}</h1>\n {intro ? <p className=\"np-post-list-intro\">{intro}</p> : null}\n </header>\n {feature ? (\n <div className=\"np-post-list-feature\">\n <PostCard doc={feature} variant=\"feature\" />\n </div>\n ) : null}\n {rest.length > 0 ? (\n <div className=\"np-post-list-grid\">\n {rest.map((post) => (\n <PostCard key={post.id ?? post.slug ?? post.title} doc={post} />\n ))}\n </div>\n ) : null}\n </section>\n );\n}\n","/**\n * Social-link strip read from `process.env.NP_SOCIAL_*` so\n * sites can light up the footer icons without forking the theme.\n * Empty when no env vars are set — the column collapses cleanly.\n *\n * Recognized env vars:\n * NP_SOCIAL_GITHUB → https://github.com/<handle>\n * NP_SOCIAL_TWITTER → https://twitter.com/<handle> or x.com URL\n * NP_SOCIAL_LINKEDIN → company / personal URL\n * NP_SOCIAL_MASTODON → https://mastodon.social/@<handle>\n * NP_SOCIAL_RSS → defaults to /feed.xml; set explicit URL to override\n * NP_SOCIAL_EMAIL → mailto: address\n */\n\ninterface SocialLink {\n href: string;\n label: string;\n Icon: () => React.JSX.Element;\n}\n\nfunction buildLinks(): SocialLink[] {\n const links: SocialLink[] = [];\n const env = process.env;\n if (env.NP_SOCIAL_GITHUB) {\n links.push({ href: env.NP_SOCIAL_GITHUB, label: \"GitHub\", Icon: GithubIcon });\n }\n if (env.NP_SOCIAL_TWITTER) {\n links.push({ href: env.NP_SOCIAL_TWITTER, label: \"Twitter / X\", Icon: TwitterIcon });\n }\n if (env.NP_SOCIAL_LINKEDIN) {\n links.push({ href: env.NP_SOCIAL_LINKEDIN, label: \"LinkedIn\", Icon: LinkedInIcon });\n }\n if (env.NP_SOCIAL_MASTODON) {\n // Mastodon recommends rel=\"me\" for verified profile links.\n links.push({ href: env.NP_SOCIAL_MASTODON, label: \"Mastodon\", Icon: MastodonIcon });\n }\n if (env.NP_SOCIAL_EMAIL) {\n const value = env.NP_SOCIAL_EMAIL.startsWith(\"mailto:\")\n ? env.NP_SOCIAL_EMAIL\n : `mailto:${env.NP_SOCIAL_EMAIL}`;\n links.push({ href: value, label: \"Email\", Icon: EmailIcon });\n }\n // RSS is always useful — default to the framework's feed when\n // not overridden. The icon is the universal RSS mark.\n links.push({\n href: env.NP_SOCIAL_RSS ?? \"/feed.xml\",\n label: \"RSS\",\n Icon: RssIcon,\n });\n return links;\n}\n\nexport function SocialLinks() {\n const links = buildLinks();\n if (links.length === 0) return null;\n return (\n <ul className=\"np-site-footer-social\">\n {links.map((link) => (\n <li key={link.href}>\n <a\n href={link.href}\n aria-label={link.label}\n rel={link.label === \"Mastodon\" ? \"me noopener noreferrer\" : \"noopener noreferrer\"}\n target={link.href.startsWith(\"mailto:\") || link.href.startsWith(\"/\") ? undefined : \"_blank\"}\n >\n <link.Icon />\n </a>\n </li>\n ))}\n </ul>\n );\n}\n\nconst ICON_PROPS = {\n width: 18,\n height: 18,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 1.8,\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n \"aria-hidden\": true,\n};\n\nfunction GithubIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22\" />\n </svg>\n );\n}\n\nfunction TwitterIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M22 4.01c-1 .49-1.98.689-3 .99-1.121-1.265-2.783-1.335-4.38-.737S11.977 6.323 12 8v1c-3.245.083-6.135-1.395-8-4 0 0-4.182 7.433 4 11-1.872 1.247-3.739 2.088-6 2 3.308 1.803 6.913 2.423 10.034 1.517 3.58-1.04 6.522-3.723 7.651-7.742a13.84 13.84 0 0 0 .497-3.753c-.002-.249 1.51-2.772 1.818-4.013z\" />\n </svg>\n );\n}\n\nfunction LinkedInIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z\" />\n <rect x=\"2\" y=\"9\" width=\"4\" height=\"12\" />\n <circle cx=\"4\" cy=\"4\" r=\"2\" />\n </svg>\n );\n}\n\nfunction MastodonIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M21 12c0 4.97-4.03 7-9 7s-9-2.03-9-7V8a5 5 0 0 1 5-5h8a5 5 0 0 1 5 5v4z\" />\n <path d=\"M9 13V9.5a2.5 2.5 0 1 1 5 0V13\" />\n </svg>\n );\n}\n\nfunction EmailIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\" />\n <polyline points=\"22,6 12,13 2,6\" />\n </svg>\n );\n}\n\nfunction RssIcon() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" {...ICON_PROPS}>\n <path d=\"M4 11a9 9 0 0 1 9 9\" />\n <path d=\"M4 4a16 16 0 0 1 16 16\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n","/**\n * Server-rendered pagination strip. Templates pass in the current\n * page + total count + URL builder; we render Prev / page numbers\n * / Next via next/link so navigation stays SPA-style and a\n * no-JS user still gets working anchors.\n */\n\nimport Link from \"next/link\";\n\nexport interface PaginationProps {\n page: number;\n totalPages: number;\n /** Builds the href for a given page number. Letting the\n * caller own this means /blog?page= and /search?q=foo&page=\n * share the same component. */\n hrefForPage: (page: number) => string;\n /** How many neighbours to show on each side of the active\n * page before collapsing to \"…\". Default 1, like GitHub. */\n siblings?: number;\n}\n\nfunction pageWindow(\n current: number,\n total: number,\n siblings: number,\n): Array<number | \"gap\"> {\n const windowSet = new Set<number>([1, total]);\n for (let i = -siblings; i <= siblings; i++) {\n const candidate = current + i;\n if (candidate >= 1 && candidate <= total) windowSet.add(candidate);\n }\n const sorted = Array.from(windowSet).sort((a, b) => a - b);\n const out: Array<number | \"gap\"> = [];\n let prev: number | null = null;\n for (const n of sorted) {\n if (prev !== null && n - prev > 1) out.push(\"gap\");\n out.push(n);\n prev = n;\n }\n return out;\n}\n\nexport function Pagination({ page, totalPages, hrefForPage, siblings = 1 }: PaginationProps) {\n if (totalPages <= 1) return null;\n const items = pageWindow(page, totalPages, siblings);\n const prev = page > 1 ? hrefForPage(page - 1) : null;\n const next = page < totalPages ? hrefForPage(page + 1) : null;\n\n return (\n <nav className=\"np-pagination\" aria-label=\"Pagination\">\n {prev ? (\n <Link href={prev} rel=\"prev\" className=\"np-pagination-step\">\n ← Prev\n </Link>\n ) : (\n <span className=\"np-pagination-step np-pagination-disabled\">← Prev</span>\n )}\n <ol className=\"np-pagination-pages\">\n {items.map((entry, index) => (\n <li key={`${typeof entry === \"number\" ? entry.toString() : \"gap\"}-${index.toString()}`}>\n {entry === \"gap\" ? (\n <span className=\"np-pagination-gap\" aria-hidden=\"true\">\n …\n </span>\n ) : (\n <Link\n href={hrefForPage(entry)}\n aria-current={entry === page ? \"page\" : undefined}\n className={\n entry === page ? \"np-pagination-page np-pagination-current\" : \"np-pagination-page\"\n }\n >\n {entry.toString()}\n </Link>\n )}\n </li>\n ))}\n </ol>\n {next ? (\n <Link href={next} rel=\"next\" className=\"np-pagination-step\">\n Next →\n </Link>\n ) : (\n <span className=\"np-pagination-step np-pagination-disabled\">Next →</span>\n )}\n </nav>\n );\n}\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["jsx","jsxs","jsx","renderBlocks","jsx","jsxs","renderBlocks","jsx","jsxs","renderBlocks","jsx","Link","jsx","jsxs","Link","jsx","jsxs","coverAlt","formatDate","readingTimeLabel","jsx","jsxs","MemberStatusWidget","MobileNav","jsx","jsxs","Link","jsx","jsxs"]}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@nexpress/theme-default",
3
+ "version": "0.1.0",
4
+ "description": "Default theme for NexPress.",
5
+ "license": "MIT",
6
+ "author": "Nexpress",
7
+ "homepage": "https://github.com/nexpress-cms/nexpress#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/nexpress-cms/nexpress.git",
11
+ "directory": "packages/themes/default"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/nexpress-cms/nexpress/issues"
15
+ },
16
+ "keywords": [
17
+ "nexpress",
18
+ "theme"
19
+ ],
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20"
34
+ },
35
+ "peerDependencies": {
36
+ "next": "^15.0.0 || ^16.0.0",
37
+ "react": "^19.0.0",
38
+ "react-dom": "^19.0.0"
39
+ },
40
+ "dependencies": {
41
+ "@nexpress/core": "0.1.0",
42
+ "@nexpress/blocks": "0.1.0",
43
+ "@nexpress/theme": "0.1.0",
44
+ "@nexpress/editor": "0.1.0",
45
+ "@nexpress/next": "0.1.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/react": "^19.0.0",
49
+ "@types/react-dom": "^19.0.0",
50
+ "next": "^16.2.4",
51
+ "react": "^19.0.0",
52
+ "react-dom": "^19.0.0",
53
+ "tsup": "^8.5.0",
54
+ "typescript": "^5.8.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsup",
58
+ "dev": "tsup --watch --no-clean",
59
+ "clean": "rm -rf dist",
60
+ "typecheck": "tsc --noEmit",
61
+ "lint": "eslint . --cache --cache-location node_modules/.cache/eslint"
62
+ }
63
+ }