Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2dd9d3ffb | |||
| 70a6798404 |
+108
-15
@@ -153,30 +153,35 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Logo as background image (paths-only SVG, no font dependency) */
|
/* Logo as background image (paths-only SVG, no font dependency) */
|
||||||
|
/* Wordmark-Schrift: Honk (expressive Color-Font, COLRv1), self-gehostet.
|
||||||
|
Bei fehlender Color-Font-Unterstützung greift die Fallback-Farbe unten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Honk';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/honk-latin.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
.wordmark-link {
|
.wordmark-link {
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: block;
|
display: block;
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
width: clamp(140px, 18vw, 200px);
|
width: auto;
|
||||||
height: clamp(22px, 2.8vw, 32px);
|
height: auto;
|
||||||
background-image: url("/logo/logo.svg");
|
font-family: 'Honk', var(--font-family-display), system-ui, sans-serif;
|
||||||
background-repeat: no-repeat;
|
font-weight: 400;
|
||||||
background-position: center;
|
font-size: clamp(2rem, 5vw, 3.1rem);
|
||||||
background-size: contain;
|
|
||||||
color: transparent;
|
|
||||||
font-size: 0;
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
text-transform: lowercase;
|
||||||
|
color: #fff; /* Fallback, falls Color-Font nicht unterstützt wird */
|
||||||
}
|
}
|
||||||
.wordmark-sr {
|
.wordmark-text { display: inline-block; }
|
||||||
position: absolute;
|
|
||||||
width: 1px; height: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0 0 0 0);
|
|
||||||
}
|
|
||||||
.wordmark-link:hover,
|
.wordmark-link:hover,
|
||||||
.wordmark-link:focus { color: #fff; border: none; opacity: 0.85; }
|
.wordmark-link:focus { border: none; opacity: 0.85; }
|
||||||
|
|
||||||
.site-header .site-nav {
|
.site-header .site-nav {
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
@@ -778,6 +783,94 @@ a.byline-author:hover, a.journal-author:hover { color: var(--accent); }
|
|||||||
|
|
||||||
.journal-tags { /* extends .tag-pills */ }
|
.journal-tags { /* extends .tag-pills */ }
|
||||||
|
|
||||||
|
/* ════════════════════════════════════════════════════════════════════════
|
||||||
|
Journal-Startseite: KARTEN-Kontext. Nimmt die Vollflächen-Panel-Regeln von
|
||||||
|
oben innerhalb von .journal-list zurück — kompakte 2-Spalten-Karten:
|
||||||
|
Bild als 16/9-Block OBEN (kein absolutes Overlay), dunkle Schrift,
|
||||||
|
natürliche Höhe (align-items:start → keine Zeilen-Stretchung; ein hoher
|
||||||
|
Eintrag zieht den Nachbarn NICHT mit).
|
||||||
|
════════════════════════════════════════════════════════════════════════ */
|
||||||
|
.journal-list { align-items: start; }
|
||||||
|
|
||||||
|
.journal-list .journal-entry,
|
||||||
|
.journal-list .journal-entry--layout-image,
|
||||||
|
.journal-list .journal-entry--layout-icon,
|
||||||
|
.journal-list .journal-entry--layout-text {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1.25rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 12px;
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
.journal-list .journal-entry--layout-image {
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
.journal-list .journal-entry-link { display: block; min-height: 0; }
|
||||||
|
|
||||||
|
/* Bild: normaler Block oben statt absolutem Hintergrund-Overlay */
|
||||||
|
.journal-list .journal-bg-image {
|
||||||
|
position: static;
|
||||||
|
inset: auto;
|
||||||
|
z-index: auto;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 0 0 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Body: linksbündig, normaler Textfluss, kompakt, dunkle Schrift */
|
||||||
|
.journal-list .journal-entry-body {
|
||||||
|
position: static;
|
||||||
|
z-index: auto;
|
||||||
|
max-width: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
justify-items: start;
|
||||||
|
text-align: left;
|
||||||
|
row-gap: 0.55rem;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
.journal-list .journal-entry-body > * { max-width: none; }
|
||||||
|
|
||||||
|
/* Bild-Layout: Schrift wieder dunkel (kein Weiß-auf-Bild) */
|
||||||
|
.journal-list .journal-entry--layout-image .journal-title,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-rubric,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-summary,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-byline,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-byline .journal-author,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-byline .journal-date,
|
||||||
|
.journal-list .journal-entry--layout-image .journal-byline .journal-author::before {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
.journal-list .journal-entry--layout-image .journal-section {
|
||||||
|
background: color-mix(in oklab, var(--section-color, var(--accent)) 35%, transparent);
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
backdrop-filter: none;
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kompaktere Karten-Typografie (nicht Hero-Größe) */
|
||||||
|
.journal-list .journal-title { font-size: 1.4rem; line-height: 1.2; font-weight: 700; letter-spacing: -0.02em; }
|
||||||
|
.journal-list .journal-summary { font-size: 1rem; line-height: 1.45; max-width: none; }
|
||||||
|
.journal-list .journal-byline { font-size: 0.9rem; }
|
||||||
|
|
||||||
|
/* Icon-Bild kleiner und linksbündig */
|
||||||
|
.journal-list .journal-icon-image { max-width: 96px; max-height: 96px; margin: 0 0 0.6rem; }
|
||||||
|
|
||||||
|
/* Tags innerhalb der Karte links, kompakt */
|
||||||
|
.journal-list .journal-entry > .tag-pills {
|
||||||
|
margin: 0.6rem 0 0;
|
||||||
|
padding: 0;
|
||||||
|
max-width: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.more {
|
.more {
|
||||||
margin-top: var(--spacing-md);
|
margin-top: var(--spacing-md);
|
||||||
font-family: var(--font-family-mono);
|
font-family: var(--font-family-mono);
|
||||||
|
|||||||
@@ -5,18 +5,28 @@ import {
|
|||||||
forumsWithCounts, forumWithThreads, recentComments, createThread, recentForModeration, threadMeta,
|
forumsWithCounts, forumWithThreads, recentComments, createThread, recentForModeration, threadMeta,
|
||||||
} from '../dialog-store.js';
|
} from '../dialog-store.js';
|
||||||
|
|
||||||
|
// Fehlt die Tabelle (Migration noch nicht eingespielt), nicht mit einem rohen
|
||||||
|
// SQL-Fehler antworten — leer zurückgeben und server-seitig laut loggen.
|
||||||
|
function softFail(c, e, fallback) {
|
||||||
|
console.error('[dialog]', e?.message || e);
|
||||||
|
return c.json(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Öffentliche Lese-Handler ─────────────────────────────────────────────
|
// ── Öffentliche Lese-Handler ─────────────────────────────────────────────
|
||||||
export async function listForums(c) {
|
export async function listForums(c) {
|
||||||
try { return c.json(await forumsWithCounts()); }
|
try { return c.json(await forumsWithCounts()); }
|
||||||
catch (e) { return c.json({ error: String(e) }, 500); }
|
catch (e) { return softFail(c, e, []); }
|
||||||
}
|
}
|
||||||
export async function showForum(c) {
|
export async function showForum(c) {
|
||||||
const data = await forumWithThreads(c.req.param('slug'));
|
try {
|
||||||
if (!data) return c.json({ error: 'Forum nicht gefunden' }, 404);
|
const data = await forumWithThreads(c.req.param('slug'));
|
||||||
return c.json(data);
|
if (!data) return c.json({ error: 'Forum nicht gefunden' }, 404);
|
||||||
|
return c.json(data);
|
||||||
|
} catch (e) { return softFail(c, e, { forum: null, threads: [] }); }
|
||||||
}
|
}
|
||||||
export async function recent(c) {
|
export async function recent(c) {
|
||||||
return c.json(await recentComments(Number(c.req.query('limit')) || 20));
|
try { return c.json(await recentComments(Number(c.req.query('limit')) || 20)); }
|
||||||
|
catch (e) { return softFail(c, e, []); }
|
||||||
}
|
}
|
||||||
export async function threadInfo(c) {
|
export async function threadInfo(c) {
|
||||||
const key = c.req.query('key');
|
const key = c.req.query('key');
|
||||||
|
|||||||
@@ -41,6 +41,30 @@ services:
|
|||||||
retries: 20
|
retries: 20
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
|
# ════════════════════════════════════════════════════════════════════════
|
||||||
|
# Migrate — spielt das (idempotente) Schema bei jedem `up` nach, damit neue
|
||||||
|
# Tabellen/Spalten auch in eine BESTEHENDE DB kommen (Init-Scripts laufen nur
|
||||||
|
# beim allerersten Start). Läuft einmal und beendet sich. supabase_admin =
|
||||||
|
# Superuser → keine Owner-Konflikte. schema.sql ist idempotent.
|
||||||
|
# ════════════════════════════════════════════════════════════════════════
|
||||||
|
migrate:
|
||||||
|
image: supabase/postgres:15.8.1.020
|
||||||
|
container_name: openbureau-migrate
|
||||||
|
restart: "no"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
PGPASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- ./db/schema.sql:/openbureau-schema.sql:ro
|
||||||
|
entrypoint: ["bash", "-c"]
|
||||||
|
command:
|
||||||
|
- >
|
||||||
|
psql -h db -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -f /openbureau-schema.sql &&
|
||||||
|
psql -h db -U supabase_admin -d postgres -c "notify pgrst, 'reload schema';" &&
|
||||||
|
echo '✓ Schema migriert.'
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════
|
||||||
# GoTrue — Auth (Login für das CMS)
|
# GoTrue — Auth (Login für das CMS)
|
||||||
# ════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════
|
||||||
@@ -124,6 +148,8 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
migrate:
|
||||||
|
condition: service_completed_successfully
|
||||||
kong:
|
kong:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<a href="#main-content" class="skip-link">Skip to content</a>
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
<header role="banner" class="site-header">
|
<header role="banner" class="site-header">
|
||||||
<a href="{{ "/" | relURL }}" class="wordmark-link" aria-label="OPENBUREAU">
|
<a href="{{ "/" | relURL }}" class="wordmark-link" aria-label="openbureau">
|
||||||
<span class="wordmark-sr">OPENBUREAU</span>
|
<span class="wordmark-text">openbureau</span>
|
||||||
</a>
|
</a>
|
||||||
<nav class="site-nav" aria-label="Site">
|
<nav class="site-nav" aria-label="Site">
|
||||||
{{ partial "menu.html" (dict "menuID" "main" "page" .) }}
|
{{ partial "menu.html" (dict "menuID" "main" "page" .) }}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user