Files
landing/docs/superpowers/specs/2026-08-02-ombrora-hub-landing-design.md
anthony 0496e1390b Add design spec for Ombrora hub landing page
Astro static site, FR/EN path-based i18n, light/dark theming, hub
linking to CVE Watch and Convert services.
2026-08-02 14:27:50 +02:00

6.3 KiB
Raw Permalink Blame History

Ombrora Hub Landing Page — Design

Purpose

A landing page at www.ombrora.com acting as a hub linking to Ombrora's existing services:

  • CVE Watch — a CVE-tracking blog, published in French (cve-fr.ombrora.com) and English (cve-en.ombrora.com) as two locale-specific deployments of the same underlying service.
  • Convert (convert.ombrora.com) — a file conversion tool (documents, audio, images, video, archives).

More services will be added to the hub over time; the design must make that cheap.

Requirements

  • Built with Astro, static output only (no SSR/SSR adapter) — required for SEO and for hosting on static shared hosting.
  • Multilingual: French and English, via path-based routing (/en/, /fr/), symmetric (no unprefixed default locale route).
  • Deployed to o2switch shared hosting: plain HTML/CSS/JS output uploaded to the host, no server-side runtime, .htaccess available for Apache-level rules.
  • SEO-optimized: prerendered HTML, meta tags, hreflang, sitemap, robots.txt.
  • Supports light and dark mode.
  • No existing brand assets — visual direction is proposed as part of this design.
  • Scope is minimal: hero + service cards + footer. No About/Contact/legal pages, no analytics.

Tech stack & project structure

  • Astro (latest stable), output: 'static' (Astro's default — no adapter needed).
  • No UI framework — plain Astro components and CSS are sufficient for this scope.
  • npm as package manager.
src/
  components/   Header.astro, Footer.astro, ServiceCard.astro, LanguageSwitcher.astro, ThemeToggle.astro
  i18n/         en.ts, fr.ts (UI strings), services.ts (service list, per-locale copy)
  layouts/      BaseLayout.astro (head/meta/hreflang/OG tags, theme init script)
  pages/
    en/index.astro
    fr/index.astro
public/
  .htaccess     (root language redirect)
  robots.txt
astro.config.mjs   (i18n config, sitemap integration)

Routing & i18n

astro.config.mjs:

i18n: {
  locales: ['en', 'fr'],
  defaultLocale: 'en',
  routing: { prefixDefaultLocale: true }
}

This produces symmetric /en/ and /fr/ routes (no bare unprefixed locale route). Astro's astro:i18n helpers (e.g. getRelativeLocaleUrl) generate cross-locale links for the language switcher and hreflang tags.

public/.htaccess handles the bare www.ombrora.com/ root with a real server-side redirect based on the Accept-Language header:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{HTTP:Accept-Language} fr [NC]
RewriteRule ^$ /fr/ [R=302,L]
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^$ /en/ [R=302,L]

French-preferring browsers land on /fr/; everything else defaults to /en/. No JavaScript redirect needed.

Content model

src/i18n/services.ts is the single source of truth for the service cards. url may be a plain string (same URL regardless of locale) or a { en, fr } object (locale-specific URL) — ServiceCard.astro resolves whichever shape is present against the current locale. Adding a future service, whether single-domain or per-locale-domain, means adding one entry here.

export const services = [
  {
    id: 'cve',
    url: { en: 'https://cve-en.ombrora.com', fr: 'https://cve-fr.ombrora.com' },
    name: { en: 'CVE Watch', fr: 'Veille CVE' },
    description: { en: '...', fr: '...' },
  },
  {
    id: 'convert',
    url: 'https://convert.ombrora.com',
    name: { en: 'Convert', fr: 'Convert' },
    description: { en: '...', fr: '...' },
  },
]

Note: CVE Watch is one logical service with two locale-specific deployments (matching the existing cve-fr/cve-en split), rendered as a single card whose link target depends on the hub's current locale — not two separate cards.

src/i18n/en.ts / fr.ts hold flat key-value UI strings (hero title/subtitle, nav labels, footer text), looked up directly in templates (e.g. t.hero.title) — no i18n library needed for this scope.

Pages & components

  • BaseLayout.astro: <html lang>, meta description, canonical URL, hreflang alternates (en, fr, x-default → en), Open Graph/Twitter card tags, favicon, global CSS, and the pre-paint theme-init script (see Theming).
  • Header.astro: Ombrora wordmark, LanguageSwitcher (links to the equivalent page in the other locale, not just the other locale's root), ThemeToggle.
  • Hero: short tagline introducing Ombrora as a hub for security and utility tools.
  • ServiceCard.astro × 2: name, one-line description, a tag (e.g. "CVE Blog", "File Converter"), outbound link resolved per current locale.
  • Footer.astro: copyright, optional contact mailto. No legal/About pages in this scope.

Visual direction

Dark, technical aesthetic fitting a security/CVE tracker and dev utility tool: neutral dark/light backgrounds, one accent color (cool cyan or violet) for links and highlights, a clean sans-serif for body text with a monospace accent for tags/labels. No decorative gimmicks.

Theming (light & dark mode)

Implemented via CSS custom properties (--bg, --fg, --accent, etc.) on :root, with [data-theme="dark"] / [data-theme="light"] overrides.

  • Default: follows system preference (prefers-color-scheme), applied by an inline <script> in BaseLayout that runs before first paint (avoids flash of wrong theme) and sets data-theme on <html>.
  • Manual override: a toggle button in the Header flips data-theme and persists the choice to localStorage; on later visits the stored preference takes precedence over system preference.
  • No extra dependency — CSS variables plus a small vanilla script.

SEO

  • @astrojs/sitemap integration generating a sitemap covering both locale routes.
  • Per-page <title>, meta description, canonical URL, and hreflang alternates in BaseLayout.
  • robots.txt allowing all crawlers, referencing the sitemap.
  • Semantic HTML (<main>, <section>, correct heading hierarchy), fully prerendered — no client-side rendering of critical content.

Build & deploy

  • astro build outputs static HTML/CSS/JS to dist/.
  • Deployment to o2switch is a manual upload of dist/ (including .htaccess, which Astro copies through from public/ unchanged). No CI/CD pipeline in this scope.

Out of scope

  • About/Contact/legal pages.
  • Analytics/tracking.
  • Any service beyond CVE Watch and Convert (future services are added by extending services.ts, not by redesigning the page).
  • CI/CD automation for deployment.