feat(privat/CV): sync to latest upstream (cv-upstream/main, 30f9608b)

This commit is contained in:
2026-07-07 15:20:55 +02:00
parent 8ac664d33d
commit a4efabbc60
417 changed files with 48564 additions and 712 deletions
@@ -0,0 +1,50 @@
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import { useContent, useContentTags } from '../hooks/useContent'
import { formatDate } from '../utils/formatDate'
export default function Kniepunkt() {
const [tag, setTag] = useState(null)
const [page, setPage] = useState(1)
const { items, totalPages, hasNext, hasPrev } = useContent('kniepunkt', { tag, page })
const tags = useContentTags('kniepunkt')
return (
<main style={{ paddingTop: '120px', minHeight: '100vh' }}>
<div className="app-container">
<div className="section-header">
<h1 className="section-title"><span className="text-gradient">Kniepunkt</span></h1>
<p className="section-subtitle">Wöchentliche KI-Kolumne. Nachrichten und Absurditäten rund um KI.</p>
</div>
{tags.length > 0 && (
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'center', marginBottom: '40px' }}>
<button onClick={() => setTag(null)} className={`secondary-button ${!tag ? 'active' : ''}`} style={{ padding: '8px 16px', fontSize: '0.85rem' }}>Alle</button>
{tags.map(t => (
<button key={t} onClick={() => { setTag(t); setPage(1) }} className={`secondary-button ${tag === t ? 'active' : ''}`} style={{ padding: '8px 16px', fontSize: '0.85rem' }}>{t}</button>
))}
</div>
)}
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '700px', margin: '0 auto' }}>
{items.map(issue => (
<Link to={`/kniepunkt/${issue.slug}`} key={issue.slug} className="glass-panel" style={{ padding: '24px', display: 'block', transition: 'transform 0.3s ease' }}>
<h3 style={{ marginBottom: '8px' }}>{issue.title}</h3>
<p style={{ color: 'var(--text-secondary)', margin: 0, fontSize: '0.9rem' }}>{formatDate(issue.date)}</p>
{issue.summary && <p style={{ color: 'var(--text-secondary)', margin: '8px 0 0', fontSize: '0.95rem' }}>{issue.summary}</p>}
</Link>
))}
{items.length === 0 && <p style={{ textAlign: 'center', color: 'var(--text-secondary)' }}>Noch keine Ausgaben vorhanden.</p>}
</div>
{totalPages > 1 && (
<div style={{ display: 'flex', justifyContent: 'center', gap: '16px', marginTop: '40px' }}>
{hasPrev && <button onClick={() => setPage(p => p - 1)} className="secondary-button">Zurück</button>}
<span style={{ color: 'var(--text-secondary)', alignSelf: 'center' }}>Seite {page} / {totalPages}</span>
{hasNext && <button onClick={() => setPage(p => p + 1)} className="secondary-button">Weiter</button>}
</div>
)}
</div>
</main>
)
}