Add Impressum page with content & styles
Replace placeholder Impressum with a full, design-aligned Vue page (GUI/src/routes/Impressum.vue). Added a <script setup> providing company, contact, register and legal note data (test data), a structured template (hero, details grid, notes) using Vuetify buttons/links, and comprehensive scoped CSS for layout and responsive behavior. Also updated codexInfo.md to document the new Impressum implementation and its test-data status. Intended to provide a ready-to-customize legal page for production substitution of real company data.
This commit is contained in:
+300
-14
@@ -1,19 +1,305 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
const companyDetails = [
|
||||||
|
{ label: 'Anbieter', value: 'Hoard Labs GmbH (Testdaten)' },
|
||||||
|
{ label: 'Vertreten durch', value: 'Max Mustermann, Geschäftsführer' },
|
||||||
|
{ label: 'Adresse', value: 'Musterstraße 42, 12345 Musterstadt, Deutschland' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const registerDetails = [
|
||||||
|
{ label: 'Handelsregister', value: 'HRB 123456' },
|
||||||
|
{ label: 'Registergericht', value: 'Amtsgericht Musterstadt' },
|
||||||
|
{ label: 'Umsatzsteuer-ID', value: 'DE123456789' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const contactDetails = [
|
||||||
|
{ label: 'Telefon', value: '+49 30 1234567-0', href: 'tel:+493012345670' },
|
||||||
|
{ label: 'E-Mail', value: 'kontakt@hoard-demo.de', href: 'mailto:kontakt@hoard-demo.de' },
|
||||||
|
{ label: 'Support', value: 'support@hoard-demo.de', href: 'mailto:support@hoard-demo.de' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const legalNotes = [
|
||||||
|
{
|
||||||
|
title: 'Verantwortlich für den Inhalt',
|
||||||
|
text: 'Julia Beispiel, Musterstraße 42, 12345 Musterstadt, Deutschland (Testdaten).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'EU-Streitbeilegung',
|
||||||
|
text: 'Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung bereit: https://ec.europa.eu/consumers/odr/. Wir sind nicht verpflichtet und nicht bereit, an einem Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Haftung für Inhalte',
|
||||||
|
text: 'Als Diensteanbieter sind wir für eigene Inhalte nach den allgemeinen Gesetzen verantwortlich. Für fremde Inhalte, auf die wir verweisen, übernehmen wir keine Gewähr. Dieses Impressum enthält ausschließlich Demo-Angaben.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Haftung für Links',
|
||||||
|
text: 'Unsere Seiten enthalten Links zu externen Webseiten Dritter. Für deren Inhalte ist stets der jeweilige Anbieter verantwortlich. Bei Bekanntwerden von Rechtsverletzungen werden derartige Links umgehend entfernt.',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container class="py-10">
|
<v-container fluid class="impressum-page">
|
||||||
<v-row justify="center">
|
<section class="impressum-hero hoard-panel">
|
||||||
<v-col cols="12" md="10" lg="8">
|
<div class="hero-copy">
|
||||||
<v-card rounded="lg" elevation="2">
|
<p class="hero-kicker">Rechtliche Angaben</p>
|
||||||
<v-card-title class="text-h5">Impressum</v-card-title>
|
<h1>Impressum</h1>
|
||||||
<v-card-text>
|
<p class="hero-lead">
|
||||||
Diese Seite ist als Platzhalter angelegt. Trage hier deine Firmen- oder Vereinsdaten
|
Diese Seite ist im Hoard-Design aufgebaut und mit Testdaten gefüllt. Ersetze die Angaben
|
||||||
ein.
|
vor einem produktiven Einsatz mit deinen echten Unternehmensdaten.
|
||||||
</v-card-text>
|
</p>
|
||||||
</v-card>
|
|
||||||
</v-col>
|
<div class="hero-meta">
|
||||||
</v-row>
|
<span class="meta-pill">Testdaten</span>
|
||||||
|
<span class="meta-text">Stand: 17. April 2026</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero-actions">
|
||||||
|
<v-btn color="primary" prepend-icon="mdi-home" to="/">Zur Startseite</v-btn>
|
||||||
|
<v-btn variant="outlined" prepend-icon="mdi-login" to="/login">Zum Login</v-btn>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="details-grid">
|
||||||
|
<article class="detail-card hoard-panel">
|
||||||
|
<h2>Anbieterangaben</h2>
|
||||||
|
<dl class="detail-list">
|
||||||
|
<div v-for="entry in companyDetails" :key="entry.label" class="detail-item">
|
||||||
|
<dt>{{ entry.label }}</dt>
|
||||||
|
<dd>{{ entry.value }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="detail-card hoard-panel">
|
||||||
|
<h2>Kontakt</h2>
|
||||||
|
<dl class="detail-list">
|
||||||
|
<div v-for="entry in contactDetails" :key="entry.label" class="detail-item">
|
||||||
|
<dt>{{ entry.label }}</dt>
|
||||||
|
<dd>
|
||||||
|
<a :href="entry.href">{{ entry.value }}</a>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="detail-card hoard-panel">
|
||||||
|
<h2>Register und Steuer</h2>
|
||||||
|
<dl class="detail-list">
|
||||||
|
<div v-for="entry in registerDetails" :key="entry.label" class="detail-item">
|
||||||
|
<dt>{{ entry.label }}</dt>
|
||||||
|
<dd>{{ entry.value }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="notes-section hoard-panel">
|
||||||
|
<header class="notes-head">
|
||||||
|
<p class="notes-kicker">Rechtliche Hinweise</p>
|
||||||
|
<h2>Wichtige Zusatzinformationen</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="notes-grid">
|
||||||
|
<article v-for="note in legalNotes" :key="note.title" class="note-card">
|
||||||
|
<h3>{{ note.title }}</h3>
|
||||||
|
<p>{{ note.text }}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.impressum-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-6);
|
||||||
|
margin-inline: auto;
|
||||||
|
width: min(100%, 1120px);
|
||||||
|
padding-block: var(--space-4) var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.impressum-hero {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: var(--space-6);
|
||||||
|
align-items: end;
|
||||||
|
padding: var(--space-8);
|
||||||
|
background:
|
||||||
|
linear-gradient(
|
||||||
|
125deg,
|
||||||
|
color-mix(in srgb, var(--color-primary-100) 40%, var(--color-surface) 60%) 0%,
|
||||||
|
var(--color-surface) 56%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-kicker,
|
||||||
|
.hero-lead,
|
||||||
|
.meta-text,
|
||||||
|
.notes-kicker {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-kicker,
|
||||||
|
.notes-kicker {
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
color: var(--color-primary-700);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
font-size: clamp(1.9rem, 2.2vw + 1rem, 2.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-lead {
|
||||||
|
max-width: 64ch;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-3);
|
||||||
|
margin-top: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px var(--space-3);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-primary-300) 60%, var(--color-border) 40%);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--color-primary-700);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: color-mix(in srgb, var(--color-primary-100) 82%, var(--color-surface) 18%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-text {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
padding: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(1.2rem, 1.2vw + 0.85rem, 1.6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
padding-bottom: var(--space-3);
|
||||||
|
border-bottom: 1px solid color-mix(in srgb, var(--color-border) 75%, var(--color-surface) 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
margin-bottom: var(--space-1);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notes-section {
|
||||||
|
padding: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notes-head {
|
||||||
|
margin-bottom: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notes-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-card {
|
||||||
|
padding: var(--space-4);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 76%, var(--color-surface) 24%);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface-alt) 72%, var(--color-surface) 28%);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 var(--space-2);
|
||||||
|
font-size: 1.03rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-card p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width <= 1080px) {
|
||||||
|
.details-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width <= 960px) {
|
||||||
|
.impressum-page {
|
||||||
|
gap: var(--space-5);
|
||||||
|
padding-block: var(--space-2) var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.impressum-hero,
|
||||||
|
.notes-section {
|
||||||
|
padding: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.impressum-hero {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-grid,
|
||||||
|
.notes-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ Ich baue alleine neben meiner Ausbildung eine einfache self-hosted Web-App für
|
|||||||
- `GUI/src/routes/Home.vue` ist jetzt eine Produkt-Startseite (Landingpage) zur App-Vorstellung statt einer Dashboard-Platzhalterkarte.
|
- `GUI/src/routes/Home.vue` ist jetzt eine Produkt-Startseite (Landingpage) zur App-Vorstellung statt einer Dashboard-Platzhalterkarte.
|
||||||
- Das Brand-Element in `GUI/src/Layout.vue` nutzt nun das App-Icon (`GUI/src/assets/images/icon.png`) statt eines Platzhalter-Buchstabens; die Darstellung wurde im Topbar-Button sichtbar vergrößert.
|
- Das Brand-Element in `GUI/src/Layout.vue` nutzt nun das App-Icon (`GUI/src/assets/images/icon.png`) statt eines Platzhalter-Buchstabens; die Darstellung wurde im Topbar-Button sichtbar vergrößert.
|
||||||
- Das Topbar-Icon in `GUI/src/Layout.vue` wurde nochmals deutlich größer gesetzt, damit das Branding besser sichtbar ist.
|
- Das Topbar-Icon in `GUI/src/Layout.vue` wurde nochmals deutlich größer gesetzt, damit das Branding besser sichtbar ist.
|
||||||
|
- `GUI/src/routes/Impressum.vue` wurde von einem Platzhalter auf eine vollständige, designkonforme Impressum-Seite mit klarer Struktur und Testdaten umgestellt.
|
||||||
|
|
||||||
## Änderungen durch Codex
|
## Änderungen durch Codex
|
||||||
- Layout-Neubau in `GUI/src/Layout.vue` mit Brand-Bereich, Seitenkontext aus Route-Metadaten, überarbeiteter Navigation und designkonformer Footer-Struktur.
|
- Layout-Neubau in `GUI/src/Layout.vue` mit Brand-Bereich, Seitenkontext aus Route-Metadaten, überarbeiteter Navigation und designkonformer Footer-Struktur.
|
||||||
@@ -96,3 +97,4 @@ Ich baue alleine neben meiner Ausbildung eine einfache self-hosted Web-App für
|
|||||||
- In `GUI/src/plugins/routesLayout.ts` wurde ein kurzer Kommentar ergänzt, der die Nutzung von `Visibility.Public`, `Visibility.Route`, `visibilityRoute` (einzeln/mehrfach) sowie typische Szenarien für die Sidebar-Sichtbarkeit beschreibt.
|
- In `GUI/src/plugins/routesLayout.ts` wurde ein kurzer Kommentar ergänzt, der die Nutzung von `Visibility.Public`, `Visibility.Route`, `visibilityRoute` (einzeln/mehrfach) sowie typische Szenarien für die Sidebar-Sichtbarkeit beschreibt.
|
||||||
- Fokusdarstellung in `GUI/src/global.css` für Vuetify-Inputs verbessert: Der doppelte grüne Fokusrahmen (zusätzlicher `focus-visible`-Outline im inneren `<input>`) wird unterdrückt; der Fokus bleibt über den Feldrahmen klar sichtbar.
|
- Fokusdarstellung in `GUI/src/global.css` für Vuetify-Inputs verbessert: Der doppelte grüne Fokusrahmen (zusätzlicher `focus-visible`-Outline im inneren `<input>`) wird unterdrückt; der Fokus bleibt über den Feldrahmen klar sichtbar.
|
||||||
- Textauswahl (`::selection`) in `GUI/src/global.css` von kräftigem Grün auf eine subtilere Primär-Tönung reduziert, damit markierte Inhalte ruhiger wirken.
|
- Textauswahl (`::selection`) in `GUI/src/global.css` von kräftigem Grün auf eine subtilere Primär-Tönung reduziert, damit markierte Inhalte ruhiger wirken.
|
||||||
|
- `GUI/src/routes/Impressum.vue` vollständig neu aufgebaut: Hero-Bereich, strukturierte Anbieter-/Kontakt-/Registerdaten, rechtliche Hinweisblöcke und klare Kennzeichnung als Testdaten im bestehenden Hoard-Design.
|
||||||
|
|||||||
Reference in New Issue
Block a user