Astro static site, FR/EN path-based i18n, light/dark theming, hub linking to CVE Watch and Convert services.
132 lines
6.3 KiB
Markdown
132 lines
6.3 KiB
Markdown
# 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`:
|
||
|
||
```js
|
||
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:
|
||
|
||
```apache
|
||
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.
|
||
|
||
```ts
|
||
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.
|