cms.c2sgmbh/src/blocks/TableOfContentsBlock.ts
Martin Porwoll 2b097eefb3 feat: add comprehensive blogging and team features
Blogging Collections:
- Tags Collection with name, slug, description, color
- Authors Collection with avatar, bio, social media links

Posts Collection extended:
- Tags and Author relationships
- Co-Authors support
- Automatic reading time calculation
- Legacy author text field fallback

New Blogging Blocks:
- AuthorBioBlock: Display author info with various layouts
- RelatedPostsBlock: Show related articles (auto/manual/category/tag)
- ShareButtonsBlock: Social sharing (Facebook, Twitter, LinkedIn, etc.)
- TableOfContentsBlock: Auto-generated TOC from headings

Team Collection extended:
- Slug field for profile pages (auto-generated)
- Hierarchy fields (reportsTo, hierarchyLevel) for org charts
- vCard export flag

New Team API Endpoints:
- GET /api/team - List with search and filters
- GET /api/team/[slug]/vcard - vCard download (VCF)

New Team Blocks:
- TeamFilterBlock: Interactive team display with search/filter
- OrgChartBlock: Hierarchical organization chart visualization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-13 21:49:13 +00:00

287 lines
7.1 KiB
TypeScript

import type { Block } from 'payload'
/**
* TableOfContentsBlock
*
* Automatisches Inhaltsverzeichnis für lange Blog-Posts.
* Extrahiert Überschriften aus dem Content und erstellt Navigation.
*/
export const TableOfContentsBlock: Block = {
slug: 'toc-block',
labels: {
singular: 'Inhaltsverzeichnis',
plural: 'Inhaltsverzeichnisse',
},
imageURL: '/assets/blocks/table-of-contents.png',
fields: [
{
name: 'title',
type: 'text',
label: 'Überschrift',
localized: true,
defaultValue: 'Inhaltsverzeichnis',
},
// Überschriften-Level
{
name: 'levels',
type: 'group',
label: 'Überschriften-Level',
admin: {
description: 'Welche Überschriften-Ebenen einschließen?',
},
fields: [
{
name: 'h2',
type: 'checkbox',
defaultValue: true,
label: 'H2',
},
{
name: 'h3',
type: 'checkbox',
defaultValue: true,
label: 'H3',
},
{
name: 'h4',
type: 'checkbox',
defaultValue: false,
label: 'H4',
},
{
name: 'h5',
type: 'checkbox',
defaultValue: false,
label: 'H5',
},
{
name: 'h6',
type: 'checkbox',
defaultValue: false,
label: 'H6',
},
],
},
// Layout
{
name: 'layout',
type: 'select',
defaultValue: 'list',
label: 'Layout',
options: [
{ label: 'Liste', value: 'list' },
{ label: 'Nummeriert', value: 'numbered' },
{ label: 'Kompakt (Inline)', value: 'inline' },
{ label: 'Sidebar (Sticky)', value: 'sidebar' },
{ label: 'Dropdown/Akkordeon', value: 'dropdown' },
],
},
{
name: 'sidebarPos',
type: 'select',
defaultValue: 'right',
label: 'Sidebar-Position',
options: [
{ label: 'Links', value: 'left' },
{ label: 'Rechts', value: 'right' },
],
admin: {
condition: (_, siblingData) => siblingData?.layout === 'sidebar',
},
},
// Verhalten
{
name: 'behavior',
type: 'group',
label: 'Verhalten',
fields: [
{
name: 'smoothScroll',
type: 'checkbox',
defaultValue: true,
label: 'Sanftes Scrollen',
},
{
name: 'highlightActive',
type: 'checkbox',
defaultValue: true,
label: 'Aktiven Abschnitt markieren',
admin: {
description: 'Markiert den aktuell sichtbaren Abschnitt',
},
},
{
name: 'scrollOffset',
type: 'number',
defaultValue: 80,
label: 'Scroll-Offset (px)',
admin: {
description: 'Abstand zum oberen Rand nach dem Scrollen (für Fixed Headers)',
},
},
{
name: 'collapsible',
type: 'checkbox',
defaultValue: false,
label: 'Einklappbar',
admin: {
description: 'User kann das Inhaltsverzeichnis ein-/ausklappen',
},
},
{
name: 'startCollapsed',
type: 'checkbox',
defaultValue: false,
label: 'Anfangs eingeklappt',
admin: {
condition: (_, siblingData) => siblingData?.collapsible,
},
},
{
name: 'showProgress',
type: 'checkbox',
defaultValue: false,
label: 'Lesefortschritt anzeigen',
admin: {
description: 'Fortschrittsbalken oder Prozent-Anzeige',
},
},
{
name: 'progressStyle',
type: 'select',
defaultValue: 'bar',
label: 'Fortschritts-Stil',
options: [
{ label: 'Balken', value: 'bar' },
{ label: 'Prozent', value: 'percent' },
{ label: 'Kreis', value: 'circle' },
],
admin: {
condition: (_, siblingData) => siblingData?.showProgress,
},
},
],
},
// Styling
{
name: 'style',
type: 'group',
label: 'Darstellung',
fields: [
{
name: 'bg',
type: 'select',
defaultValue: 'light',
label: 'Hintergrund',
options: [
{ label: 'Keiner', value: 'none' },
{ label: 'Hell', value: 'light' },
{ label: 'Dunkel', value: 'dark' },
{ label: 'Akzent', value: 'accent' },
],
},
{
name: 'border',
type: 'checkbox',
defaultValue: true,
label: 'Rahmen',
},
{
name: 'borderSide',
type: 'select',
defaultValue: 'left',
label: 'Rahmen-Seite',
options: [
{ label: 'Alle', value: 'all' },
{ label: 'Links', value: 'left' },
{ label: 'Oben', value: 'top' },
],
admin: {
condition: (_, siblingData) => siblingData?.border,
},
},
{
name: 'rounded',
type: 'select',
defaultValue: 'md',
label: 'Ecken',
options: [
{ label: 'Keine', value: 'none' },
{ label: 'Klein', value: 'sm' },
{ label: 'Mittel', value: 'md' },
{ label: 'Groß', value: 'lg' },
],
},
{
name: 'shadow',
type: 'checkbox',
defaultValue: false,
label: 'Schatten',
},
{
name: 'indent',
type: 'checkbox',
defaultValue: true,
label: 'Sub-Überschriften einrücken',
},
{
name: 'showIcon',
type: 'checkbox',
defaultValue: false,
label: 'Icons anzeigen',
admin: {
description: 'Link-Symbol neben Einträgen',
},
},
{
name: 'fontSize',
type: 'select',
defaultValue: 'sm',
label: 'Schriftgröße',
options: [
{ label: 'Klein', value: 'sm' },
{ label: 'Normal', value: 'base' },
{ label: 'Groß', value: 'lg' },
],
},
{
name: 'lineHeight',
type: 'select',
defaultValue: 'relaxed',
label: 'Zeilenhöhe',
options: [
{ label: 'Eng', value: 'tight' },
{ label: 'Normal', value: 'normal' },
{ label: 'Locker', value: 'relaxed' },
],
},
],
},
// Limits
{
name: 'minItems',
type: 'number',
defaultValue: 3,
label: 'Mindestanzahl',
admin: {
description: 'Inhaltsverzeichnis nur anzeigen, wenn mindestens X Einträge',
},
},
{
name: 'maxItems',
type: 'number',
label: 'Maximalanzahl',
admin: {
description: 'Maximale Anzahl angezeigter Einträge (0 = unbegrenzt)',
},
},
// Accessibility
{
name: 'a11yLabel',
type: 'text',
label: 'ARIA Label',
localized: true,
defaultValue: 'Inhaltsverzeichnis',
},
],
}