feat(T02): Static pages – home, referenzen, kontakt, legal (impressum/datenschutz/agb)
This commit is contained in:
@@ -1,7 +1,108 @@
|
||||
<template>
|
||||
<LegalContentPage title="AGB Vermietung" :content="content" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({ title: "AGB Vermietung – HMS Licht & Ton", meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }] });
|
||||
const content = `<p>Allgemeine Geschäftsbedingungen für die Vermietung.</p>`;
|
||||
</script>
|
||||
useHead({
|
||||
title: "AGB Vermietung – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
});
|
||||
|
||||
const content = `
|
||||
<h2>§ 1 Geltungsbereich</h2>
|
||||
<p>
|
||||
Diese Allgemeinen Geschäftsbedingungen (AGB) gelten für alle Mietverträge über
|
||||
Veranstaltungstechnik zwischen der Hammerschmidt u. Mössle GbR (nachfolgend „HMS
|
||||
Licht & Ton“ oder „Vermieter“) und dem Mieter. Sie gelten ausschließlich;
|
||||
entgegenstehende oder von unseren AGB abweichende Bedingungen des Mieters
|
||||
erkennen wir nicht an, es sei denn, wir hätten ausdrücklich schriftlich ihrer
|
||||
Geltung zugestimmt.
|
||||
</p>
|
||||
|
||||
<h2>§ 2 Mietgegenstand</h2>
|
||||
<p>
|
||||
Gegenstand des Mietvertrages ist die Überlassung von Veranstaltungstechnik
|
||||
(Lautsprecher, Mischpulte, Lichtanlagen, Rigging-Material, Traversen,
|
||||
Zubehör etc.) gemäß der im Mietvertrag bzw. in der Auftragsbestätigung
|
||||
angegebenen Spezifikation. Der Vermieter schuldet nicht die Durchführung der
|
||||
Veranstaltung, sondern nur die Überlassung der gemieteten Technik in
|
||||
vertragsgemäßem Zustand.
|
||||
</p>
|
||||
|
||||
<h2>§ 3 Preise</h2>
|
||||
<p>
|
||||
Es gelten die zum Zeitpunkt der Auftragsbestätigung im Mietkatalog bzw. im
|
||||
Angebot angegebenen Preise. Alle Preise verstehen sich zzgl. der gesetzlich
|
||||
geltenden Mehrwertsteuer. Miettage berechnen sich ab Abholung bzw. Anlieferung
|
||||
bis zur Rückgabe bzw. Abholung durch den Vermieter. Ein Miettag entspricht
|
||||
24 Stunden. Bei Überschreitung der vereinbarten Mietzeit werden zusätzliche
|
||||
Miettage berechnet.
|
||||
</p>
|
||||
|
||||
<h2>§ 4 Zahlungsbedingungen</h2>
|
||||
<p>
|
||||
Die Zahlung ist innerhalb von 14 Tagen nach Rechnungsstellung ohne Abzug
|
||||
fällig, sofern nichts anderes vereinbart wurde. Bei Neukunden kann eine
|
||||
Anzahlung in Höhe von 50 % des Gesamtmietpreises vor Übergabe der Technik
|
||||
verlangt werden. Die Aufrechnung mit Gegenansprüchen ist nur zulässig,
|
||||
soweit diese unbestritten oder rechtskräftig festgestellt sind.
|
||||
</p>
|
||||
|
||||
<h2>§ 5 Haftung des Mieters</h2>
|
||||
<p>
|
||||
Der Mieter hat das Mietmaterial pfleglich zu behandeln und vor Beschädigung,
|
||||
Diebstahl und unsachgemäßer Nutzung zu schützen. Der Mieter haftet für alle
|
||||
Schäden am Mietmaterial, die während der Mietzeit entstehen, soweit sie nicht
|
||||
auf normaler Abnutzung beruhen. Bei Verlust oder Diebstahl trägt der Mieter
|
||||
den Wiederbeschaffungswert. Bei Beschädigung trägt der Mieter die
|
||||
Reparaturkosten oder den Zeitwert bei Totalschaden.
|
||||
</p>
|
||||
<p>
|
||||
Eine Haftung des Vermieters für indirekte Schäden, insbesondere für
|
||||
Gewinnverluste, Ausfallkosten oder Folgeschäden der Veranstaltung, ist
|
||||
ausgeschlossen, soweit diese nicht auf Vorsatz oder grober Fahrlässigkeit
|
||||
beruhen.
|
||||
</p>
|
||||
|
||||
<h2>§ 6 Übergabe und Rückgabe</h2>
|
||||
<p>
|
||||
Die Übergabe des Mietmaterials erfolgt am Lager des Vermieters oder an dem
|
||||
vereinbarten Veranstaltungsort. Der Mieter hat das Mietmaterial bei
|
||||
Übergabe auf Vollständigkeit und Schäden zu prüfen. Mängel sind sofort
|
||||
schriftlich zu melden. Bei der Rückgabe wird das Mietmaterial erneut
|
||||
geprüft. Fehlbestände oder Schäden, die erst bei der Rückgabe festgestellt
|
||||
werden, gelten als während der Mietzeit entstanden, sofern der Mieter nicht
|
||||
den Beweis erbringt, dass der Schaden bereits bei Übergabe vorlag.
|
||||
</p>
|
||||
<p>
|
||||
Das Mietmaterial ist nach Ende der Mietzeit in gereinigtem und
|
||||
sortiertem Zustand zurückzugeben. Verpackungsmaterial ist vollständig
|
||||
zurückzugeben. Nicht rechtzeitig zurückgegebenes Material wird bis zur
|
||||
Rückgabe weiterberechnet.
|
||||
</p>
|
||||
|
||||
<h2>§ 7 Kündigung und Rücktritt</h2>
|
||||
<p>
|
||||
Der Mieter kann den Mietvertrag jederzeit vor Übergabe des Mietmaterials
|
||||
schriftlich kündigen. Bei Kündigung bis 14 Tage vor Mietbeginn werden 25 %,
|
||||
bis 7 Tage 50 %, bis 3 Tage 75 % und ab 3 Tagen 100 % des Mietpreises als
|
||||
Stornokosten berechnet.
|
||||
</p>
|
||||
<p>
|
||||
Der Vermieter behält sich vor, vom Vertrag zurückzutreten, wenn die
|
||||
Verfügung über das Mietmaterial aus Gründen, die der Vermieter nicht zu
|
||||
vertreten hat, unmöglich wird (z. B. höhere Gewalt, höhere Gewalt,
|
||||
unvorhersehbare Ereignisse). In diesem Fall werden bereits gezahlte
|
||||
Mietkosten erstattet.
|
||||
</p>
|
||||
|
||||
<h2>§ 8 Schlussbestimmungen</h2>
|
||||
<p>
|
||||
Es gilt das Recht der Bundesrepublik Deutschland. Gerichtsstand ist
|
||||
Günzburg. Sollten einzelne Bestimmungen dieser AGB unwirksam sein, so
|
||||
bleibt die Wirksamkeit der übrigen Bestimmungen unberührt. An die Stelle
|
||||
der unwirksamen Bestimmung tritt eine Regelung, die dem wirtschaftlichen
|
||||
Zweck der unwirksamen Bestimmung am nächsten kommt.
|
||||
</p>
|
||||
`;
|
||||
</script>
|
||||
@@ -1,7 +1,108 @@
|
||||
<template>
|
||||
<LegalContentPage title="Datenschutz (DSGVO)" :content="content" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({ title: "Datenschutz – HMS Licht & Ton", meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }] });
|
||||
const content = `<p>Datenschutzerklärung gemäß DSGVO.</p>`;
|
||||
</script>
|
||||
useHead({
|
||||
title: "Datenschutz – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
});
|
||||
|
||||
const content = `
|
||||
<h2>1. Datenschutz auf einen Blick</h2>
|
||||
<p>
|
||||
Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren
|
||||
personenbezogenen Daten passiert, wenn Sie diese Website besuchen oder unser
|
||||
Kontaktformular nutzen. Personenbezogene Daten sind alle Daten, mit denen Sie
|
||||
persönlich identifiziert werden können.
|
||||
</p>
|
||||
|
||||
<h3>Datenerhebung</h3>
|
||||
<p>
|
||||
Die Datenerhebung auf dieser Website erfolgt technisch notwendig zur Bereitstellung
|
||||
der Website und zur Gewährleistung der Funktionstüchtigkeit und Sicherheit der
|
||||
Systeme. Darüber hinaus werden Daten nur erhoben, wenn Sie uns diese im Rahmen
|
||||
des Kontaktformulars freiwillig zur Verfügung stellen.
|
||||
</p>
|
||||
|
||||
<h3>Cookies</h3>
|
||||
<p>
|
||||
Diese Website verwendet keine Tracking-Cookies. Technisch notwendige Cookies,
|
||||
die für den Betrieb der Seite erforderlich sind, werden nur verwendet, soweit
|
||||
dies für die Bereitstellung der Funktionalität der Website zwingend notwendig
|
||||
ist. Sie können die Speicherung solcher Cookies durch entsprechende Einstellungen
|
||||
in Ihrem Browser verhindern.
|
||||
</p>
|
||||
|
||||
<h2>2. Verantwortliche Stelle</h2>
|
||||
<p>
|
||||
Verantwortlich für die Datenverarbeitung auf dieser Website ist:<br/>
|
||||
Hammerschmidt u. Mössle GbR<br/>
|
||||
Grockelhofen 10<br/>
|
||||
89340 Leipheim<br/>
|
||||
Telefon: +49 (0) 8221 / 204433<br/>
|
||||
E-Mail: info@hms-licht-ton.de
|
||||
</p>
|
||||
|
||||
<h2>3. Erhebung von Daten beim Kontaktformular</h2>
|
||||
<p>
|
||||
Wenn Sie uns über das Kontaktformular Anfragen zukommen lassen, werden Ihre
|
||||
Angaben aus dem Anfrageformular inklusive der von Ihnen dort angegebenen
|
||||
Kontaktdaten zwecks Bearbeitung der Anfrage und für den Fall von Anschlussfragen
|
||||
bei uns gespeichert. Diese Daten geben wir nicht ohne Ihre Einwilligung weiter.
|
||||
</p>
|
||||
<p>
|
||||
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b
|
||||
DSGVO, sofern Ihre Anfrage mit der Erfüllung eines Vertrags zusammenhängt oder
|
||||
zur Durchführung vorvertraglicher Maßnahmen erforderlich ist. In allen
|
||||
übrigen Fällen ist die Verarbeitung auf Grundlage Ihres berechtigten
|
||||
Interesses (Art. 6 Abs. 1 lit. f DSGVO) oder auf Grundlage Ihrer Einwilligung
|
||||
(Art. 6 Abs. 1 lit. a DSGVO) erfolgt.
|
||||
</p>
|
||||
<p>
|
||||
Die Daten werden gelöscht, sobald sie für die Erreichung des Zweckes ihrer
|
||||
Erhebung nicht mehr erforderlich sind. Für die personenbezogenen Daten aus
|
||||
dem Eingabeformular der Kontaktanfrage ist dies der Fall, wenn die jeweilige
|
||||
Konversation mit Ihnen beendet ist. Der Gesprächsbeginn endet, wenn aus den
|
||||
Umständen zu entnehmen ist, dass der betroffene Sachverhalt abschließend
|
||||
geklärt ist.
|
||||
</p>
|
||||
|
||||
<h2>4. Server-Log-Dateien</h2>
|
||||
<p>
|
||||
Der Provider der Seiten erhebt und speichert automatisch Informationen in
|
||||
sogenannten Server-Log-Dateien, die Ihr Browser automatisch an uns übermittelt.
|
||||
Diese sind:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Browsertyp und Browserversion</li>
|
||||
<li>verwendetes Betriebssystem</li>
|
||||
<li>Referrer URL</li>
|
||||
<li>Hostname des zugreifenden Rechners</li>
|
||||
<li>Uhrzeit der Serveranfrage</li>
|
||||
<li>IP-Adresse (anonymisiert)</li>
|
||||
</ul>
|
||||
<p>
|
||||
Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht
|
||||
vorgenommen. Die Verarbeitung erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f
|
||||
DSGVO zum Zweck der Gewährleistung eines reibungslosen Betriebs der Website.
|
||||
</p>
|
||||
|
||||
<h2>5. Weitergabe an Drittanbieter</h2>
|
||||
<p>
|
||||
Eine Übermittlung Ihrer persönlichen Daten an Dritte zu anderen als den im
|
||||
Folgenden aufgeführten Zwecken findet nicht statt. Eine Weitergabe erfolgt nur,
|
||||
wenn Sie eine ausdrückliche Einwilligung dazu erteilt haben oder die
|
||||
Weitergabe gesetzlich zulässig ist.
|
||||
</p>
|
||||
|
||||
<h2>6. Ihre Rechte</h2>
|
||||
<p>
|
||||
Sie haben das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der
|
||||
Verarbeitung, Widerspruch gegen die Verarbeitung und das Recht auf
|
||||
Datenübertragbarkeit (Art. 15–20 DSGVO). Zudem haben Sie das Recht, sich bei
|
||||
einer Datenschutz-Aufsichtsbehörde über die Verarbeitung Ihrer
|
||||
personenbezogenen Daten zu beschweren.
|
||||
</p>
|
||||
`;
|
||||
</script>
|
||||
@@ -1,7 +1,79 @@
|
||||
<template>
|
||||
<LegalContentPage title="Impressum" :content="impressumContent" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({ title: "Impressum – HMS Licht & Ton", meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }] });
|
||||
const impressumContent = `<p>Hammerschmidt u. Mössle GbR</p><p>Grockelhofen 10, 89340 Leipheim</p><p>Telefon: +49 (0) 8221 / 204433</p><p>E-Mail: info@hms-licht-ton.de</p>`;
|
||||
</script>
|
||||
useHead({
|
||||
title: "Impressum – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
});
|
||||
|
||||
const impressumContent = `
|
||||
<h2>Angaben gemäß § 5 TMG</h2>
|
||||
<p>
|
||||
Hammerschmidt u. Mössle GbR<br/>
|
||||
Grockelhofen 10<br/>
|
||||
89340 Leipheim
|
||||
</p>
|
||||
|
||||
<h2>Kontakt</h2>
|
||||
<p>
|
||||
Telefon: +49 (0) 8221 / 204433<br/>
|
||||
E-Mail: <a href="mailto:info@hms-licht-ton.de">info@hms-licht-ton.de</a>
|
||||
</p>
|
||||
|
||||
<h2>Vertretungsberechtigte</h2>
|
||||
<p>
|
||||
Markus Hammerschmidt<br/>
|
||||
Thomas Mössle
|
||||
</p>
|
||||
|
||||
<h2>Registereintrag</h2>
|
||||
<p>
|
||||
Eintragung im Registergericht: Amtsgericht Günzburg<br/>
|
||||
Registernummer: HRA 12345 (Beispiel – wird nachgeliefert)
|
||||
</p>
|
||||
|
||||
<h2>Umsatzsteuer-ID</h2>
|
||||
<p>
|
||||
Umsatzsteuer-Identifikationsnummer gemäß § 27a Umsatzsteuergesetz:<br/>
|
||||
DE 123456789 (Beispiel – wird nachgeliefert)
|
||||
</p>
|
||||
|
||||
<h2>Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h2>
|
||||
<p>
|
||||
Markus Hammerschmidt<br/>
|
||||
Grockelhofen 10<br/>
|
||||
89340 Leipheim
|
||||
</p>
|
||||
|
||||
<h2>Haftung für Inhalte</h2>
|
||||
<p>
|
||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den
|
||||
allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht
|
||||
verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach
|
||||
Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.
|
||||
</p>
|
||||
<p>
|
||||
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen
|
||||
Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt
|
||||
der Kenntnis einer konkreten Rechtsverletzung möglich.
|
||||
</p>
|
||||
|
||||
<h2>Haftung für Links</h2>
|
||||
<p>
|
||||
Unser Angebot enthält ggf. Links zu externen Websites Dritter, auf deren Inhalte wir keinen
|
||||
Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen.
|
||||
Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der
|
||||
Seiten verantwortlich.
|
||||
</p>
|
||||
|
||||
<h2>Urheberrecht</h2>
|
||||
<p>
|
||||
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem
|
||||
deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der
|
||||
Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des
|
||||
jeweiligen Autors bzw. Erstellers.
|
||||
</p>
|
||||
`;
|
||||
</script>
|
||||
+153
-12
@@ -1,19 +1,83 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="mb-12">
|
||||
<p class="text-sm text-accent font-semibold mb-2">Seit 2003 · Über 20 Jahre Veranstaltungstechnik</p>
|
||||
<h1 class="text-4xl lg:text-5xl font-extrabold mb-4">Professionelle Technik für Ihre Veranstaltung</h1>
|
||||
<p class="text-text-muted text-lg mb-6 max-w-2xl">
|
||||
Von der Firmenevent-Beschallung bis zur Open-Air-Großproduktion: HMS Licht & Ton liefert
|
||||
Tontechnik, Lichttechnik, Rigging und Komplettlösungen aus Leipheim und Ellzee.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<NuxtLink to="/mietkatalog" class="btn-primary">Mietkatalog öffnen</NuxtLink>
|
||||
<NuxtLink to="/kontakt" class="btn-secondary">Beratung anfragen</NuxtLink>
|
||||
<!-- Hero Section -->
|
||||
<section class="relative mb-16 overflow-hidden rounded-lg">
|
||||
<div class="absolute inset-0 bg-bg">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1505236858219-8359eb222e89?w=1600&q=80"
|
||||
alt="Veranstaltungstechnik"
|
||||
class="w-full h-full object-cover opacity-30"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-bg via-bg/80 to-bg/50" />
|
||||
<div class="relative px-6 py-20 lg:py-32 max-w-4xl">
|
||||
<p class="text-sm text-accent font-semibold mb-2">Seit 2003 · Über 20 Jahre Veranstaltungstechnik</p>
|
||||
<h1 class="text-4xl lg:text-6xl font-extrabold mb-4" data-testid="hero-headline">
|
||||
Veranstaltungstechnik
|
||||
</h1>
|
||||
<p class="text-text-muted text-lg lg:text-xl mb-8 max-w-2xl">
|
||||
Professionelle Tontechnik, Lichttechnik, Rigging und Komplettlösungen
|
||||
für Ihre Veranstaltung. Von der Firmenevent-Beschallung bis zur
|
||||
Open-Air-Großproduktion – HMS Licht & Ton liefert aus Leipheim und Ellzee.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<NuxtLink to="/mietkatalog" class="btn-primary" data-testid="hero-cta-mietkatalog">
|
||||
Mietkatalog öffnen
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/kontakt" class="btn-secondary" data-testid="hero-cta-kontakt">
|
||||
Beratung anfragen
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<!-- Speaker Grid (Equipment Types) -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-2xl font-bold mb-6">Unser Equipment</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-4" data-testid="speaker-grid">
|
||||
<div
|
||||
v-for="eq in equipmentTypes"
|
||||
:key="eq.label"
|
||||
class="flex flex-col items-center gap-3 p-5 rounded-lg border border-border-default bg-panel hover:border-accent-border transition-colors duration-fast"
|
||||
>
|
||||
<div class="w-12 h-12 flex items-center justify-center text-secondary">
|
||||
<component :is="eq.icon" />
|
||||
</div>
|
||||
<span class="text-xs text-text-muted text-center">{{ eq.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Über uns Section -->
|
||||
<section class="mb-16 bg-panel rounded-lg p-8" data-testid="about-section">
|
||||
<h2 class="text-2xl font-bold mb-6">Über uns</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6 mb-6">
|
||||
<div class="text-center">
|
||||
<p class="text-4xl font-extrabold text-accent mb-1" data-testid="stat-years">20+</p>
|
||||
<p class="text-sm text-text-muted">Jahre Erfahrung</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-4xl font-extrabold text-accent mb-1" data-testid="stat-devices">1000+</p>
|
||||
<p class="text-sm text-text-muted">Geräte im Mietpark</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-4xl font-extrabold text-accent mb-1" data-testid="stat-events">500+</p>
|
||||
<p class="text-sm text-text-muted">Events betreut</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-text-muted text-sm max-w-3xl">
|
||||
HMS Licht & Ton ist Ihr verlässlicher Partner für Veranstaltungstechnik in
|
||||
Bayerisch-Schwaben und darüber hinaus. Seit über 20 Jahren planen, liefern und
|
||||
betreiben wir Technik für Konzerte, Firmenevents, Festspiele und private
|
||||
Feiern. Unser Team aus erfahrenen Tontechnikern, Lichttechnikern und Rigging-Spezialisten
|
||||
sorgt dafür, dass Ihre Veranstaltung perfekt läuft – vom ersten Beratungsgespräch
|
||||
bis zum letzten Kabel am Abbau.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- 8 Service Cards -->
|
||||
<section class="mb-16" data-testid="services-section">
|
||||
<h2 class="text-2xl font-bold mb-6">Leistungen</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div
|
||||
@@ -26,10 +90,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Mietkatalog CTA -->
|
||||
<section class="mb-12 text-center bg-panel rounded-lg p-10" data-testid="mietkatalog-cta">
|
||||
<h2 class="text-2xl font-bold mb-4">Bereit für Ihr nächstes Event?</h2>
|
||||
<p class="text-text-muted mb-6 max-w-2xl mx-auto">
|
||||
Durchstöbern Sie unseren Mietkatalog mit über 1.000 Artikeln – von Lautsprechern
|
||||
über Lichtanlagen bis zu Rigging-Material.
|
||||
</p>
|
||||
<NuxtLink to="/mietkatalog" class="btn-primary" data-testid="cta-mietkatalog-link">
|
||||
Zum Mietkatalog
|
||||
</NuxtLink>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from "vue";
|
||||
|
||||
useHead({
|
||||
title: "HMS Licht & Ton – Veranstaltungstechnik Leipheim/Ellzee",
|
||||
meta: [
|
||||
@@ -48,5 +126,68 @@ const services = [
|
||||
{ title: "Verkauf", description: "Neu- und Gebrauchtgeräte führender Hersteller mit Beratung, Inbetriebnahme und Service." },
|
||||
{ title: "Personal", description: "Qualifizierte Tontechniker, Lichttechniker und Rigger für Aufbau, Betrieb und Abbau." },
|
||||
{ title: "Transport", description: "Eigene Transportfahrzeuge für sichere An- und Ablieferung inklusive Verladekonzept." },
|
||||
{ title: "Lagerung", description: "Klimatisierte und gesicherte Lagerung für empfindliche Technik zwischen den Einsätzen." },
|
||||
{ title: "Werkstatt", description: "Reparatur und Wartung eigener sowie fremder Geräte durch unsere zertifizierten Techniker." },
|
||||
{ title: "Installation", description: "Festinstallationen in Veranstaltungsräumen, Kirchen, Schulen und Firmengebäuden." },
|
||||
{ title: "Booking", description: "Vermittlung von Künstlern, DJs und Technikern für Ihre Veranstaltung aus unserem Partnernetzwerk." },
|
||||
];
|
||||
</script>
|
||||
|
||||
type EquipmentIcon = () => ReturnType<typeof h>;
|
||||
|
||||
const equipmentTypes: { label: string; icon: EquipmentIcon }[] = [
|
||||
{
|
||||
label: "Lautsprecher",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("rect", { x: 8, y: 8, width: 32, height: 32, rx: 2, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("circle", { cx: 24, cy: 24, r: 8, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("circle", { cx: 24, cy: 24, r: 4, fill: "none", stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Mischpulte",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("rect", { x: 6, y: 12, width: 36, height: 24, rx: 2, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("line", { x1: 14, y1: 18, x2: 14, y2: 30, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 22, y1: 18, x2: 22, y2: 30, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 30, y1: 18, x2: 30, y2: 30, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("circle", { cx: 14, cy: 30, r: 3, fill: "none", stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Lichtanlagen",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("rect", { x: 18, y: 6, width: 12, height: 10, rx: 1, fill: "currentColor" }),
|
||||
h("path", { d: "M24 16 L24 24", stroke: "currentColor", "stroke-width": 2, "stroke-linecap": "round" }),
|
||||
h("circle", { cx: 24, cy: 30, r: 6, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("path", { d: "M18 30 L14 30 M30 30 L34 30", stroke: "currentColor", "stroke-width": 1.5, "stroke-linecap": "round", opacity: 0.5 }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Rigging",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("path", { d: "M24 6 L24 18", stroke: "currentColor", "stroke-width": 2, "stroke-linecap": "round" }),
|
||||
h("rect", { x: 16, y: 18, width: 16, height: 20, rx: 2, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("path", { d: "M20 18 L16 10 M28 18 L32 10", stroke: "currentColor", "stroke-width": 1.5, "stroke-linecap": "round" }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Traversen",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("rect", { x: 6, y: 20, width: 36, height: 8, rx: 1, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("line", { x1: 12, y1: 20, x2: 12, y2: 28, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 18, y1: 20, x2: 18, y2: 28, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 24, y1: 20, x2: 24, y2: 28, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 30, y1: 20, x2: 30, y2: 28, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
h("line", { x1: 36, y1: 20, x2: 36, y2: 28, stroke: "currentColor", "stroke-width": 1.5 }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Komplett-Setups",
|
||||
icon: () => h("svg", { width: 48, height: 48, viewBox: "0 0 48 48", fill: "none" }, [
|
||||
h("circle", { cx: 24, cy: 24, r: 18, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
h("path", { d: "M24 6 L24 18 M6 24 L18 24 M24 30 L24 42 M30 24 L42 24", stroke: "currentColor", "stroke-width": 1.5, "stroke-linecap": "round" }),
|
||||
h("circle", { cx: 24, cy: 24, r: 6, fill: "none", stroke: "currentColor", "stroke-width": 2 }),
|
||||
]),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
+280
-4
@@ -1,9 +1,285 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-text mb-4">Kontakt</h1>
|
||||
<p class="text-text-muted">Kontaktformular wird hier angezeigt.</p>
|
||||
<h1 class="text-3xl font-bold text-text mb-2" data-testid="kontakt-headline">Kontakt</h1>
|
||||
<p class="text-text-muted mb-8">Planen Sie mit uns Ihre nächste Veranstaltung.</p>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-12">
|
||||
<!-- Left Column: Addresses + Persons -->
|
||||
<div class="space-y-6">
|
||||
<!-- Office Address -->
|
||||
<div class="bg-panel border border-border-default rounded-lg p-6" data-testid="office-card">
|
||||
<h2 class="text-accent text-sm font-bold mb-3">Büro</h2>
|
||||
<p class="text-text mb-1">Hammerschmidt u. Mössle GbR</p>
|
||||
<p class="text-text-muted text-sm mb-1">Grockelhofen 10</p>
|
||||
<p class="text-text-muted text-sm mb-3">89340 Leipheim</p>
|
||||
<p class="text-text-muted text-sm mb-1">Tel: <a href="tel:+498221204433" class="text-accent hover:underline">+49 8221 204433</a></p>
|
||||
<p class="text-text-muted text-sm">E-Mail: <a href="mailto:info@hms-licht-ton.de" class="text-accent hover:underline">info@hms-licht-ton.de</a></p>
|
||||
</div>
|
||||
|
||||
<!-- Warehouse Address -->
|
||||
<div class="bg-panel border border-border-default rounded-lg p-6" data-testid="warehouse-card">
|
||||
<h2 class="text-accent text-sm font-bold mb-3">Lager / Werkstatt</h2>
|
||||
<p class="text-text-muted text-sm mb-1">Ellzee</p>
|
||||
<p class="text-text-muted text-sm mb-3">Bayern, Deutschland</p>
|
||||
<p class="text-text-muted text-sm">Besuche nach Terminvereinbarung.</p>
|
||||
</div>
|
||||
|
||||
<!-- Opening Hours -->
|
||||
<div class="bg-panel border border-border-default rounded-lg p-6" data-testid="hours-card">
|
||||
<h2 class="text-accent text-sm font-bold mb-3">Öffnungszeiten</h2>
|
||||
<div class="space-y-1 text-text-muted text-sm">
|
||||
<p>Mo – Do: 08:00 – 17:00</p>
|
||||
<p>Fr: 08:00 – 14:00</p>
|
||||
<p>Sa – So: Geschlossen</p>
|
||||
<p class="text-accent text-xs mt-2">Termine außerhalb der Öffnungszeiten nach Vereinbarung.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Persons -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div v-for="person in contactPersons" :key="person.name" class="bg-panel border border-border-default rounded-lg p-5" :data-testid="'contact-person-' + person.name.split(' ')[0].toLowerCase()">
|
||||
<div class="w-16 h-16 rounded-full bg-card border border-border-default mb-3 flex items-center justify-center text-secondary">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
|
||||
<circle cx="16" cy="12" r="5" fill="none" stroke="currentColor" stroke-width="2" />
|
||||
<path d="M6 28 Q16 20 26 28" fill="none" stroke="currentColor" stroke-width="2" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-text text-sm font-bold">{{ person.name }}</p>
|
||||
<p class="text-accent text-xs mb-1">{{ person.role }}</p>
|
||||
<a :href="'mailto:' + person.email" class="text-text-muted text-xs hover:text-accent transition-colors duration-fast">{{ person.email }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column: Contact Form -->
|
||||
<div class="bg-panel border border-border-default rounded-lg p-6" data-testid="contact-form-card">
|
||||
<h2 class="text-2xl font-bold mb-6">Anfrage senden</h2>
|
||||
|
||||
<!-- Success State -->
|
||||
<div v-if="submitSuccess" class="bg-success-bg border border-success/30 rounded-lg p-6 text-center" data-testid="success-message">
|
||||
<p class="text-success font-bold text-lg mb-2">Vielen Dank!</p>
|
||||
<p class="text-text-muted text-sm">Ihre Nachricht wurde erfolgreich gesendet. Wir melden uns in Kürze bei Ihnen.</p>
|
||||
<button class="btn-secondary mt-4" @click="resetForm" data-testid="reset-form">Neue Nachricht</button>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div v-else-if="submitError" class="bg-error-bg border border-error/30 rounded-lg p-6 text-center" data-testid="error-message">
|
||||
<p class="text-error font-bold text-lg mb-2">Fehler</p>
|
||||
<p class="text-text-muted text-sm mb-4">Beim Senden ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.</p>
|
||||
<button class="btn-primary" @click="submitError = false" data-testid="retry-submit">Erneut versuchen</button>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<form v-else @submit.prevent="handleSubmit" novalidate data-testid="contact-form">
|
||||
<!-- Name -->
|
||||
<div class="mb-4">
|
||||
<label for="name" class="block text-text-muted text-sm mb-1">Name *</label>
|
||||
<input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="w-full bg-surface border border-border-default rounded-md px-3 py-2 text-text focus:border-accent focus:outline-none"
|
||||
:class="{ 'border-error': errors.name }"
|
||||
data-testid="form-name"
|
||||
@blur="validateField('name')"
|
||||
/>
|
||||
<p v-if="errors.name" class="text-error text-xs mt-1" data-testid="error-name">{{ errors.name }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="mb-4">
|
||||
<label for="email" class="block text-text-muted text-sm mb-1">E-Mail *</label>
|
||||
<input
|
||||
id="email"
|
||||
v-model="form.email"
|
||||
type="email"
|
||||
class="w-full bg-surface border border-border-default rounded-md px-3 py-2 text-text focus:border-accent focus:outline-none"
|
||||
:class="{ 'border-error': errors.email }"
|
||||
data-testid="form-email"
|
||||
@blur="validateField('email')"
|
||||
/>
|
||||
<p v-if="errors.email" class="text-error text-xs mt-1" data-testid="error-email">{{ errors.email }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Phone -->
|
||||
<div class="mb-4">
|
||||
<label for="phone" class="block text-text-muted text-sm mb-1">Telefon</label>
|
||||
<input
|
||||
id="phone"
|
||||
v-model="form.phone"
|
||||
type="tel"
|
||||
class="w-full bg-surface border border-border-default rounded-md px-3 py-2 text-text focus:border-accent focus:outline-none"
|
||||
data-testid="form-phone"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Message -->
|
||||
<div class="mb-4">
|
||||
<label for="message" class="block text-text-muted text-sm mb-1">Nachricht *</label>
|
||||
<textarea
|
||||
id="message"
|
||||
v-model="form.message"
|
||||
rows="5"
|
||||
class="w-full bg-surface border border-border-default rounded-md px-3 py-2 text-text focus:border-accent focus:outline-none"
|
||||
:class="{ 'border-error': errors.message }"
|
||||
data-testid="form-message"
|
||||
@blur="validateField('message')"
|
||||
></textarea>
|
||||
<p v-if="errors.message" class="text-error text-xs mt-1" data-testid="error-message-field">{{ errors.message }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Privacy Consent -->
|
||||
<div class="mb-6">
|
||||
<label class="flex items-start gap-3 cursor-pointer">
|
||||
<input
|
||||
v-model="form.privacy"
|
||||
type="checkbox"
|
||||
class="mt-1 w-4 h-4 rounded border-border-default bg-surface accent-accent"
|
||||
:class="{ 'border-error': errors.privacy }"
|
||||
data-testid="form-privacy"
|
||||
/>
|
||||
<span class="text-text-muted text-sm">
|
||||
Ich habe die <NuxtLink to="/datenschutz" class="text-accent hover:underline">Datenschutzerklärung</NuxtLink> gelesen und stimme zu, dass meine Daten zur Bearbeitung meiner Anfrage gespeichert werden. *
|
||||
</span>
|
||||
</label>
|
||||
<p v-if="errors.privacy" class="text-error text-xs mt-1" data-testid="error-privacy">{{ errors.privacy }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-primary w-full"
|
||||
:disabled="isSubmitting"
|
||||
data-testid="form-submit"
|
||||
>
|
||||
{{ isSubmitting ? "Wird gesendet..." : "Anfrage senden" }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({ title: "Kontakt – HMS Licht & Ton", meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }] });
|
||||
</script>
|
||||
import { reactive, ref } from "vue";
|
||||
|
||||
useHead({
|
||||
title: "Kontakt – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
});
|
||||
|
||||
const contactPersons = [
|
||||
{ name: "Markus Hammerschmidt", role: "Geschäftsführer – Ton & Verkauf", email: "m.hammerschmidt@hms-licht-ton.de" },
|
||||
{ name: "Thomas Mössle", role: "Geschäftsführer – Licht & Rigging", email: "t.moessle@hms-licht-ton.de" },
|
||||
];
|
||||
|
||||
interface ContactForm {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
message: string;
|
||||
privacy: boolean;
|
||||
}
|
||||
|
||||
interface FormErrors {
|
||||
name?: string;
|
||||
email?: string;
|
||||
message?: string;
|
||||
privacy?: string;
|
||||
}
|
||||
|
||||
const form = reactive<ContactForm>({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
message: "",
|
||||
privacy: false,
|
||||
});
|
||||
|
||||
const errors = reactive<FormErrors>({});
|
||||
const isSubmitting = ref(false);
|
||||
const submitSuccess = ref(false);
|
||||
const submitError = ref(false);
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
function validateField(field: keyof FormErrors): boolean {
|
||||
switch (field) {
|
||||
case "name":
|
||||
if (!form.name.trim()) {
|
||||
errors.name = "Bitte geben Sie Ihren Namen ein.";
|
||||
return false;
|
||||
}
|
||||
delete errors.name;
|
||||
return true;
|
||||
case "email":
|
||||
if (!form.email.trim()) {
|
||||
errors.email = "Bitte geben Sie Ihre E-Mail-Adresse ein.";
|
||||
return false;
|
||||
}
|
||||
if (!emailRegex.test(form.email)) {
|
||||
errors.email = "Bitte geben Sie eine gültige E-Mail-Adresse ein.";
|
||||
return false;
|
||||
}
|
||||
delete errors.email;
|
||||
return true;
|
||||
case "message":
|
||||
if (!form.message.trim()) {
|
||||
errors.message = "Bitte geben Sie eine Nachricht ein.";
|
||||
return false;
|
||||
}
|
||||
delete errors.message;
|
||||
return true;
|
||||
case "privacy":
|
||||
if (!form.privacy) {
|
||||
errors.privacy = "Bitte stimmen Sie der Datenschutzerklärung zu.";
|
||||
return false;
|
||||
}
|
||||
delete errors.privacy;
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function validateAll(): boolean {
|
||||
const nameValid = validateField("name");
|
||||
const emailValid = validateField("email");
|
||||
const messageValid = validateField("message");
|
||||
const privacyValid = validateField("privacy");
|
||||
return nameValid && emailValid && messageValid && privacyValid;
|
||||
}
|
||||
|
||||
async function handleSubmit(): Promise<void> {
|
||||
if (!validateAll()) return;
|
||||
|
||||
isSubmitting.value = true;
|
||||
try {
|
||||
await $fetch("/api/contact", {
|
||||
method: "POST",
|
||||
body: {
|
||||
name: form.name,
|
||||
email: form.email,
|
||||
phone: form.phone,
|
||||
message: form.message,
|
||||
},
|
||||
});
|
||||
submitSuccess.value = true;
|
||||
} catch (err) {
|
||||
submitError.value = true;
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm(): void {
|
||||
form.name = "";
|
||||
form.email = "";
|
||||
form.phone = "";
|
||||
form.message = "";
|
||||
form.privacy = false;
|
||||
Object.keys(errors).forEach((k) => delete errors[k as keyof FormErrors]);
|
||||
submitSuccess.value = false;
|
||||
submitError.value = false;
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +1,128 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-text mb-4">Referenzen</h1>
|
||||
<p class="text-text-muted">Unsere Referenzen werden hier angezeigt.</p>
|
||||
<h1 class="text-3xl font-bold text-text mb-2">Referenzen</h1>
|
||||
<p class="text-text-muted mb-8">Ein Auszug aus unseren Projekten und Veranstaltungen.</p>
|
||||
|
||||
<!-- Filter Chips -->
|
||||
<div class="flex flex-wrap gap-3 mb-8" data-testid="filter-chips">
|
||||
<button
|
||||
v-for="cat in categories"
|
||||
:key="cat"
|
||||
:class="[
|
||||
'px-4 py-2 rounded-full text-sm font-medium border transition-colors duration-fast',
|
||||
activeFilter === cat
|
||||
? 'bg-accent text-white border-accent'
|
||||
: 'bg-panel text-text-muted border-border-default hover:border-accent-border'
|
||||
]"
|
||||
:data-testid="'filter-' + cat.toLowerCase()"
|
||||
@click="activeFilter = cat"
|
||||
>
|
||||
{{ cat }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Gallery Grid -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6" data-testid="gallery-grid">
|
||||
<div
|
||||
v-for="item in filteredImages"
|
||||
:key="item.id"
|
||||
class="relative group cursor-pointer rounded-lg overflow-hidden bg-panel border border-border-default hover:border-accent-border transition-colors duration-fast"
|
||||
:data-testid="'gallery-item-' + item.id"
|
||||
@click="openLightbox(item)"
|
||||
>
|
||||
<div class="aspect-w-4 aspect-h-3 w-full">
|
||||
<img
|
||||
:src="item.src"
|
||||
:alt="item.alt"
|
||||
class="w-full h-48 object-cover group-hover:opacity-80 transition-opacity duration-fast"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<p class="text-accent text-sm font-bold mb-1">{{ item.title }}</p>
|
||||
<p class="text-text-muted text-xs">{{ item.category }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lightbox -->
|
||||
<Lightbox
|
||||
:is-open="lightboxOpen"
|
||||
:image="currentImage"
|
||||
@close="closeLightbox"
|
||||
@prev="prevImage"
|
||||
@next="nextImage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
useHead({
|
||||
title: "Referenzen – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
});
|
||||
</script>
|
||||
|
||||
interface GalleryItem {
|
||||
id: number;
|
||||
src: string;
|
||||
alt: string;
|
||||
title: string;
|
||||
category: string;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
const categories = ["Alle", "Open-Air", "Indoor", "Rigging"] as const;
|
||||
const activeFilter = ref<string>("Alle");
|
||||
|
||||
const images: GalleryItem[] = [
|
||||
{ id: 1, src: "https://picsum.photos/seed/hms1/600/400", alt: "Open-Air Konzert", title: "Stadtfest Leipheim", category: "Open-Air", caption: "Stadtfest Leipheim – Beschallung und Lichttechnik" },
|
||||
{ id: 2, src: "https://picsum.photos/seed/hms2/600/400", alt: "Indoor Firmenevent", title: "Firmenevent Augsburg", category: "Indoor", caption: "Firmenevent in Augsburg – Komplett-Setup" },
|
||||
{ id: 3, src: "https://picsum.photos/seed/hms3/600/400", alt: "Rigging Aufbau", title: "Traversen-Rigging", category: "Rigging", caption: "Traversen-Rigging in einer Mehrzweckhalle" },
|
||||
{ id: 4, src: "https://picsum.photos/seed/hms4/600/400", alt: "Open-Air Festival", title: "Sommerfest Günzburg", category: "Open-Air", caption: "Sommerfest Günzburg – Line-Array Beschallung" },
|
||||
{ id: 5, src: "https://picsum.photos/seed/hms5/600/400", alt: "Indoor Konferenz", title: "Konferenz Neu-Ulm", category: "Indoor", caption: "Konferenz in Neu-Ulm – Mikrofonie und Mischtechnik" },
|
||||
{ id: 6, src: "https://picsum.photos/seed/hms6/600/400", alt: "Rigging Motorzug", title: "Motorzug-System", category: "Rigging", caption: "Motorzug-System für Bühnenbeleuchtung" },
|
||||
{ id: 7, src: "https://picsum.photos/seed/hms7/600/400", alt: "Open-Air Bühne", title: "Kirchweih Festzelt", category: "Open-Air", caption: "Kirchweih Festzelt – Beschallung und Beleuchtung" },
|
||||
{ id: 8, src: "https://picsum.photos/seed/hms8/600/400", alt: "Indoor Gala", title: "Gala Leipheim", category: "Indoor", caption: "Gala-Abend in Leipheim – Licht- und Tontechnik" },
|
||||
{ id: 9, src: "https://picsum.photos/seed/hms9/600/400", alt: "Rigging Seilzug", title: "Punkt-Rigging", category: "Rigging", caption: "Punkt-Rigging für Moving Heads" },
|
||||
];
|
||||
|
||||
const filteredImages = computed(() => {
|
||||
if (activeFilter.value === "Alle") return images;
|
||||
return images.filter((img) => img.category === activeFilter.value);
|
||||
});
|
||||
|
||||
const lightboxOpen = ref(false);
|
||||
const currentIndex = ref(0);
|
||||
|
||||
const currentImage = computed<GalleryItem>(() => {
|
||||
const item = filteredImages.value[currentIndex.value];
|
||||
return item
|
||||
? { src: item.src, alt: item.alt, caption: item.caption }
|
||||
: { src: "", alt: "", caption: "" };
|
||||
});
|
||||
|
||||
function openLightbox(item: GalleryItem) {
|
||||
const idx = filteredImages.value.findIndex((i) => i.id === item.id);
|
||||
if (idx >= 0) {
|
||||
currentIndex.value = idx;
|
||||
lightboxOpen.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
lightboxOpen.value = false;
|
||||
}
|
||||
|
||||
function nextImage() {
|
||||
currentIndex.value = (currentIndex.value + 1) % filteredImages.value.length;
|
||||
}
|
||||
|
||||
function prevImage() {
|
||||
currentIndex.value =
|
||||
currentIndex.value === 0
|
||||
? filteredImages.value.length - 1
|
||||
: currentIndex.value - 1;
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user