Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

# Build-Check für Pull Requests. Deployt niemals – das übernimmt
# ausschließlich deploy-pages.yml bei Push auf main oder manuellem Start.
on:
pull_request:
branches: [main]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm

- name: Install dependencies
run: npm ci

- name: Type/Astro check
run: npm run check

- name: Build
run: npm run build
62 changes: 62 additions & 0 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Deploy to GitHub Pages

on:
push:
branches: [main]
workflow_dispatch:

# Workflow-weit nur Leserechte. Die für das OIDC-basierte Pages-Deployment
# nötigen Schreibrechte (pages/id-token) sind ausschließlich dem deploy-Job
# zugeordnet, damit der build-Job sie nicht erbt.
permissions:
contents: read

# Nur ein Pages-Deployment gleichzeitig; laufende Deployments nicht abbrechen.
concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm

- name: Install dependencies
run: npm ci

- name: Type/Astro check
run: npm run check

- name: Build
run: npm run build

- name: Configure Pages
uses: actions/configure-pages@v5

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v4
with:
path: ./dist

deploy:
needs: build
runs-on: ubuntu-latest
# Nur der Deploy-Job erhält die für actions/deploy-pages nötigen Rechte.
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
50 changes: 36 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# blitztextweb

Statische Produktwebsite für [Blitztext Linux](https://github.com/TimInTech/blitztext-linux) –
vorgesehen für die Domain `https://blitztext.timintech.de`.
Statische Produktwebsite für [Blitztext Linux](https://github.com/TimInTech/blitztext-linux),
veröffentlicht über GitHub Pages unter `https://timintech.github.io/blitztextweb/`.

Dieses Repository enthält **ausschließlich die Website**. Die Desktop-App lebt im
getrennten Repository [TimInTech/blitztext-linux](https://github.com/TimInTech/blitztext-linux).
Expand Down Expand Up @@ -29,19 +29,22 @@ npm run build # Produktionsbuild → dist/
npm run preview # gebauten Stand lokal ansehen
```

Der Produktionsbuild landet im Ordner **`dist/`** und ist für das Hosting am
Domain-Root (`/`) gebaut.
Der Produktionsbuild landet im Ordner **`dist/`** und ist für die Auslieferung
unter dem GitHub-Pages-Unterpfad **`/blitztextweb/`** gebaut
(`base: '/blitztextweb'` in `astro.config.mjs`).

## Seiten

Alle Routen werden unter dem Unterpfad `/blitztextweb/` ausgeliefert.

| Route | Inhalt |
| :--- | :--- |
| `/` | Deutsche Startseite |
| `/en/` | Englische Startseite |
| `/impressum/` | Impressum (Vorlage mit markierten Platzhaltern) |
| `/datenschutz/` | Datenschutzerklärung (Deutsch) |
| `/en/privacy/` | Datenschutzerklärung (Englisch) |
| `/404.html` | Fehlerseite |
| `/blitztextweb/` | Deutsche Startseite |
| `/blitztextweb/en/` | Englische Startseite |
| `/blitztextweb/impressum/` | Impressum (Vorlage mit markierten Platzhaltern) |
| `/blitztextweb/datenschutz/` | Datenschutzerklärung (Deutsch) |
| `/blitztextweb/en/privacy/` | Datenschutzerklärung (Englisch) |
| `/blitztextweb/404.html` | Fehlerseite |

## Herkunft der Blitztext-Assets

Expand All @@ -54,9 +57,28 @@ App-Repository [TimInTech/blitztext-linux](https://github.com/TimInTech/blitztex
- `public/screenshots/` ← `docs/screenshots/linux/` (Dateinamen für das Web vereinheitlicht)
- `public/images/og-*.png` ← `docs/screenshots/linux/Banner-{de,en}.png`

## Deployment

Gehostet wird **ausschließlich über GitHub Pages** (Project Page) unter:

`https://timintech.github.io/blitztextweb/`

Es wird **keine Custom Domain** verwendet – es gibt keine `CNAME`-Datei und
keine DNS-Konfiguration.

- Deployment über GitHub Actions, Workflow `.github/workflows/deploy-pages.yml`
(Trigger: Push auf `main` oder manueller `workflow_dispatch`). Der
Produktionsbuild in **`dist/`** wird als Pages-Artefakt veröffentlicht.
- Pull Requests werden nur von `.github/workflows/ci.yml` geprüft (Build ohne
Deploy) und deployen niemals.
- Die Schreibrechte `pages: write` / `id-token: write` gelten ausschließlich für
den Deploy-Job; Build und Workflow-Ebene laufen mit `contents: read`.
- Die eigentliche **Aktivierung von GitHub Pages** (Settings → Pages → Source:
*GitHub Actions*) erfolgt manuell und ist nicht Teil dieses Repos.

## Noch offen vor dem öffentlichen Deployment

- **Rechtliche Angaben:** Impressum und Datenschutzerklärung enthalten deutlich
markierte `[PLATZHALTER]` (Betreiber, Anschrift, Kontakt, Hosting-Anbieter/Logdaten).
Diese müssen vor der Veröffentlichung ausgefüllt werden.
- **Deployment und DNS** waren nicht Bestandteil des Erstellungsauftrags dieser Website.
- **Rechtliche Angaben:** Das Impressum enthält deutlich markierte
`[PLATZHALTER]` (Betreiber, Anschrift, Kontakt). Diese sind rechtlich
erforderlich (u. a. § 5 DDG) und müssen vom Betreiber ausgefüllt werden, bevor
GitHub Pages öffentlich aktiviert wird.
7 changes: 5 additions & 2 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

// https://astro.build/config
// Auslieferung als GitHub-Pages-Project-Page unter
// https://timintech.github.io/blitztextweb/ (Unterpfad, kein Domain-Root).
export default defineConfig({
site: 'https://blitztext.timintech.de',
site: 'https://timintech.github.io',
base: '/blitztextweb',
output: 'static',
trailingSlash: 'ignore',
integrations: [
Expand All @@ -13,7 +16,7 @@ export default defineConfig({
}),
],
build: {
// saubere /pfad/index.html-Ausgabe für statisches Hosting am Domain-Root
// saubere /pfad/index.html-Ausgabe für statisches Hosting
format: 'directory',
},
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "blitztextweb",
"version": "1.0.0",
"private": true,
"description": "Static product website for Blitztext Linux (blitztext.timintech.de)",
"description": "Static product website for Blitztext Linux (https://timintech.github.io/blitztextweb/)",
"type": "module",
"scripts": {
"dev": "astro dev",
Expand Down
2 changes: 1 addition & 1 deletion public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://blitztext.timintech.de/sitemap-index.xml
Sitemap: https://timintech.github.io/blitztextweb/sitemap-index.xml
13 changes: 8 additions & 5 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
import type { Dict } from '../i18n';
import { langPrefix, type Lang } from '../i18n';
import { product } from '../data/product';
import { withBase } from '../utils/base';

interface Props {
dict: Dict;
}

const { dict } = Astro.props;
const home = `${langPrefix(dict.lang as Lang)}/`;
const privacyUrl = dict.lang === 'de' ? '/datenschutz/' : '/en/privacy/';
const home = withBase(`${langPrefix(dict.lang as Lang)}/`);
const privacyUrl = withBase(dict.lang === 'de' ? '/datenschutz/' : '/en/privacy/');
const imprintUrl = withBase('/impressum/');
const otherLangUrl = withBase(dict.otherLangUrl);
const year = new Date().getFullYear();
---

Expand All @@ -18,7 +21,7 @@ const year = new Date().getFullYear();
<div class="footer-grid">
<div class="footer-brand">
<a class="brand" href={home} aria-label={dict.nav.homeLabel}>
<img src="/brand/logo-mark-dark.svg" alt="" width="30" height="30" />
<img src={withBase('/brand/logo-mark-dark.svg')} alt="" width="30" height="30" />
<span>Blitztext Linux</span>
</a>
<p>{dict.footer.tagline}</p>
Expand All @@ -39,15 +42,15 @@ const year = new Date().getFullYear();
<h2>{dict.footer.legalTitle}</h2>
<ul>
<li><a href={privacyUrl}>{dict.footer.legal.privacy}</a></li>
<li><a href="/impressum/">{dict.footer.legal.imprint}</a></li>
<li><a href={imprintUrl}>{dict.footer.legal.imprint}</a></li>
</ul>
</nav>

<nav aria-label={dict.footer.websiteTitle}>
<h2>{dict.footer.websiteTitle}</h2>
<ul>
<li>
<a href={dict.otherLangUrl} lang={dict.lang === 'de' ? 'en' : 'de'}>
<a href={otherLangUrl} lang={dict.lang === 'de' ? 'en' : 'de'}>
{dict.nav.langSwitch}
</a>
</li>
Expand Down
7 changes: 4 additions & 3 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
import type { Dict } from '../i18n';
import { langPrefix, type Lang } from '../i18n';
import { product } from '../data/product';
import { withBase } from '../utils/base';

interface Props {
dict: Dict;
/** Ziel des Sprachumschalters */
/** Ziel des Sprachumschalters (bereits mit Base-URL präfixiert) */
altUrl: string;
}

const { dict, altUrl } = Astro.props;
const home = `${langPrefix(dict.lang as Lang)}/`;
const home = withBase(`${langPrefix(dict.lang as Lang)}/`);

const navItems = [
{ href: `${home}#features`, label: dict.nav.features },
Expand All @@ -24,7 +25,7 @@ const navItems = [
<header class="site-header">
<div class="container header-inner">
<a class="brand" href={home} aria-label={dict.nav.homeLabel}>
<img src="/brand/logo-mark-dark.svg" alt="" width="34" height="34" />
<img src={withBase('/brand/logo-mark-dark.svg')} alt="" width="34" height="34" />
<span class="brand-name">Blitztext <span class="brand-linux">Linux</span></span>
</a>

Expand Down
9 changes: 5 additions & 4 deletions src/components/Landing.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
import type { Dict } from '../i18n';
import { product } from '../data/product';
import { withBase } from '../utils/base';
import CopyBlock from './CopyBlock.astro';

interface Props {
Expand Down Expand Up @@ -38,7 +39,7 @@ const recordingShot = dict.screenshots.items[1]!;
</dl>
</div>
<figure class="hero-shot shot">
<img src={heroShot.src} alt={dict.hero.imgAlt} width="256" height="259" loading="eager" />
<img src={withBase(heroShot.src)} alt={dict.hero.imgAlt} width="256" height="259" loading="eager" />
<figcaption>{dict.hero.imgCaption}</figcaption>
</figure>
</div>
Expand Down Expand Up @@ -85,7 +86,7 @@ const recordingShot = dict.screenshots.items[1]!;
</ol>
</div>
<figure class="flow-shot shot">
<img src={recordingShot.src} alt={dict.flow.imgAlt} width="256" height="259" loading="lazy" />
<img src={withBase(recordingShot.src)} alt={dict.flow.imgAlt} width="256" height="259" loading="lazy" />
<figcaption>{recordingShot.caption}</figcaption>
</figure>
</div>
Expand Down Expand Up @@ -149,7 +150,7 @@ const recordingShot = dict.screenshots.items[1]!;
{
dict.screenshots.items.map((item) => (
<figure class="shot">
<img src={item.src} alt={item.alt} loading="lazy" />
<img src={withBase(item.src)} alt={item.alt} loading="lazy" />
<figcaption>{item.caption}</figcaption>
</figure>
))
Expand All @@ -162,7 +163,7 @@ const recordingShot = dict.screenshots.items[1]!;
{
dict.screenshots.trayStates.map((state) => (
<li>
<img src={state.src} alt={state.alt} width="48" height="48" loading="lazy" />
<img src={withBase(state.src)} alt={state.alt} width="48" height="48" loading="lazy" />
<span>{state.label}</span>
</li>
))
Expand Down
4 changes: 3 additions & 1 deletion src/data/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export const product = {
version: '0.8.1',
license: 'MIT',
os: 'Linux',
siteUrl: 'https://blitztext.timintech.de',
// Origin der GitHub-Pages-Auslieferung. Der Unterpfad (`base`) wird zentral
// über `withBase` bzw. `import.meta.env.BASE_URL` ergänzt.
siteUrl: 'https://timintech.github.io',
repoUrl: 'https://github.com/TimInTech/blitztext-linux',
releasesUrl: 'https://github.com/TimInTech/blitztext-linux/releases',
latestReleaseUrl: 'https://github.com/TimInTech/blitztext-linux/releases/tag/v0.8.1',
Expand Down
19 changes: 11 additions & 8 deletions src/layouts/Base.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
import type { Dict } from '../i18n';
import { product } from '../data/product';
import { withBase } from '../utils/base';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import '../styles/global.css';
Expand Down Expand Up @@ -29,10 +30,12 @@ const {
includeAppSchema = false,
} = Astro.props;

const canonical = new URL(path, product.siteUrl).href;
const altUrl = altPath !== null ? new URL(altPath, product.siteUrl).href : null;
const ogImage = new URL(dict.meta.ogImage, product.siteUrl).href;
// x-default zeigt auf die deutsche Fassung (Standardsprache der Domain)
// Alle absoluten URLs enthalten den GitHub-Pages-Unterpfad (`base`).
const canonical = new URL(withBase(path), product.siteUrl).href;
const altUrl = altPath !== null ? new URL(withBase(altPath), product.siteUrl).href : null;
const ogImage = new URL(withBase(dict.meta.ogImage), product.siteUrl).href;
const siteHome = new URL(withBase('/'), product.siteUrl).href;
// x-default zeigt auf die deutsche Fassung (Standardsprache der Website)
const xDefault = dict.lang === 'de' ? canonical : altUrl;

// Strukturierte Daten: ausschließlich im App-Repository bestätigte Angaben.
Expand All @@ -44,7 +47,7 @@ const appSchema = {
applicationCategory: 'UtilitiesApplication',
softwareVersion: product.version,
license: product.licenseUrl,
url: product.siteUrl,
url: siteHome,
downloadUrl: product.releasesUrl,
softwareHelp: product.setupDocUrl,
sameAs: product.repoUrl,
Expand All @@ -63,8 +66,8 @@ const appSchema = {
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="sitemap" href="/sitemap-index.xml" />
<link rel="icon" type="image/svg+xml" href={withBase('/favicon.svg')} />
<link rel="sitemap" href={withBase('/sitemap-index.xml')} />

<link rel="alternate" hreflang={dict.htmlLang} href={canonical} />
{altUrl && altLang && <link rel="alternate" hreflang={altLang} href={altUrl} />}
Expand Down Expand Up @@ -92,7 +95,7 @@ const appSchema = {
</head>
<body>
<a class="skip-link" href="#main">{dict.skipLink}</a>
<Header dict={dict} altUrl={altPath ?? dict.otherLangUrl} />
<Header dict={dict} altUrl={withBase(altPath ?? dict.otherLangUrl)} />
<main id="main">
<slot />
</main>
Expand Down
Loading
Loading