#let theme = ( bg-color: rgb("#fdf6e3"), fg-color: rgb("#073642"), accent-color: rgb("#268bd2"), border-color: rgb("#073642"), heading-font: "Atkinson Hyperlegible", body-font: "DejaVu Sans", border-radius: 0.8cm, border-stroke: 4pt, title-size: 20pt, label-size: 12pt, body-size: 12pt, info-text-size: 12pt, ) // Default logo configuration #let default-logo = ( path: none, height: 4cm, fit: "contain", rotation: 0deg, offset: (x: 0cm, y: 0cm), pin-position: none, // "top-left", "top-center", "top-right", etc. ) // Konfiguriert die Logos #let configure-logo(logo-config) = { if logo-config == none { return default-logo } if type(logo-config) == str { // String = nur Pfad return default-logo + (path: logo-config) } return default-logo + logo-config } // Hilfsfunktion um ein einzelnes Logo zu positionieren #let place-logo(logo, position, dx: 0cm, dy: 0cm) = { let logo = configure-logo(logo) if logo.path == none { return } place(position, dx: logo.offset.x + dx, dy: logo.offset.y + dy)[ #rotate(logo.rotation)[ #image(logo.path, height: logo.height, fit: logo.fit) ] ] } // Positioniert mehrere Logos basierend auf Layout und Anzahl #let position-logos(logos, layout: "horizontal") = { let logos = if type(logos) == array { logos.map(configure-logo) } else if type(logos) == dictionary { (configure-logo(logos),) } else { () } if layout == "horizontal" { // Logos nebeneinander oben if logos.len() == 1 { place-logo(logos.first(), top + center) } else if logos.len() == 2 { place-logo(logos.at(0), top + left, dx: 1.5cm, dy: 0.7cm) place-logo(logos.at(1), top + right, dx: -1.5cm, dy: 0.7cm) } else if logos.len() == 3 { place-logo(logos.at(0), top + left, dx: 1.5cm, dy: 0.7cm) place-logo(logos.at(1), top + center, dy: 0.7cm) place-logo(logos.at(2), top + right, dx: -1.5cm, dy: 0.7cm) } else { // 4+ logos - anordnen in Gitter let cols = calc.min(2, logos.len()) let rows = calc.ceil(logos.len() / cols) for (i, logo) in logos.enumerate() { let row = calc.floor(i / cols) let col = calc.rem(i, cols) let x = -2.5cm + col * 5cm let y = 0.5cm + row * 2.2cm place-logo(logo, top + left, dx: x, dy: y) } } } else if layout == "vertical" { // Logos auf der rechten Seite positioniert, vertikal gestapelt if logos.len() == 1 { place-logo(logos.first(), top + right, dx: -1cm, dy: 0.7cm) } else if logos.len() == 2 { place-logo(logos.at(0), top + right, dx: -1cm, dy: 0.7cm) place-logo(logos.at(1), top + right, dx: -1cm, dy: 4.2cm) } else { // 3+ logos: vertikal auf der rechten Seite mit leichtem Offset gestapelt for (i, logo) in logos.enumerate() { let dy = 0.7cm + i * 3.5cm place-logo(logo, top + right, dx: -1cm, dy: dy) } } } } // Hilfsfunktion um den Inhalt zu arrangieren #let arrange-content(title: [], when: [], where: [], about: [], layout: "horizontal", current-theme: theme) = { let left-padding = if layout == "vertical" { 1.5cm } else { 1.5cm } let right-padding = if layout == "vertical" { 5cm } else { 1.5cm } let top-padding = if layout == "vertical" { 0.8cm } else { 5.5cm } pad(top: top-padding, bottom: 1.5cm, left: left-padding, right: right-padding)[ #stack( dir: ttb, spacing: 1em, // Title if title != [] { text(size: current-theme.title-size, weight: "bold", font: current-theme.heading-font, title) }, // Info-Block für wann/wo if when != [] or where != [] { block( inset: 0.8em, radius: 0.4em, width: 100%, fill: current-theme.bg-color.mix(current-theme.accent-color).darken(10%), stack( dir: ttb, spacing: 0.4em, if when != [] { align(center + horizon, stack( dir: ltr, spacing: 0.5em, align(center + horizon, emoji.calendar), text(size: current-theme.info-text-size, when), )) }, if where != [] { align(center + horizon, stack( dir: ltr, spacing: 0.5em, align(center + horizon, emoji.pin), text(size: current-theme.info-text-size, where), )) }, ), ) }, // Beschreibungstext if about != [] { let about-align = if layout == "vertical" { left } else { center } block( spacing: 0.1em, align(about-align, text(size: current-theme.body-size, about)) ) } ) ] } // Haupt-Vorlage-Funktion #let sharepic( logos: (), layout: "horizontal", title: [], when: [], where: [], about: [], theme-override: (:) ) = { // Überschreiben der Theme let current-theme = theme + theme-override set page( width: 15cm, height: 15cm, fill: current-theme.bg-color, margin: 0cm, ) set text( font: current-theme.body-font, size: 15pt, fill: current-theme.fg-color, ) align(center + horizon)[ #rect( width: 14cm, height: 14cm, radius: current-theme.border-radius, stroke: current-theme.border-stroke + current-theme.border-color, )[ // Positioniert Logos basierend auf Layout #{position-logos(logos, layout: layout)} // Inhaltsbereich #{arrange-content( title: title, when: when, where: where, about: about, layout: layout, current-theme: current-theme )} ] ] } // Verwendungsbeispiele und Dokumentation /* #sharepic( logos: ( (path: "logo1.png", height: 4cm), (path: "connection.png", height: 4cm, rotation: -8deg), (path: "kew.jpg", height: 4cm, rotation: 8deg) ), layout: "horizontal", title: [Beispiel-Event], when: [22.10.2025, 17:00 Uhr], where: [Ort Hier], about: [Beschreibung des Events...] ) #sharepic( logos: ( (path: "logo1.png", height: 3cm), (path: "logo2.png", height: 3cm), (path: "logo3.png", height: 3cm), (path: "logo4.png", height: 3cm) ), layout: "vertical", title: [Beispiel-Event], about: [Beschreibung des Events...] ) // Einfache Verwendung mit String-Logos #sharepic( logos: ("connection.png", "kew.jpg"), layout: "horizontal", title: [Beispiel-Event] ) */