Files
paliad/frontend/src/index.tsx
mAi a0082d2b0d fix(index): drop Downloads section from anon landing — the dotm card was the only visible affordance for unauth visitors
m's call 2026-05-19: the /files/hl-patents-style.dotm link on the
anonymous frontpage shouldn't tempt visitors to try downloading. The
/files/{filename} route IS already auth-gated (302 to /login on
anon click), and the macro-update endpoint at /patentstyle/* stays
public for the in-Word update logic per m's note ('with knowledge
of the direct source link it needs to be available').

Authenticated users never see this page anyway — handleRootPage 302s
them to /dashboard. So removing the section costs them nothing and
removes the obvious affordance for anon visitors. ICON_DOWNLOAD
const dropped along with it.

The Downloads page itself (/downloads + Sidebar nav entry) stays —
that's auth-gated and works for logged-in users.

Leftover surface: /patentstyle/HL-Patents-Style.dotm is still anon-
downloadable (necessary for the Word macro's auto-update poll).
That's m's stated requirement — flagged as the known leak path for
anyone who knows the URL.
2026-05-19 09:05:36 +02:00

132 lines
8.9 KiB
TypeScript

import { h } from "./jsx";
import { Sidebar } from "./components/Sidebar";
import { Footer } from "./components/Footer";
import { PWAHead } from "./components/PWAHead";
import { FIRM } from "./branding";
const ICON_BOOK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/><path d="M8 7h6"/><path d="M8 11h4"/></svg>';
const ICON_FILE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>';
const ICON_FOLDER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>';
const ICON_CALC = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="6" x2="16" y2="6"/><line x1="8" y1="14" x2="8" y2="14.01"/><line x1="12" y1="14" x2="12" y2="14.01"/><line x1="16" y1="14" x2="16" y2="14.01"/><line x1="8" y1="18" x2="16" y2="18"/></svg>';
const ICON_CLOCK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>';
const ICON_GLOSSAR = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>';
const ICON_TABLE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/></svg>';
const ICON_CHECK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>';
const ICON_BUILDING = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v16"/><path d="M16 9h3a2 2 0 0 1 2 2v10"/><path d="M9 7h2"/><path d="M9 11h2"/><path d="M9 15h2"/></svg>';
export function renderIndex(): string {
return "<!DOCTYPE html>" + (
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#BFF355" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<PWAHead />
<title data-i18n="index.title">{`Paliad — Patentwissen für ${FIRM}`}</title>
<link rel="stylesheet" href="/assets/global.css" />
</head>
<body className="has-sidebar">
<Sidebar currentPath="/" authenticated={false} />
<main>
<section className="hero">
<div className="container">
<h1>Patent Litigation<br /><span className="hero-accent" data-i18n="index.hero.accent">{`für ${FIRM}`}</span></h1>
<p className="hero-sub" data-i18n="index.hero.sub">
{`Administration, Knowledge und Tools für das ${FIRM} Patent-Team.`}
</p>
</div>
</section>
<section className="sections">
<div className="container">
<div className="grid">
<div className="card">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_BOOK }} />
<h2 data-i18n="index.guides.title">Leitf&auml;den</h2>
<p data-i18n="index.guides.desc">Praxisleitf&auml;den zu Verfahren vor dem EPA, BPatG und UPC. Schritt-f&uuml;r-Schritt-Anleitungen f&uuml;r typische Workflows.</p>
</div>
<div className="card">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_FILE }} />
<h2 data-i18n="index.templates.title">Vorlagen</h2>
<p data-i18n="index.templates.desc">{`Standardisierte Vorlagen für Schriftsätze, Korrespondenz und interne Dokumente. ${FIRM} Patents Style Guide.`}</p>
</div>
<div className="card">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_FOLDER }} />
<h2 data-i18n="index.documents.title">Dokumente</h2>
<p data-i18n="index.documents.desc">Referenzmaterialien, Checklisten und Arbeitshilfen f&uuml;r den Praxisalltag im Patentrecht.</p>
</div>
</div>
</div>
</section>
<section className="sections">
<div className="container">
<h3 className="section-heading" data-i18n="index.tools">Werkzeuge</h3>
<div className="grid grid-2">
<a href="/tools/kostenrechner" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_CALC }} />
<h2 data-i18n="index.cost.title">Kostenrechner</h2>
<p data-i18n="index.cost.desc">Sch&auml;tzung der Verfahrenskosten f&uuml;r DE-Gerichte, UPC und EPA-Verfahren. Gerichts- und Anwaltskosten auf einen Blick.</p>
</a>
<a href="/tools/fristenrechner" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_CLOCK }} />
<h2 data-i18n="index.deadline.title">Fristenrechner</h2>
<p data-i18n="index.deadline.desc">Berechnung von Verfahrensfristen f&uuml;r UPC-, deutsche und EPA-Verfahren mit Feiertags-Anpassung.</p>
</a>
<a href="/glossary" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_GLOSSAR }} />
<h2 data-i18n="index.glossar.title">Patentglossar</h2>
<p data-i18n="index.glossar.desc">Zweisprachiges DE/EN-Glossar der wichtigsten Begriffe im Patentrecht. Durchsuchbar nach Kategorien.</p>
</a>
<a href="/tools/gebuehrentabellen" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_TABLE }} />
<h2 data-i18n="index.gebuehren.title">Geb&uuml;hrentabellen</h2>
<p data-i18n="index.gebuehren.desc">Interaktive Geb&uuml;hrentabellen f&uuml;r GKG, RVG, UPC, EPA und PatKostG. Streitwert eingeben, Geb&uuml;hr ablesen.</p>
</a>
<a href="/checklists" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_CHECK }} />
<h2 data-i18n="index.checklisten.title">Checklisten</h2>
<p data-i18n="index.checklisten.desc">Interaktive Checklisten f&uuml;r UPC-, DE- und EPA-Verfahren. Fortschritt wird lokal gespeichert.</p>
</a>
<a href="/courts" className="card card-link">
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_BUILDING }} />
<h2 data-i18n="index.gerichte.title">Gerichtsverzeichnis</h2>
<p data-i18n="index.gerichte.desc">Gerichte, UPC-Kammern und Patent&auml;mter auf einen Blick &mdash; mit Adressen, Einreichungshinweisen und Sprachen.</p>
</a>
</div>
</div>
</section>
<section className="offices">
<div className="container">
<h3 data-i18n="index.offices">Standorte</h3>
<div className="office-list">
<span data-i18n="index.office.munich">M&uuml;nchen</span>
<span data-i18n="index.office.duesseldorf">D&uuml;sseldorf</span>
<span data-i18n="index.office.hamburg">Hamburg</span>
<span data-i18n="index.office.amsterdam">Amsterdam</span>
<span data-i18n="index.office.london">London</span>
<span data-i18n="index.office.paris">Paris</span>
<span data-i18n="index.office.milan">Mailand</span>
</div>
</div>
</section>
</main>
<Footer />
<script src="/assets/index.js"></script>
</body>
</html>
);
}