diff --git a/component-library/src/App.tsx b/component-library/src/App.tsx index b3b2c13..3897652 100644 --- a/component-library/src/App.tsx +++ b/component-library/src/App.tsx @@ -13,7 +13,11 @@ import HomePage from "@/pages/home" import HowItWorksPage from "@/pages/how-it-works" import KlarpreisPage from "@/pages/klarpreis" import { SimplePage } from "@/pages/placeholder" +import HeizkostenabrechnungProductPage from "@/pages/products/heizkostenabrechnung" +import MesstechnikProductPage from "@/pages/products/messtechnik-infrastruktur" import ProductsPage from "@/pages/products" +import RauchwarnmelderProductPage from "@/pages/products/rauchwarnmelder" +import UviProductPage from "@/pages/products/uvi" import WissenPage from "@/pages/wissen" import DatenschutzSicherheitPage from "@/pages/wissen/datenschutz-sicherheit" import GesetzlicheAnforderungenPage from "@/pages/wissen/gesetzliche-anforderungen" @@ -39,6 +43,19 @@ export default function App() { } /> } /> } /> + } /> + } + /> + } + /> + } + /> } /> = 5 ? "lg:grid-cols-5" : "lg:grid-cols-4", + className + )} + > + {steps.map((step, i) => ( +
  • 0 && "lg:border-l" + )} + > + +
    + {i > 0 ? ( + + ) : null} + {step.media ?? ( + + {step.icon} + + )} +
    +

    + {step.title} +

    + {step.description ? ( +

    + {step.description} +

    + ) : null} +
  • + ))} + + ) +} + +export { ProcessSteps, NumberedList, StepFlow, StepRail } diff --git a/component-library/src/components/solenos/site-footer.tsx b/component-library/src/components/solenos/site-footer.tsx index 22eddc2..faf0cc5 100644 --- a/component-library/src/components/solenos/site-footer.tsx +++ b/component-library/src/components/solenos/site-footer.tsx @@ -8,6 +8,13 @@ const COLUMNS: { title: string; links: { to: string; label: string }[] }[] = [ title: "Produkt", links: [ { to: "/produkte", label: "Produkte" }, + { to: "/produkte/uvi", label: "UVI" }, + { to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" }, + { to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" }, + { + to: "/produkte/messtechnik-infrastruktur", + label: "Messtechnik und Infrastruktur", + }, { to: "/so-funktionierts", label: "So funktioniert’s" }, { to: "/konfigurator", label: "Konfigurator" }, { to: "/klarpreis", label: "SolenOS Klarpreis" }, diff --git a/component-library/src/components/solenos/site-header.tsx b/component-library/src/components/solenos/site-header.tsx index 0c01937..b93e53c 100644 --- a/component-library/src/components/solenos/site-header.tsx +++ b/component-library/src/components/solenos/site-header.tsx @@ -22,17 +22,28 @@ const AUDIENCES = [ { to: "/fuer-wen/installateure", label: "Installateure & Heizungsbauer" }, ] +/** mirrors the product registry in `@/pages/products/product-page` */ +const PRODUCTS = [ + { to: "/produkte/uvi", label: "UVI" }, + { to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" }, + { to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" }, + { + to: "/produkte/messtechnik-infrastruktur", + label: "Messtechnik und Infrastruktur", + }, +] + type NavItem = { to: string label: string /** present ⇒ rendered as a dropdown; `to` stays the section root that marks it active */ - menu?: typeof AUDIENCES + menu?: { to: string; label: string }[] } /** Source of truth for nav order – desktop pill, dropdown and mobile sheet all read it. */ const NAV_ITEMS: NavItem[] = [ { to: "/", label: "Start" }, - { to: "/produkte", label: "Produkte" }, + { to: "/produkte", label: "Produkte", menu: PRODUCTS }, { to: "/so-funktionierts", label: "So funktioniert’s" }, { to: "/fuer-wen", label: "Für wen?", menu: AUDIENCES }, { to: "/wissen", label: "Wissen" }, @@ -120,7 +131,7 @@ function useActivePill(activeKey: string | undefined) { return { navRef, pill } } -function AudienceMenu({ item, active }: { item: NavItem; active: boolean }) { +function NavMenu({ item, active }: { item: NavItem; active: boolean }) { return ( item.menu ? ( - + ) : ( + Quelle:{" "} + + {source.cite} + +

    + ) +} + +/** Property grid: line icon over a navy title, body copy, optional citation. */ +function TopicCards({ + items, + className, +}: { + items: Topic[] + className?: string +}) { + return ( +
    + {items.map((item) => ( + + + + {item.icon} + +

    + {item.title} +

    +

    + {item.body} +

    + {item.source ? : null} +
    +
    + ))} +
    + ) +} + +export { LegalSourceNote, TopicCards } +export type { LegalSource, Topic } diff --git a/component-library/src/lib/legal.ts b/component-library/src/lib/legal.ts new file mode 100644 index 0000000..ca4e24c --- /dev/null +++ b/component-library/src/lib/legal.ts @@ -0,0 +1,9 @@ +/** gesetze-im-internet base for the Heizkostenverordnung. */ +const HEIZKOSTENV = "https://www.gesetze-im-internet.de/heizkostenv" + +/** Permalink to a single paragraph, e.g. `heizkostenv("6a")`. */ +function heizkostenv(paragraph: string) { + return `${HEIZKOSTENV}/__${paragraph}.html` +} + +export { heizkostenv } diff --git a/component-library/src/pages/home.tsx b/component-library/src/pages/home.tsx index cb0581e..b00b351 100644 --- a/component-library/src/pages/home.tsx +++ b/component-library/src/pages/home.tsx @@ -14,7 +14,7 @@ import { Container, Section, SectionHeading } from "@/components/solenos/section import { PageHero } from "@/components/solenos/page-hero" import { HeroArt } from "@/components/solenos/hero-art" import { InfoStrip } from "@/components/solenos/info-strip" -import { ProcessSteps, NumberedList } from "@/components/solenos/process-steps" +import { NumberedList, StepFlow } from "@/components/solenos/process-steps" import { Checklist } from "@/components/solenos/checklist" import { CtaBanner } from "@/components/solenos/cta-banner" import { FaqAccordion, type FaqItem } from "@/components/solenos/faq-accordion" @@ -25,7 +25,6 @@ import { AssetRender, icons, renders, - vectors, type RenderAsset, } from "@/components/solenos/site-assets" @@ -113,58 +112,44 @@ const operationsScope = [ }, ] -function StepMedia({ src }: { src: string }) { - return ( - - - - ) -} - const processSteps = [ { - media: ( - - ), - title: "Gebäude anlegen & bestellen", - description: - "In nur 30 Minuten konfigurieren und bestellen.", - }, - { - media: , - title: "Vorkonfiguriert liefern", - description: "Geräte werden für Ihr Objekt vorbereitet geliefert.", + media: , + title: "Gebäude erfassen", + description: "Adresse, Wohnungen und Heizart angeben.", }, { media: ( - + <> + + + ), + title: "Ausstattung bestimmen", + description: "SolenOS ermittelt passende Geräte und Mengen.", + }, + { + media: ( + + ), + title: "Vorkonfiguriert erhalten", + description: "Geräte bereits jeder Wohnung zugeordnet geliefert.", + }, + { + media: , title: "Geräte montieren", - description: "Montage vor Ort – ohne aufwendige Softwarekonfiguration.", + description: "Selbst installieren oder Montage beauftragen.", }, { media: ( - + ), - title: "Bewohner einladen", - description: "Laden Sie die Bewohner in das SolenOS Portal ein.", - }, - { - media: , - title: "Automatischer Betrieb", - description: "SolenOS übernimmt Daten, Services und laufenden Betrieb.", + title: "Betrieb starten", + description: "Bewohner einladen und digital verwalten.", }, ] @@ -192,6 +177,7 @@ const systemTasks = [ media: , title: "UVI", text: "Regelmäßige Verbrauchsinformation für Bewohner.", + to: "/produkte/uvi", }, { media: ( @@ -199,6 +185,7 @@ const systemTasks = [ ), title: "Heizkostenabrechnung", text: "Verbrauchsdaten strukturiert erfassen und für die jährliche Abrechnung nutzen.", + to: "/produkte/heizkostenabrechnung", }, { media: ( @@ -206,11 +193,13 @@ const systemTasks = [ ), title: "Rauchwarnmelder", text: "Rauchwarnmelder gemeinsam mit der übrigen Gebäudetechnik planen und verwalten.", + to: "/produkte/rauchwarnmelder", }, { media: , title: "Messtechnik und Infrastruktur", text: "Fernauslesbare Zähler, Sensoren und Kommunikationsinfrastruktur für den laufenden Betrieb.", + to: "/produkte/messtechnik-infrastruktur", }, ] @@ -472,13 +461,14 @@ export default function HomePage() {
    - - +
    + +
    +
    @@ -529,7 +519,7 @@ export default function HomePage() { variant="link" className="h-auto shrink-0 self-start p-0 sm:self-center" > - + Mehr erfahren diff --git a/component-library/src/pages/products/heizkostenabrechnung.tsx b/component-library/src/pages/products/heizkostenabrechnung.tsx new file mode 100644 index 0000000..6e50360 --- /dev/null +++ b/component-library/src/pages/products/heizkostenabrechnung.tsx @@ -0,0 +1,338 @@ +import { Link } from "react-router-dom" +import { + ArrowRight, + CalendarClock, + Euro, + FileCheck2, + Flame, + Layers, + Droplets, + UserRoundCog, +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Checklist } from "@/components/solenos/checklist" +import { + ComparisonTable, + type ComparisonColumn, + type ComparisonRow, +} from "@/components/solenos/comparison-table" +import { CtaBanner } from "@/components/solenos/cta-banner" +import { FaqAccordion, type FaqItem } from "@/components/solenos/faq-accordion" +import { EuroCircleIcon } from "@/components/solenos/line-icons" +import { NumberedList } from "@/components/solenos/process-steps" +import { Section, SectionHeading } from "@/components/solenos/section" +import { + AssetRender, + renders, + vectors, +} from "@/components/solenos/site-assets" +import { TopicCards, type Topic } from "@/components/solenos/topic-cards" +import { heizkostenv } from "@/lib/legal" +import { ProductCrossLinks, ProductPage } from "@/pages/products/product-page" + +/** + * Hero art: the glass money render as the subject – the costs being + * distributed – with the consumption bars as their basis and the euro orb as + * the accent. Decorative; the copy carries the meaning. + */ +function BillingHeroArt() { + return ( +
    + + + +
    + ) +} + +const DISTRIBUTION: Topic[] = [ + { + icon: , + title: "Kosten der Wärmeversorgung", + body: "Mindestens 50 und höchstens 70 Prozent der Kosten werden nach dem erfassten Wärmeverbrauch verteilt, die übrigen nach Wohn- oder Nutzfläche beziehungsweise umbautem Raum.", + source: { cite: "§ 7 HeizkostenV", href: heizkostenv("7") }, + }, + { + icon: , + title: "Kosten der Warmwasserversorgung", + body: "Für die zentrale Warmwasserversorgung gilt derselbe Rahmen: 50 bis 70 Prozent nach erfasstem Warmwasserverbrauch, der Rest nach Wohn- oder Nutzfläche.", + source: { cite: "§ 8 HeizkostenV", href: heizkostenv("8") }, + }, + { + icon: , + title: "Verbundene Anlagen", + body: "Erzeugt eine Anlage Wärme und Warmwasser gemeinsam, werden die einheitlich entstandenen Betriebskosten zuerst zwischen beiden Zwecken aufgeteilt – anhand der auf die Warmwasserbereitung entfallenden Wärmemenge, die dafür mit einem Wärmezähler gemessen wird.", + source: { cite: "§ 9 HeizkostenV", href: heizkostenv("9") }, + }, + { + icon: , + title: "Nutzungszeiträume und Nutzerwechsel", + body: "Weil die Ausstattung fernablesbar ist, werden Zwischenwerte zum Stichtag aus der laufenden Datenerfassung übernommen und die Verbräuche dem jeweiligen Nutzungszeitraum zugeordnet.", + }, +] + +const YEAR_FLOW = [ + { + title: "Abrechnungszeitraum festlegen", + description: + "Zeitraum, Verteilungsmaßstäbe und Gebäudedaten werden im Portal hinterlegt.", + }, + { + title: "Verbrauchsdaten laufen automatisch mit", + description: + "Die fernablesbare Messtechnik liefert Monatswerte – dieselbe Datenbasis wie für die UVI.", + }, + { + title: "Kosten des Abrechnungszeitraums erfassen", + description: + "Brennstoff- oder Wärmelieferkosten, Betriebsstrom, Wartung und Messdienstkosten werden zugeordnet.", + }, + { + title: "Abrechnung erstellen und prüfen", + description: + "Verteilung nach den gewählten Maßstäben, inklusive Nutzerwechsel und Leerstand.", + }, + { + title: "Dokumente bereitstellen", + description: + "Einzelabrechnungen und Pflichtangaben stehen für Eigentümer, Verwaltung und Bewohner im Portal bereit.", + }, +] + +const BASIS_COLUMNS: ComparisonColumn[] = [ + { title: "Mit SolenOS", highlight: true }, + { title: "Klassischer Ableseweg", check: false }, +] + +const BASIS_ROWS: ComparisonRow[] = [ + { + label: "Datenerhebung", + cells: ["laufend fernabgelesen", "Ablesetermin je Wohnung"], + }, + { + label: "Zugang zur Wohnung", + cells: ["nicht erforderlich", "erforderlich, inklusive Nachtermine"], + }, + { + label: "Nutzerwechsel", + cells: ["Zwischenwerte aus der laufenden Erfassung", "Zwischenablesung vor Ort"], + }, + { + label: "Unterjährige Information", + cells: ["monatlich aus derselben Datenbasis", "separat zu organisieren"], + }, + { + label: "Datenbestand", + cells: [ + "Gebäude, Wohnungen und Geräte einmalig strukturiert", + "je Leistung erneut zu übermitteln", + ], + }, +] + +const INCLUDED = [ + "Verteilung der Wärme- und Warmwasserkosten nach HeizkostenV", + "Berücksichtigung von Nutzerwechseln und Leerständen", + "Einzelabrechnung je Wohnung mit den Pflichtangaben nach § 6a Absatz 3", + "Bereitstellung der Dokumente im Portal für Verwaltung und Bewohner", + "Übernahme der Verbrauchsdaten aus dem laufenden Messbetrieb", +] + +const NOT_INCLUDED = [ + "Betriebskostenabrechnung des Gebäudes (kalte Betriebskosten)", + "Beschaffung von Brennstoff oder Wärmelieferung", + "Mietvertragliche Prüfung und Mahnwesen", +] + +const FAQS: FaqItem[] = [ + { + question: "Brauche ich für die Abrechnung einen Ablesetermin?", + answer: + "Nein. Die Werte stammen aus der fernablesbaren Messtechnik und werden zum Ende des Abrechnungszeitraums automatisch übernommen. Auch Zwischenwerte bei Nutzerwechseln entstehen ohne Termin in der Wohnung.", + }, + { + question: "Welche Verteilungsmaßstäbe kann ich wählen?", + answer: + "Für die Wärmekosten sind mindestens 50 und höchstens 70 Prozent nach erfasstem Verbrauch zu verteilen (§ 7 Absatz 1 HeizkostenV); für Warmwasser gilt derselbe Rahmen (§ 8 Absatz 1). Die Wahl der Maßstäbe bleibt dem Gebäudeeigentümer überlassen und wird für künftige Abrechnungszeiträume im Portal hinterlegt (§ 6 Absatz 4).", + }, + { + question: "Was passiert, wenn nicht verbrauchsabhängig abgerechnet wird?", + answer: + "Nach § 12 Absatz 1 HeizkostenV kann der Nutzer seinen Kostenanteil um 15 Prozent kürzen, soweit entgegen der Verordnung nicht verbrauchsabhängig abgerechnet wird. Fehlt die fernablesbare Ausstattung oder werden die Informationen nach § 6a nicht vollständig mitgeteilt, sind es 3 Prozent.", + }, + { + question: "Kann ich die Abrechnung ohne UVI buchen?", + answer: + "Die Abrechnung setzt erfasste Verbrauchsdaten voraus. Läuft der Messbetrieb über SolenOS, ist die Datenbasis vorhanden und die Abrechnung nutzt sie direkt – die monatliche Verbrauchsinformation entsteht dann aus demselben Datenbestand.", + }, + { + question: "Wie sehen Bewohner ihre Abrechnung?", + answer: + "Die Einzelabrechnung wird im Mieterportal bereitgestellt und kann als Dokument ausgegeben werden. Bewohner sehen ausschließlich die Unterlagen ihres eigenen Nutzungsverhältnisses.", + }, +] + +export default function HeizkostenabrechnungProductPage() { + return ( + Heizkosten­abrechnung} + tagline="Aus den Daten, die ohnehin laufen." + lead="Die jährliche Abrechnung der Heiz- und Warmwasserkosten entsteht aus denselben fernabgelesenen Verbrauchswerten wie die monatliche UVI – verteilt nach den Maßstäben der Heizkostenverordnung, ohne Ablesetermin im Gebäude." + actions={ + <> + + + + } + note="Wenige Angaben · unverbindliche Kostenschätzung" + visual={} + features={[ + { + icon: , + title: "Verbrauchsabhängig verteilt", + sub: "50 bis 70 Prozent nach Verbrauch, der Rest nach Fläche.", + }, + { + icon: , + title: "Nutzerwechsel inklusive", + sub: "Zwischenwerte zum Stichtag ohne Termin in der Wohnung.", + }, + { + icon: , + title: "Mit Pflichtangaben", + sub: "Energieträger, Entgelte und Vergleichswerte nach § 6a.", + }, + { + icon: , + title: "Ein Datenbestand", + sub: "Gebäude, Wohnungen und Geräte werden einmal strukturiert.", + }, + ]} + closing={ +
    + } + title="Abrechnung und Messbetrieb aus einer Hand" + description="Wir gehen Abrechnungszeitraum, Verteilungsmaßstäbe und Ausstattung für Ihr Gebäude konkret durch." + actions={ + <> + + + + } + /> +
    + } + > +
    + + +
    + +
    +
    +
    + + +
    + + + +
    +
    + +
    + + +
    + +
    + +
    + +

    Enthalten

    + +
    + +

    + Nicht Teil der Heizkostenabrechnung +

    + +

    + Die Kosten der Verbrauchserfassung, ihrer Verwendung und der + Abrechnungs- und Verbrauchsinformationen gehören zu den + umlagefähigen Betriebskosten der Heizungsanlage. +

    +

    + § 7 Absatz 2 HeizkostenV +

    +
    +
    +
    + +
    + + +
    + + +
    + ) +} diff --git a/component-library/src/pages/products.tsx b/component-library/src/pages/products/index.tsx similarity index 65% rename from component-library/src/pages/products.tsx rename to component-library/src/pages/products/index.tsx index 579a7db..d873980 100644 --- a/component-library/src/pages/products.tsx +++ b/component-library/src/pages/products/index.tsx @@ -1,3 +1,4 @@ +import type * as React from "react" import { Link } from "react-router-dom" import { ArrowRight, Euro } from "lucide-react" @@ -7,36 +8,30 @@ import { CtaBanner } from "@/components/solenos/cta-banner" import { Container, Section, SectionHeading } from "@/components/solenos/section" import { PageBreadcrumb } from "@/components/solenos/page-breadcrumb" import { AssetRender, renders } from "@/components/solenos/site-assets" +import { PRODUCTS } from "@/pages/products/product-page" -const products = [ - { - title: "UVI", - sub: "Monatliche Verbrauchsinformation", - description: - "Verbrauchsdaten werden automatisch erfasst und die regelmäßigen Verbrauchsinformationen für die Bewohner bereitgestellt.", - illustration: ( -
    - -
    - ), - }, - { - title: "Heizkostenabrechnung", - sub: "Verbrauchsdaten korrekt abrechnen", - description: - "Verbrauchsdaten strukturiert erfassen und für die jährliche Abrechnung nutzen.", - illustration: , - }, - { - title: "Rauchwarnmelder", - sub: "Sicher überwacht, zentral verwaltet", - description: - "Rauchwarnmelder gemeinsam mit der übrigen Gebäudetechnik planen und verwalten.", - illustration: , - }, -] +/** + * One illustration per product, keyed by route so the registry stays free of + * layout decisions. The first three products are the bookable services and get + * a card each; the fourth is the technical layer underneath them and closes the + * grid as a wide strip. + */ +const illustrations: Record = { + "/produkte/uvi": ( + + ), + "/produkte/heizkostenabrechnung": ( + + ), + "/produkte/rauchwarnmelder": ( + + ), +} export default function ProductsPage() { + const services = PRODUCTS.slice(0, 3) + const infrastructure = PRODUCTS[3] + return ( <>
    @@ -44,34 +39,33 @@ export default function ProductsPage() {
    - {products.map((s) => ( - + {services.map((product) => ( +

    - {s.title} + {product.title}

    -

    {s.sub}

    +

    + {product.sub} +

    - {s.illustration} + {illustrations[product.to]}

    - {s.description} + {product.summary}

    + + + } + note="Wenige Angaben · unverbindliche Kostenschätzung" + visual={} + features={[ + { + icon: , + title: "Fernablesbar", + sub: "Ablesung ohne Zugang zu den einzelnen Wohnungen.", + }, + { + icon: , + title: "Interoperabel", + sub: "Offene Funkstandards, Schlüsselmaterial bleibt verfügbar.", + }, + { + icon: , + title: "Vorkonfiguriert", + sub: "Geräte kommen Gebäude und Einheit zugeordnet an.", + }, + { + icon: , + title: "Daten in Deutschland", + sub: "Verschlüsselte Übertragung, Hosting in Falkenstein.", + }, + ]} + closing={ +
    + } + title="Welche Ausstattung braucht Ihr Gebäude?" + description="Aus Gebäudedaten, Wärmeverteilung und Wohnungszahl ermitteln wir Geräteart und Menge – und daraus den Preis." + actions={ + <> + + + + } + /> +
    + } + > +
    + + +
    + +
    + + +
    + +
    + } + action={ + + } + > + Nicht fernablesbare Verbrauchserfassung muss grundsätzlich bis zum + 31. Dezember 2026 durch Nachrüstung oder Austausch die Anforderungen + an Fernablesbarkeit und Interoperabilität erfüllen. + +
    + +
    + +
    + +

    + Weiterverwendung möglich, wenn +

    + +
    + +

    + Austausch erforderlich bei +

    + +

    + Was übernommen werden kann, wirkt sich unmittelbar auf die + Geräteliste und damit auf den Preis aus. Der Bestand wird deshalb + bei der vollständigen Objektkonfiguration je Einheit erfasst. +

    +
    +
    +
    + +
    + + + {LIFECYCLE.map((item) => ( +
    +

    + {item.device} +

    +

    + {item.interval} +

    +

    + {item.note} +

    +
    + ))} +
    +

    + Eichfristen nach Anlage 7 der Mess- und Eichverordnung. Elektronische + Heizkostenverteiler unterliegen nicht dem Eichrecht. +

    +
    + +
    + } + action={ + + } + /> +
    + +
    + + +
    + + + + ) +} diff --git a/component-library/src/pages/products/product-page.tsx b/component-library/src/pages/products/product-page.tsx new file mode 100644 index 0000000..6e4c031 --- /dev/null +++ b/component-library/src/pages/products/product-page.tsx @@ -0,0 +1,196 @@ +import * as React from "react" +import { Link } from "react-router-dom" +import { ArrowRight } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { FeatureBand, type FeatureBandItem } from "@/components/solenos/feature-band" +import { PageBreadcrumb } from "@/components/solenos/page-breadcrumb" +import { PageHero } from "@/components/solenos/page-hero" +import { Container, Section, SectionHeading } from "@/components/solenos/section" +import { icons } from "@/components/solenos/site-assets" + +type Product = { + to: string + /** short label for navigation and cross-links */ + label: string + /** headline used on the overview cards */ + title: string + /** one-line positioning under the card title */ + sub: string + summary: string + /** baked-in disc icon, used wherever the four products are listed */ + icon: string +} + +/** + * The four products, in the order they are presented everywhere + * (overview grid, header menu, cross-links at the foot of each product page). + */ +const PRODUCTS: Product[] = [ + { + to: "/produkte/uvi", + label: "UVI", + title: "UVI", + sub: "Monatliche Verbrauchsinformation", + summary: + "Verbrauchsdaten werden automatisch erfasst und die monatliche Verbrauchsinformation für die Bewohner erzeugt und bereitgestellt – ohne Ablesetermin in der Wohnung.", + icon: icons.uvi, + }, + { + to: "/produkte/heizkostenabrechnung", + label: "Heizkostenabrechnung", + title: "Heizkostenabrechnung", + sub: "Verbrauchsdaten korrekt abrechnen", + summary: + "Die jährliche Abrechnung entsteht aus denselben erfassten Verbrauchsdaten: Verteilung nach HeizkostenV, Nutzerwechsel berücksichtigt, Dokumente im Portal.", + icon: icons.billing, + }, + { + to: "/produkte/rauchwarnmelder", + label: "Rauchwarnmelder", + title: "Rauchwarnmelder", + sub: "Sicher überwacht, zentral verwaltet", + summary: + "Ferninspizierbare Rauchwarnmelder inklusive Montage, jährlicher Inspektion nach DIN 14676-1 und lückenloser Dokumentation im Portal.", + icon: icons.smokeAlarm, + }, + { + to: "/produkte/messtechnik-infrastruktur", + label: "Messtechnik und Infrastruktur", + title: "Messtechnik und Infrastruktur", + sub: "Die technische Grundlage", + summary: + "Fernablesbare Zähler und Heizkostenverteiler, Gateway und Datenübertragung – vorkonfiguriert geliefert und laufend überwacht.", + icon: icons.radio, + }, +] + +function ProductIcon({ + src, + className = "size-12", +}: { + src: string + className?: string +}) { + return +} + +function ProductBreadcrumb({ current }: { current: string }) { + return ( + + ) +} + +/** + * Shared product page shell: split PageHero with the + * Startseite → Produkte → product breadcrumb, a feature band summarising the + * product in four properties, the product's own sections, then the closing + * slot (CtaBanner). + */ +function ProductPage({ + breadcrumb, + eyebrow, + title, + tagline, + lead, + actions, + note, + visual, + features, + children, + closing, +}: { + /** last breadcrumb crumb; also the product's own name */ + breadcrumb: string + eyebrow?: React.ReactNode + title: React.ReactNode + /** short bold subline under the H1 */ + tagline?: React.ReactNode + lead?: React.ReactNode + actions?: React.ReactNode + note?: React.ReactNode + visual?: React.ReactNode + features: FeatureBandItem[] + /** the product's spec sections between feature band and closing */ + children?: React.ReactNode + closing?: React.ReactNode +}) { + return ( + <> + } + eyebrow={eyebrow} + title={title} + lead={ + <> + {tagline ? ( + + {tagline} + + ) : null} + {lead} + + } + actions={actions} + note={note} + visual={visual} + /> + +
    + +
    + {children} + {closing} +
    + + ) +} + +/** + * Closes a product page out with the three other products, so the four pages + * form one navigable set instead of dead ends. + */ +function ProductCrossLinks({ current }: { current: string }) { + const others = PRODUCTS.filter((product) => product.to !== current) + + return ( +
    + +
    + {others.map((product) => ( + + +

    + {product.title} +

    +

    + {product.summary} +

    +
    + +
    +
    + ))} +
    +
    + ) +} + +export { PRODUCTS, ProductCrossLinks, ProductIcon, ProductPage } +export type { Product } diff --git a/component-library/src/pages/products/rauchwarnmelder.tsx b/component-library/src/pages/products/rauchwarnmelder.tsx new file mode 100644 index 0000000..d44d799 --- /dev/null +++ b/component-library/src/pages/products/rauchwarnmelder.tsx @@ -0,0 +1,346 @@ +import { Link } from "react-router-dom" +import { + ArrowRight, + BellRing, + ClipboardCheck, + ScrollText, + ShieldCheck, + Timer, + Wifi, +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Checklist } from "@/components/solenos/checklist" +import { + ComparisonTable, + type ComparisonColumn, + type ComparisonRow, +} from "@/components/solenos/comparison-table" +import { CtaBanner } from "@/components/solenos/cta-banner" +import { FaqAccordion, type FaqItem } from "@/components/solenos/faq-accordion" +import { PortalGaugeIcon } from "@/components/solenos/line-icons" +import { PriceCard } from "@/components/solenos/price-card" +import { StepRail } from "@/components/solenos/process-steps" +import { Section, SectionHeading } from "@/components/solenos/section" +import { + AssetRender, + renders, + vectors, +} from "@/components/solenos/site-assets" +import { TopicCards, type Topic } from "@/components/solenos/topic-cards" +import { SmokeDetectorIllustration } from "@/components/solenos/illustrations" +import { ProductCrossLinks, ProductPage } from "@/pages/products/product-page" + +/** + * Hero art: the glass smoke detector as the subject with the real device + * beside it and the check orb as the accent – device plus verified operational + * readiness. Decorative; the copy carries the meaning. + */ +function SmokeAlarmHeroArt() { + return ( +
    + + + +
    + ) +} + +const DUTIES: Topic[] = [ + { + icon: , + title: "Einbau und Betriebsbereitschaft", + body: "Rauchwarnmelder sind in Wohnungen nach den Bauordnungen der Länder vorgeschrieben. Wer für die Sicherstellung der Betriebsbereitschaft verantwortlich ist, regelt das jeweilige Landesrecht – in den meisten Ländern der Eigentümer.", + }, + { + icon: , + title: "Jährliche Inspektion", + body: "Die Anwendungsnorm DIN 14676-1 verlangt eine Inspektion mindestens einmal jährlich: Energieversorgung, Rauchzutrittsöffnungen und Umfeld des Melders werden geprüft.", + }, + { + icon: , + title: "Ferninspektion nach Norm", + body: "Die DIN 14676-1 kennt neben der Vor-Ort-Inspektion die Teil- und die vollständige Ferninspektion. Geeignete Melder melden Verschmutzung, Batteriezustand und Demontage selbst – ohne Termin in der Wohnung.", + }, + { + icon: , + title: "Austausch nach zehn Jahren", + body: "Rauchwarnmelder werden spätestens nach zehn Jahren Nutzungsdauer ausgetauscht. Verbaute Melder, Einbauorte und Austauschtermine sind im Portal je Wohnung dokumentiert.", + }, +] + +const ROLLOUT_STEPS = [ + { + media: , + title: "Bedarf ermitteln", + description: + "Aus Wohnungen und Zimmerzahl ergibt sich, wie viele Melder je Einheit benötigt werden.", + }, + { + media: ( + + ), + title: "Vorkonfiguriert erhalten", + description: + "Die Melder kommen bereits dem Gebäude und den geplanten Einheiten zugeordnet an.", + }, + { + media: , + title: "Montieren", + description: + "Montage durch Sie, Ihren Fachbetrieb oder als Komplettleistung durch SolenOS.", + }, + { + media: , + title: "Anbinden", + description: + "Die Melder funken über dieselbe Gebäudeinfrastruktur wie die Verbrauchserfassung.", + }, + { + media: ( + + ), + title: "Ferninspektion läuft", + description: + "Status, Meldungen und Inspektionsnachweise stehen laufend im Portal bereit.", + }, +] + +const INSPECTION_COLUMNS: ComparisonColumn[] = [ + { title: "Ferninspektion", highlight: true }, + { title: "Vor-Ort-Inspektion", check: false }, +] + +const INSPECTION_ROWS: ComparisonRow[] = [ + { + label: "Termin in der Wohnung", + cells: ["nicht erforderlich", "je Wohnung, inklusive Nachterminen"], + }, + { + label: "Prüfung", + cells: ["laufend durch den Melder", "einmal jährlich vor Ort"], + }, + { + label: "Störungen", + cells: ["werden gemeldet, sobald sie auftreten", "fallen beim Jahrestermin auf"], + }, + { + label: "Nachweis", + cells: ["automatisch dokumentiert", "Protokoll je Begehung"], + }, + { + label: "Aufwand für Bewohner", + cells: ["keine Anwesenheitspflicht", "Anwesenheit erforderlich"], + }, +] + +const INCLUDED = [ + "Rauchwarnmelder inklusive Montage und Eigentumsübertragung", + "Bedarfsermittlung je Wohnung aus den Gebäudedaten", + "regelmäßige Ferninspektion und Störungsmeldungen", + "Inspektionsnachweise je Wohnung im Portal", + "Support für Rückfragen von Verwaltung und Bewohnern", +] + +const FAQS: FaqItem[] = [ + { + question: "Wie oft müssen Rauchwarnmelder geprüft werden?", + answer: + "Mindestens einmal jährlich. Die Anwendungsnorm DIN 14676-1 lässt dafür neben der Vor-Ort-Inspektion auch die Teil- und die vollständige Ferninspektion zu, sofern die eingesetzten Melder dafür geeignet sind.", + }, + { + question: "Ersetzt die Ferninspektion die Vor-Ort-Prüfung vollständig?", + answer: + "Bei Meldern, die für die vollständige Ferninspektion geeignet sind, kann die Sicherstellung der Betriebsbereitschaft über die Gerätelebensdauer aus der Ferne erfolgen. Anlassbezogene Einsätze bleiben möglich – etwa wenn ein Melder demontiert wurde, dauerhaft verschmutzt ist oder ausgetauscht werden muss.", + }, + { + question: "Wer ist für die Rauchwarnmelder verantwortlich?", + answer: + "Einbau und Sicherstellung der Betriebsbereitschaft richten sich nach der Bauordnung des jeweiligen Landes. In den meisten Ländern trägt der Eigentümer die Verantwortung für die Betriebsbereitschaft; SolenOS liefert die Melder, die Inspektion und die Nachweise, mit denen diese Pflicht erfüllt werden kann.", + }, + { + question: "Wann müssen die Melder ausgetauscht werden?", + answer: + "Spätestens nach zehn Jahren Nutzungsdauer. Einbaudatum und fälliger Austausch sind je Gerät und Wohnung im Portal hinterlegt, sodass der Austausch mit dem übrigen Gebäudebetrieb geplant werden kann.", + }, + { + question: "Sind die Kosten umlagefähig?", + answer: + "Die laufenden Kosten der Ferninspektion sind grundsätzlich als Betriebskosten umlagefähig. Die einmaligen Kosten der Hardware inklusive Montage und Eigentumsübertragung sind es nicht – sie sind Anschaffungskosten des Eigentümers.", + }, + { + question: "Kann ich Rauchwarnmelder später ergänzen?", + answer: + "Ja. Läuft der Messbetrieb bereits über SolenOS, wird die vorhandene Gebäudestruktur weiterverwendet: Wohnungen und Einheiten sind erfasst, die Melder werden lediglich ergänzt und angebunden.", + }, +] + +export default function RauchwarnmelderProductPage() { + return ( + + + + + } + note="Wenige Angaben · unverbindliche Kostenschätzung" + visual={} + features={[ + { + icon: , + title: "Ferninspizierbar", + sub: "Prüfung ohne Termin und ohne Anwesenheit der Bewohner.", + }, + { + icon: , + title: "Störung fällt sofort auf", + sub: "Verschmutzung, Batterie und Demontage werden gemeldet.", + }, + { + icon: , + title: "Nachweis je Wohnung", + sub: "Inspektionen und Austauschfristen sind dokumentiert.", + }, + { + icon: , + title: "Im selben Portal", + sub: "Melder stehen neben Zählern und Verbrauchsdaten.", + }, + ]} + closing={ +
    + } + title="Rauchwarnmelder für Ihr Gebäude" + description="Bedarf, Montage und Ferninspektion in einem Schritt – auch zusätzlich zu einem laufenden Messbetrieb." + actions={ + <> + + + + } + /> +
    + } + > +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + } + /> + + + +
    + } + /> + +

    Enthalten

    + + +
    +
    +
    + +
    + + +
    + + + + ) +} diff --git a/component-library/src/pages/products/uvi.tsx b/component-library/src/pages/products/uvi.tsx new file mode 100644 index 0000000..013015d --- /dev/null +++ b/component-library/src/pages/products/uvi.tsx @@ -0,0 +1,348 @@ +import { Link } from "react-router-dom" +import { + ArrowRight, + CalendarClock, + Euro, + FileCheck2, + RadioTower, +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Checklist } from "@/components/solenos/checklist" +import { CtaBanner } from "@/components/solenos/cta-banner" +import { FaqAccordion, type FaqItem } from "@/components/solenos/faq-accordion" +import { PortalGaugeIcon } from "@/components/solenos/line-icons" +import { NoticeArt, NoticeBanner } from "@/components/solenos/notice-banner" +import { PriceCard } from "@/components/solenos/price-card" +import { StepRail } from "@/components/solenos/process-steps" +import { Section, SectionHeading } from "@/components/solenos/section" +import { + AssetRender, + renders, + vectors, +} from "@/components/solenos/site-assets" +import { heizkostenv } from "@/lib/legal" +import { ProductCrossLinks, ProductPage } from "@/pages/products/product-page" + +/** + * Hero art: the UVI pane as the subject – what the resident receives – with + * the consumption bars behind it and the consumption ring as the accent. + * Decorative; the copy carries the meaning. + */ +function UviHeroArt() { + return ( +
    + + + +
    + ) +} + +const MONTHLY_STEPS = [ + { + media: , + title: "Verbrauch erfassen", + description: + "Wärmezähler, Heizkostenverteiler und Wasserzähler messen laufend je Wohnung.", + }, + { + media: , + title: "Werte übertragen", + description: + "Das Gateway sammelt die Funkdaten im Gebäude und überträgt sie verschlüsselt an SolenOS.", + }, + { + media: , + title: "Daten prüfen und zuordnen", + description: + "Die Werte werden plausibilisiert und Wohnung, Gerät und Nutzungszeitraum zugeordnet.", + }, + { + media: , + title: "Verbrauchsinformation erzeugen", + description: + "Monatswert, Vergleichswerte und die nach § 6a HeizkostenV geforderten Angaben werden aufbereitet.", + }, + { + media: ( + + ), + title: "Bewohnern bereitstellen", + description: + "Bewohner rufen ihre Information im Mieterportal ab, Eigentümer sehen den Versandstatus.", + }, +] + +const MONTHLY_CONTENT = [ + "Verbrauch des Nutzers im letzten Monat in Kilowattstunden", + "Vergleich mit dem Vormonat desselben Nutzers", + "Vergleich mit dem entsprechenden Monat des Vorjahres, soweit die Daten erhoben wurden", + "Vergleich mit dem Verbrauch eines normierten Durchschnittsnutzers derselben Nutzerkategorie", +] + +const BILLING_CONTENT = [ + "Anteil der eingesetzten Energieträger, bei Fernwärme zusätzlich Treibhausgasemissionen und Primärenergiefaktor", + "erhobene Steuern, Abgaben und Zölle", + "Entgelte für Messtechnik, Eichung, Ablesung und Abrechnung", + "grafischer Vergleich des witterungsbereinigten Energieverbrauchs mit dem vorherigen Abrechnungszeitraum", + "Kontaktinformationen zu Energieeffizienz und Hinweise zur Streitbeilegung", +] + +const INCLUDED = [ + "fernablesbare Messtechnik für Wärme und Warmwasser", + "Gateway, Datenübertragung und Geräteüberwachung", + "monatliche Erzeugung der Verbrauchsinformation", + "Bereitstellung im Mieterportal für jede Wohnung", + "Nutzerwechsel ohne Ablesetermin vor Ort", + "Portalzugang für Eigentümer und Verwaltung", +] + +const NOT_INCLUDED = [ + "Jahresabrechnung der Heiz- und Warmwasserkosten", + "Rauchwarnmelder und deren Inspektion", + "Betriebskostenabrechnung des gesamten Gebäudes", +] + +const FAQS: FaqItem[] = [ + { + question: "Ab wann muss die Verbrauchsinformation monatlich erfolgen?", + answer: + "Sobald fernablesbare Ausstattungen zur Verbrauchserfassung installiert sind, sind die Verbrauchsinformationen nach § 6a Absatz 1 Nummer 2 HeizkostenV seit dem 1. Januar 2022 monatlich mitzuteilen. Für Abrechnungszeiträume ab dem 1. Dezember 2021 galt zunächst ein mindestens vierteljährlicher bzw. halbjährlicher Rhythmus.", + }, + { + question: "Wie erhalten die Bewohner ihre Verbrauchsinformation?", + answer: + "Über das Mieterportal. Jeder Bewohner erhält einen eigenen Zugang und sieht ausschließlich die Werte der eigenen Wohnung und des eigenen Nutzungszeitraums – nicht die Daten von Vor- oder Nachmietern.", + }, + { + question: "Was passiert, wenn ein Bewohner keinen digitalen Zugang nutzt?", + answer: + "Die Information wird im Portal bereitgestellt und kann als Dokument ausgegeben werden, sodass die Verwaltung sie auf dem für das Gebäude vereinbarten Weg zustellen kann. Die Pflicht trifft den Gebäudeeigentümer; SolenOS liefert die dafür benötigten Inhalte vollständig aufbereitet.", + }, + { + question: "Muss für die UVI jemand in die Wohnung?", + answer: + "Nein. Fernablesbar heißt, dass die Ausstattung ohne Zugang zu den einzelnen Nutzeinheiten abgelesen werden kann (§ 5 Absatz 2 HeizkostenV). Auch bei einem Nutzerwechsel werden die Werte zum Stichtag aus der laufenden Datenerfassung übernommen.", + }, + { + question: "Kann ich die UVI ohne Heizkostenabrechnung buchen?", + answer: + "Ja. Der UVI-Komplettbetrieb umfasst die benötigte Messtechnik und die zugehörigen digitalen Dienstleistungen. Die Heizkostenabrechnung baut auf denselben erfassten Verbrauchsdaten auf und kann jederzeit ergänzt werden.", + }, +] + +export default function UviProductPage() { + return ( + + Unterjährige Verbrauchs­information + + } + tagline="Monatlich. Automatisch. Nachweisbar." + lead="Sind fernablesbare Zähler installiert, muss jeder Nutzer monatlich über seinen Verbrauch informiert werden. SolenOS erzeugt diese Information aus den laufend erfassten Werten und stellt sie den Bewohnern im Mieterportal bereit." + actions={ + <> + + + + } + note="Wenige Angaben · unverbindliche Kostenschätzung" + visual={} + features={[ + { + icon: , + title: "Monatlich automatisch", + sub: "Erfassung, Aufbereitung und Bereitstellung laufen ohne Zutun.", + }, + { + icon: , + title: "Ohne Wohnungszugang", + sub: "Fernablesung statt Ablesetermin – auch beim Nutzerwechsel.", + }, + { + icon: , + title: "Eigener Bewohnerzugang", + sub: "Jede Wohnung sieht ausschließlich ihren eigenen Verbrauch.", + }, + { + icon: , + title: "Pflichtangaben enthalten", + sub: "Monatswert und Vergleiche nach § 6a HeizkostenV.", + }, + ]} + closing={ +
    + } + title="Was kostet die UVI für Ihr Gebäude?" + description="Mit wenigen Angaben zu Gebäude, Wohnungen und Wärmeverteilung erhalten Sie eine erste Preisindikation." + actions={ + <> + + + + } + /> +
    + } + > +
    + } + action={ + + } + > + Wo fernablesbare Ausstattungen installiert sind, sind die + Verbrauchsinformationen seit dem 1. Januar 2022 monatlich + mitzuteilen. Werden sie nicht oder nicht vollständig mitgeteilt, + können Nutzer ihren Kostenanteil um 3 % kürzen. + +
    + +
    + +
    + +

    + Monatlich +

    +

    + Verbrauchsinformation je Wohnung +

    + +

    + § 6a Absatz 2 HeizkostenV +

    +
    + +

    + Zur Abrechnung +

    +

    + Zusätzliche Informationen +

    + +

    + § 6a Absatz 3 HeizkostenV +

    +
    +
    +
    + +
    + + +
    + +
    + +
    + +

    Enthalten

    + +

    + Nicht im UVI-Betrieb enthalten +

    + +

    + Heizkostenabrechnung und Rauchwarnmelder sind eigene Leistungen – + einzeln buchbar und jederzeit ergänzbar. +

    +
    +
    + + UVI-Komplettbetrieb + + } + cadence="Monatlich" + price="10,50 €" + unit="je Wohnung / Monat" + allocation={{ + label: "Grundsätzlich umlagefähig", + tone: "positive", + }} + description="Sensoren, Daten, Portal und Verbrauchsinformation inklusive." + media={ + + } + /> + +
    +
    +
    + +
    + + +
    + + +
    + ) +} diff --git a/component-library/src/pages/wissen/datenschutz-sicherheit.tsx b/component-library/src/pages/wissen/datenschutz-sicherheit.tsx index 1524848..f92d60a 100644 --- a/component-library/src/pages/wissen/datenschutz-sicherheit.tsx +++ b/component-library/src/pages/wissen/datenschutz-sicherheit.tsx @@ -11,10 +11,9 @@ import { } from "@/components/solenos/site-assets" import { TopicCards, - WissenArticle, - WissenRelated, type Topic, -} from "@/pages/wissen/wissen-article" +} from "@/components/solenos/topic-cards" +import { WissenArticle, WissenRelated } from "@/pages/wissen/wissen-article" const safeguards: Topic[] = [ { diff --git a/component-library/src/pages/wissen/gesetzliche-anforderungen.tsx b/component-library/src/pages/wissen/gesetzliche-anforderungen.tsx index 424a398..06ff31e 100644 --- a/component-library/src/pages/wissen/gesetzliche-anforderungen.tsx +++ b/component-library/src/pages/wissen/gesetzliche-anforderungen.tsx @@ -11,19 +11,18 @@ import { vectors, } from "@/components/solenos/site-assets" import { - HEIZKOSTENV, TopicCards, - WissenArticle, - WissenRelated, type Topic, -} from "@/pages/wissen/wissen-article" +} from "@/components/solenos/topic-cards" +import { heizkostenv } from "@/lib/legal" +import { WissenArticle, WissenRelated } from "@/pages/wissen/wissen-article" const requirements: Topic[] = [ { icon: , title: "Unterjährige Verbrauchsinformation", body: "Monatliche Verbrauchsinformationen auf Basis der erfassten Verbrauchs- und Ablesewerte – zur Umsetzung der Anforderungen des § 6a HeizkostenV.", - source: { cite: "§ 6a HeizkostenV", href: `${HEIZKOSTENV}/__6a.html` }, + source: { cite: "§ 6a HeizkostenV", href: heizkostenv("6a") }, }, { icon: , @@ -34,7 +33,7 @@ const requirements: Topic[] = [ icon: , title: "Interoperable Messtechnik", body: "Die eingesetzten Verbrauchserfassungsgeräte sind OMS-fähig. Soweit für die jeweilige Ausstattung anwendbar, erfüllt die gelieferte Messtechnik die Anforderungen an Interoperabilität und Stand der Technik nach § 5 HeizkostenV.", - source: { cite: "§ 5 HeizkostenV", href: `${HEIZKOSTENV}/__5.html` }, + source: { cite: "§ 5 HeizkostenV", href: heizkostenv("5") }, }, ] diff --git a/component-library/src/pages/wissen/wissen-article.tsx b/component-library/src/pages/wissen/wissen-article.tsx index 201eff1..0910d1b 100644 --- a/component-library/src/pages/wissen/wissen-article.tsx +++ b/component-library/src/pages/wissen/wissen-article.tsx @@ -2,76 +2,11 @@ import type * as React from "react" import { Link } from "react-router-dom" import { ArrowRight } from "lucide-react" -import { cn } from "@/lib/utils" -import { Card, CardContent } from "@/components/ui/card" import { IconBadge } from "@/components/solenos/icon-tile" import { PageBreadcrumb } from "@/components/solenos/page-breadcrumb" import { PageHero } from "@/components/solenos/page-hero" import { Container, Section } from "@/components/solenos/section" -/** The paragraph of the HeizkostenV a property is cited against. */ -type LegalSource = { - cite: string - href: string -} - -/** One technical property: line icon, title, body, optional legal citation. */ -type Topic = { - icon: React.ReactNode - title: string - body: string - source?: LegalSource -} - -const HEIZKOSTENV = "https://www.gesetze-im-internet.de/heizkostenv" - -/** Cited source line, pinned to the card's baseline so rows stay aligned. */ -function LegalSourceNote({ source }: { source: LegalSource }) { - return ( -

    - Quelle:{" "} - - {source.cite} - -

    - ) -} - -/** Property grid: line icon over a navy title, body copy, optional citation. */ -function TopicCards({ - items, - className, -}: { - items: Topic[] - className?: string -}) { - return ( -
    - {items.map((item) => ( - - - - {item.icon} - -

    - {item.title} -

    -

    - {item.body} -

    - {item.source ? : null} -
    -
    - ))} -
    - ) -} - /** * Shared shell for the /wissen articles: split PageHero with the * Startseite → Wissen → article breadcrumb, then the article's own sections. @@ -165,5 +100,4 @@ function WissenRelated({ ) } -export { HEIZKOSTENV, TopicCards, WissenArticle, WissenRelated } -export type { LegalSource, Topic } +export { WissenArticle, WissenRelated }