feat(legal): integrate legal pages in-app with header support
All checks were successful
Deploy Waveform to VPS / deploy (push) Successful in 1m21s
All checks were successful
Deploy Waveform to VPS / deploy (push) Successful in 1m21s
This commit is contained in:
parent
342dbc549f
commit
a957991bee
6 changed files with 290 additions and 281 deletions
110
app/(app)/(legal)/imprint/page.tsx
Normal file
110
app/(app)/(legal)/imprint/page.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
/**
|
||||||
|
* @file app/(legal)/imprint/page.tsx
|
||||||
|
* @description Server component rendering the imprint/legal notice page tailored to the app layout design.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AppFooter from "@/components/layout/AppFooter";
|
||||||
|
import { AppHeader } from "@/components/layout/AppHeader";
|
||||||
|
|
||||||
|
export default async function ImprintPage() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full w-full bg-background p-4 min-h-0 overflow-hidden">
|
||||||
|
<AppHeader isLegalImprint />
|
||||||
|
<div className="flex-1 overflow-y-auto flex flex-col gap-4 py-4 min-h-0 pr-1">
|
||||||
|
{/* Information pursuant to § 5 DDG */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Information Pursuant to § 5
|
||||||
|
DDG
|
||||||
|
</h2>
|
||||||
|
<div className="font-mono text-xs bg-background border border-surface/80 rounded-xl p-4 text-foreground space-y-1">
|
||||||
|
<p className="font-semibold text-white">André Kempf</p>
|
||||||
|
<p className="text-accent">Full-Stack Web Developer</p>
|
||||||
|
<p className="text-muted">Großschneidersweg 2a</p>
|
||||||
|
<p className="text-muted">76149 Karlsruhe, Germany</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted">
|
||||||
|
Also responsible for content pursuant to § 18 Abs. 2 MStV.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Contact
|
||||||
|
</h2>
|
||||||
|
<div className="p-4 bg-background border border-surface/80 rounded-xl font-mono text-xs">
|
||||||
|
<p className="text-muted">
|
||||||
|
<span className="text-white">Email:</span>{" "}
|
||||||
|
<span className="text-accent hover:underline cursor-pointer">
|
||||||
|
dev@andre-kempf.com
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Disclaimer */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Disclaimer & Legal Notes
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<h3 className="font-semibold text-white text-sm">
|
||||||
|
Liability for Content
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted">
|
||||||
|
As a service provider, I am responsible for my own content on
|
||||||
|
these pages according to general laws pursuant to § 7 Abs. 1 DDG.
|
||||||
|
However, according to §§ 8 to 10 DDG, I am not obligated to
|
||||||
|
monitor transmitted or stored third-party information or to
|
||||||
|
investigate circumstances that indicate illegal activity.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 pt-3 border-t border-surface/60">
|
||||||
|
<h3 className="font-semibold text-white text-sm">
|
||||||
|
Liability for Links
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted">
|
||||||
|
My website contains links to external third-party websites over
|
||||||
|
whose content I have no control. Therefore, I cannot accept any
|
||||||
|
liability for these external contents. The respective provider or
|
||||||
|
operator of the pages is always responsible for the content of the
|
||||||
|
linked pages.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 pt-3 border-t border-surface/60">
|
||||||
|
<h3 className="font-semibold text-white text-sm">Copyright</h3>
|
||||||
|
<p className="text-muted">
|
||||||
|
The content and works created on these pages are subject to German
|
||||||
|
copyright law. Duplication, processing, distribution, or any form
|
||||||
|
of commercialization beyond the scope of copyright law require the
|
||||||
|
prior written consent of the author or creator.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dispute Resolution */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Dispute Resolution
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted">
|
||||||
|
The European Commission provides a platform for online dispute
|
||||||
|
resolution (OS):{" "}
|
||||||
|
<a
|
||||||
|
href="https://ec.europa.eu/consumers/odr/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-accent hover:underline break-all"
|
||||||
|
>
|
||||||
|
https://ec.europa.eu/consumers/odr/
|
||||||
|
</a>
|
||||||
|
.<br />I am neither willing nor obligated to participate in dispute
|
||||||
|
resolution proceedings before a consumer arbitration board.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AppFooter />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
135
app/(app)/(legal)/privacy/page.tsx
Normal file
135
app/(app)/(legal)/privacy/page.tsx
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
/**
|
||||||
|
* @file app/(legal)/privacy/page.tsx
|
||||||
|
* @description Server component rendering the privacy policy page tailored to the app layout design.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AppFooter from "@/components/layout/AppFooter";
|
||||||
|
import { AppHeader } from "@/components/layout/AppHeader";
|
||||||
|
|
||||||
|
export default async function PrivacyPage() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full w-full bg-background p-4 min-h-0 overflow-hidden">
|
||||||
|
<AppHeader isLegalPrivacy />
|
||||||
|
<div className="flex-1 overflow-y-auto flex flex-col gap-4 py-4 min-h-0 pr-1">
|
||||||
|
{/* Overview */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Data Protection at a Glance
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="font-semibold text-white text-sm">
|
||||||
|
General Information
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted">
|
||||||
|
The following notes provide a simple overview of what happens to
|
||||||
|
your personal data when you visit this website. Personal data is
|
||||||
|
any data that can be used to personally identify you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="font-semibold text-white text-sm">
|
||||||
|
Data Collection on This Website
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted">
|
||||||
|
Data processing on this website is carried out by the website
|
||||||
|
operator. Your data is collected when you provide it to us, or
|
||||||
|
automatically by our IT systems when you visit the site.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Responsible Party */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Responsible Party
|
||||||
|
(Controller)
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted">
|
||||||
|
The controller responsible for data processing on this website is:
|
||||||
|
</p>
|
||||||
|
<div className="font-mono text-xs bg-background border border-surface/80 rounded-xl p-4 text-foreground space-y-1">
|
||||||
|
<p className="font-semibold text-white">André Kempf</p>
|
||||||
|
<p className="text-muted">Großschneidersweg 2a</p>
|
||||||
|
<p className="text-muted">76149 Karlsruhe, Germany</p>
|
||||||
|
<p className="pt-2 text-muted">
|
||||||
|
Email:{" "}
|
||||||
|
<span className="text-accent hover:underline cursor-pointer font-medium">
|
||||||
|
dev@andre-kempf.com
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hosting & Server Log Files */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Hosting & Server
|
||||||
|
Infrastructure
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted">
|
||||||
|
This website is hosted externally on web servers operated by Netcup
|
||||||
|
GmbH. Personal data processed on this website is stored on the
|
||||||
|
host's secure servers.
|
||||||
|
</p>
|
||||||
|
<p className="text-muted">
|
||||||
|
The hosting provider automatically processes technical access data
|
||||||
|
in server environment variables necessary to establish a stable
|
||||||
|
connection and deliver page assets securely.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Server Analytics */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Server Analytics &
|
||||||
|
Privacy-First Tracking
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted">
|
||||||
|
To evaluate website reach and optimize user experience, this website
|
||||||
|
processes minimal access metrics (e.g., total daily views, coarse
|
||||||
|
device category, and daily visitor counts).
|
||||||
|
</p>
|
||||||
|
<div className="p-4 rounded-xl bg-background/80 border border-surface/80 space-y-2 text-xs font-mono">
|
||||||
|
<p className="text-emerald-400 font-semibold">
|
||||||
|
// Key privacy guarantees:
|
||||||
|
</p>
|
||||||
|
<ul className="list-disc list-inside space-y-1 text-muted">
|
||||||
|
<li>
|
||||||
|
<strong className="text-white">No Cookies:</strong> We do not
|
||||||
|
store cookies or local storage identifiers on your device.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong className="text-white">Anonymized IPs:</strong> IP
|
||||||
|
addresses are instantly hashed with a daily salt and never
|
||||||
|
stored in plain text.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong className="text-white">Zero Third Parties:</strong>{" "}
|
||||||
|
Analytics data is processed locally on our own server and never
|
||||||
|
shared with external tracking services.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted">
|
||||||
|
The legal basis for this processing is our legitimate interest in
|
||||||
|
maintaining and optimizing our online portfolio (Art. 6(1)(f) GDPR).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Your Rights */}
|
||||||
|
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
||||||
|
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
||||||
|
<span className="text-accent">//</span> Your Rights
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted">
|
||||||
|
You have the right at any time to receive information free of charge
|
||||||
|
about the origin, recipient, and purpose of your stored personal
|
||||||
|
data. You also have a right to request the correction or deletion of
|
||||||
|
this data.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AppFooter />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
/**
|
|
||||||
* @file app/(legal)/imprint/page.tsx
|
|
||||||
* @description Server component rendering the imprint/legal notice page tailored to the app layout design.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default async function ImprintPage() {
|
|
||||||
return (
|
|
||||||
<section className="flex-1 overflow-y-auto w-full bg-background">
|
|
||||||
<div className="relative p-6 max-w-7xl mx-auto">
|
|
||||||
<h1 className="text-2xl font-bold text-white mb-1 tracking-tight">
|
|
||||||
Legal Notice<span className="text-accent">.</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div className="space-y-6 text-sm mt-4 text-foreground/80 leading-relaxed">
|
|
||||||
{/* Information pursuant to § 5 DDG */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Information Pursuant to §
|
|
||||||
5 DDG
|
|
||||||
</h2>
|
|
||||||
<div className="font-mono text-xs bg-background border border-surface/80 rounded-xl p-4 text-foreground space-y-1">
|
|
||||||
<p className="font-semibold text-white">André Kempf</p>
|
|
||||||
<p className="text-accent">Full-Stack Web Developer</p>
|
|
||||||
<p className="text-muted">Großschneidersweg 2a</p>
|
|
||||||
<p className="text-muted">76149 Karlsruhe, Germany</p>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted">
|
|
||||||
Also responsible for content pursuant to § 18 Abs. 2 MStV.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Contact */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Contact
|
|
||||||
</h2>
|
|
||||||
<div className="p-4 bg-background border border-surface/80 rounded-xl font-mono text-xs">
|
|
||||||
<p className="text-muted">
|
|
||||||
<span className="text-white">Email:</span>{" "}
|
|
||||||
<span className="text-accent hover:underline cursor-pointer">
|
|
||||||
dev@andre-kempf.com
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Disclaimer */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Disclaimer & Legal Notes
|
|
||||||
</h2>
|
|
||||||
<div className="space-y-1">
|
|
||||||
<h3 className="font-semibold text-white text-sm">
|
|
||||||
Liability for Content
|
|
||||||
</h3>
|
|
||||||
<p className="text-muted">
|
|
||||||
As a service provider, I am responsible for my own content on
|
|
||||||
these pages according to general laws pursuant to § 7 Abs. 1
|
|
||||||
DDG. However, according to §§ 8 to 10 DDG, I am not obligated to
|
|
||||||
monitor transmitted or stored third-party information or to
|
|
||||||
investigate circumstances that indicate illegal activity.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1 pt-3 border-t border-surface/60">
|
|
||||||
<h3 className="font-semibold text-white text-sm">
|
|
||||||
Liability for Links
|
|
||||||
</h3>
|
|
||||||
<p className="text-muted">
|
|
||||||
My website contains links to external third-party websites over
|
|
||||||
whose content I have no control. Therefore, I cannot accept any
|
|
||||||
liability for these external contents. The respective provider
|
|
||||||
or operator of the pages is always responsible for the content
|
|
||||||
of the linked pages.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1 pt-3 border-t border-surface/60">
|
|
||||||
<h3 className="font-semibold text-white text-sm">Copyright</h3>
|
|
||||||
<p className="text-muted">
|
|
||||||
The content and works created on these pages are subject to
|
|
||||||
German copyright law. Duplication, processing, distribution, or
|
|
||||||
any form of commercialization beyond the scope of copyright law
|
|
||||||
require the prior written consent of the author or creator.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Dispute Resolution */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Dispute Resolution
|
|
||||||
</h2>
|
|
||||||
<p className="text-muted">
|
|
||||||
The European Commission provides a platform for online dispute
|
|
||||||
resolution (OS):{" "}
|
|
||||||
<a
|
|
||||||
href="https://ec.europa.eu/consumers/odr/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-accent hover:underline break-all"
|
|
||||||
>
|
|
||||||
https://ec.europa.eu/consumers/odr/
|
|
||||||
</a>
|
|
||||||
.<br />I am neither willing nor obligated to participate in
|
|
||||||
dispute resolution proceedings before a consumer arbitration
|
|
||||||
board.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
/**
|
|
||||||
* @file app/(legal)/privacy/page.tsx
|
|
||||||
* @description Server component rendering the privacy policy page tailored to the app layout design.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default async function PrivacyPage() {
|
|
||||||
return (
|
|
||||||
<section className="flex-1 overflow-y-auto w-full bg-background">
|
|
||||||
<div className="relative p-6 max-w-7xl mx-auto">
|
|
||||||
<h1 className="text-2xl font-bold text-white mb-1 tracking-tight">
|
|
||||||
Privacy Policy<span className="text-accent">.</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div className="space-y-6 text-sm mt-4 text-foreground/80 leading-relaxed">
|
|
||||||
{/* Overview */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Data Protection at a
|
|
||||||
Glance
|
|
||||||
</h2>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<h3 className="font-semibold text-white text-sm">
|
|
||||||
General Information
|
|
||||||
</h3>
|
|
||||||
<p className="text-muted">
|
|
||||||
The following notes provide a simple overview of what happens to
|
|
||||||
your personal data when you visit this website. Personal data is
|
|
||||||
any data that can be used to personally identify you.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<h3 className="font-semibold text-white text-sm">
|
|
||||||
Data Collection on This Website
|
|
||||||
</h3>
|
|
||||||
<p className="text-muted">
|
|
||||||
Data processing on this website is carried out by the website
|
|
||||||
operator. Your data is collected when you provide it to us, or
|
|
||||||
automatically by our IT systems when you visit the site.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Responsible Party */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Responsible Party
|
|
||||||
(Controller)
|
|
||||||
</h2>
|
|
||||||
<p className="text-muted">
|
|
||||||
The controller responsible for data processing on this website is:
|
|
||||||
</p>
|
|
||||||
<div className="font-mono text-xs bg-background border border-surface/80 rounded-xl p-4 text-foreground space-y-1">
|
|
||||||
<p className="font-semibold text-white">André Kempf</p>
|
|
||||||
<p className="text-muted">Großschneidersweg 2a</p>
|
|
||||||
<p className="text-muted">76149 Karlsruhe, Germany</p>
|
|
||||||
<p className="pt-2 text-muted">
|
|
||||||
Email:{" "}
|
|
||||||
<span className="text-accent hover:underline cursor-pointer font-medium">
|
|
||||||
dev@andre-kempf.com
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hosting & Server Log Files */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Hosting & Server
|
|
||||||
Infrastructure
|
|
||||||
</h2>
|
|
||||||
<p className="text-muted">
|
|
||||||
This website is hosted externally on web servers operated by
|
|
||||||
Netcup GmbH. Personal data processed on this website is stored on
|
|
||||||
the host's secure servers.
|
|
||||||
</p>
|
|
||||||
<p className="text-muted">
|
|
||||||
The hosting provider automatically processes technical access data
|
|
||||||
in server environment variables necessary to establish a stable
|
|
||||||
connection and deliver page assets securely.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Server Analytics */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Server Analytics &
|
|
||||||
Privacy-First Tracking
|
|
||||||
</h2>
|
|
||||||
<p className="text-muted">
|
|
||||||
To evaluate website reach and optimize user experience, this
|
|
||||||
website processes minimal access metrics (e.g., total daily views,
|
|
||||||
coarse device category, and daily visitor counts).
|
|
||||||
</p>
|
|
||||||
<div className="p-4 rounded-xl bg-background/80 border border-surface/80 space-y-2 text-xs font-mono">
|
|
||||||
<p className="text-emerald-400 font-semibold">
|
|
||||||
// Key privacy guarantees:
|
|
||||||
</p>
|
|
||||||
<ul className="list-disc list-inside space-y-1 text-muted">
|
|
||||||
<li>
|
|
||||||
<strong className="text-white">No Cookies:</strong> We do not
|
|
||||||
store cookies or local storage identifiers on your device.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong className="text-white">Anonymized IPs:</strong> IP
|
|
||||||
addresses are instantly hashed with a daily salt and never
|
|
||||||
stored in plain text.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong className="text-white">Zero Third Parties:</strong>{" "}
|
|
||||||
Analytics data is processed locally on our own server and
|
|
||||||
never shared with external tracking services.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted">
|
|
||||||
The legal basis for this processing is our legitimate interest in
|
|
||||||
maintaining and optimizing our online portfolio (Art. 6(1)(f)
|
|
||||||
GDPR).
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Your Rights */}
|
|
||||||
<div className="bg-surface border border-muted/20 rounded-xl p-6 shadow-xl space-y-3">
|
|
||||||
<h2 className="text-base font-semibold text-white flex items-center gap-2 font-mono">
|
|
||||||
<span className="text-accent">//</span> Your Rights
|
|
||||||
</h2>
|
|
||||||
<p className="text-muted">
|
|
||||||
You have the right at any time to receive information free of
|
|
||||||
charge about the origin, recipient, and purpose of your stored
|
|
||||||
personal data. You also have a right to request the correction or
|
|
||||||
deletion of this data.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -27,8 +27,6 @@ export default function AppFooter() {
|
||||||
<div key={link.href} className="flex items-center gap-2 sm:gap-4">
|
<div key={link.href} className="flex items-center gap-2 sm:gap-4">
|
||||||
<Link
|
<Link
|
||||||
href={link.href}
|
href={link.href}
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="group inline-flex items-center gap-1.5 hover:text-foreground transition-colors cursor-pointer"
|
className="group inline-flex items-center gap-1.5 hover:text-foreground transition-colors cursor-pointer"
|
||||||
title={link.name}
|
title={link.name}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @file components/layout/AppHeader.tsx
|
* @file components/layout/AppHeader.tsx
|
||||||
* @description Application top header component providing navigation controls, dynamic channel or friend tab titles, and optional server settings or member list toggles.
|
* @description Application top header component providing navigation controls, dynamic channel or friend tab titles, optional server settings, member list toggles, and legal views support.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
|
|
@ -12,24 +12,13 @@ import {
|
||||||
Users,
|
Users,
|
||||||
Hash,
|
Hash,
|
||||||
Settings,
|
Settings,
|
||||||
|
FileText,
|
||||||
|
ShieldCheck,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { ServerSettingsMenu } from "./ServerSettingsMenu";
|
import { ServerSettingsMenu } from "./ServerSettingsMenu";
|
||||||
import { FriendsHeader, TabType } from "@/components/friends/FriendsHeader";
|
import { FriendsHeader, TabType } from "@/components/friends/FriendsHeader";
|
||||||
|
|
||||||
/**
|
/** Properties for the AppHeader component. */
|
||||||
* Properties for the AppHeader component.
|
|
||||||
*
|
|
||||||
* @interface AppHeaderProps
|
|
||||||
* @property {string} [title] - The title of the current channel or view.
|
|
||||||
* @property {boolean} [showMembersButton=false] - Whether to show the button that toggles the members sidebar.
|
|
||||||
* @property {{ id: string; name: string }} [server] - Optional server configuration object containing its unique identifier and name.
|
|
||||||
* @property {boolean} [showFriendsTabs=false] - Whether to display the friends navigation tabs in the header.
|
|
||||||
* @property {TabType} [activeTab] - The currently active friends tab identifier.
|
|
||||||
* @property {(tab: TabType) => void} [setActiveTab] - Callback function to update the active friends tab.
|
|
||||||
* @property {number} [allCount=0] - The total number of friends.
|
|
||||||
* @property {number} [pendingCount=0] - The number of pending friend requests.
|
|
||||||
* @property {boolean} [isSettings=false] - Whether the header is rendered in the settings view.
|
|
||||||
*/
|
|
||||||
interface AppHeaderProps {
|
interface AppHeaderProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
showMembersButton?: boolean;
|
showMembersButton?: boolean;
|
||||||
|
|
@ -43,11 +32,11 @@ interface AppHeaderProps {
|
||||||
allCount?: number;
|
allCount?: number;
|
||||||
pendingCount?: number;
|
pendingCount?: number;
|
||||||
isSettings?: boolean;
|
isSettings?: boolean;
|
||||||
|
isLegalImprint?: boolean;
|
||||||
|
isLegalPrivacy?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Renders the application header with navigation controls, dynamic titles, tabs, and action buttons. */
|
||||||
* Renders the application header with navigation controls, dynamic titles, tabs, and action buttons.
|
|
||||||
*/
|
|
||||||
export function AppHeader({
|
export function AppHeader({
|
||||||
title,
|
title,
|
||||||
showMembersButton = false,
|
showMembersButton = false,
|
||||||
|
|
@ -58,16 +47,21 @@ export function AppHeader({
|
||||||
allCount = 0,
|
allCount = 0,
|
||||||
pendingCount = 0,
|
pendingCount = 0,
|
||||||
isSettings = false,
|
isSettings = false,
|
||||||
|
isLegalImprint = false,
|
||||||
|
isLegalPrivacy = false,
|
||||||
}: AppHeaderProps) {
|
}: AppHeaderProps) {
|
||||||
const { isNavOpen, toggleNav, toggleMembers } = useSidebarStore();
|
const { isNavOpen, toggleNav, toggleMembers } = useSidebarStore();
|
||||||
|
|
||||||
|
const isLegalView = isLegalImprint || isLegalPrivacy;
|
||||||
|
|
||||||
const hasContent =
|
const hasContent =
|
||||||
!isNavOpen ||
|
!isNavOpen ||
|
||||||
!!title ||
|
!!title ||
|
||||||
showMembersButton ||
|
showMembersButton ||
|
||||||
!!server ||
|
!!server ||
|
||||||
showFriendsTabs ||
|
showFriendsTabs ||
|
||||||
isSettings;
|
isSettings ||
|
||||||
|
isLegalView;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -76,7 +70,7 @@ export function AppHeader({
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 min-w-0 overflow-hidden">
|
<div className="flex items-center gap-2 min-w-0 overflow-hidden">
|
||||||
{/* Toggle button for navigation (auch in Settings sichtbar, wenn eingeklappt) */}
|
{/* Toggle button for navigation */}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleNav}
|
onClick={toggleNav}
|
||||||
|
|
@ -102,8 +96,26 @@ export function AppHeader({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Legal Imprint Header Title */}
|
||||||
|
{isLegalImprint && (
|
||||||
|
<div className="flex items-center gap-1.5 ml-1 min-w-0">
|
||||||
|
<FileText className="w-4 h-4 text-muted shrink-0" />
|
||||||
|
<h1 className="font-bold text-white text-base truncate">Imprint</h1>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Legal Privacy Header Title */}
|
||||||
|
{isLegalPrivacy && (
|
||||||
|
<div className="flex items-center gap-1.5 ml-1 min-w-0">
|
||||||
|
<ShieldCheck className="w-4 h-4 text-muted shrink-0" />
|
||||||
|
<h1 className="font-bold text-white text-base truncate">
|
||||||
|
Privacy Policy
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Dynamic Channel Title */}
|
{/* Dynamic Channel Title */}
|
||||||
{!isSettings && title && (
|
{!isSettings && !isLegalView && title && (
|
||||||
<div className="flex items-center gap-1.5 ml-1 min-w-0">
|
<div className="flex items-center gap-1.5 ml-1 min-w-0">
|
||||||
<Hash className="w-4 h-4 text-muted shrink-0" />
|
<Hash className="w-4 h-4 text-muted shrink-0" />
|
||||||
<h1 className="font-bold text-white text-base truncate">{title}</h1>
|
<h1 className="font-bold text-white text-base truncate">{title}</h1>
|
||||||
|
|
@ -111,14 +123,18 @@ export function AppHeader({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Friends Header Component */}
|
{/* Friends Header Component */}
|
||||||
{!isSettings && showFriendsTabs && setActiveTab && activeTab && (
|
{!isSettings &&
|
||||||
<FriendsHeader
|
!isLegalView &&
|
||||||
activeTab={activeTab}
|
showFriendsTabs &&
|
||||||
setActiveTab={setActiveTab}
|
setActiveTab &&
|
||||||
allCount={allCount}
|
activeTab && (
|
||||||
pendingCount={pendingCount}
|
<FriendsHeader
|
||||||
/>
|
activeTab={activeTab}
|
||||||
)}
|
setActiveTab={setActiveTab}
|
||||||
|
allCount={allCount}
|
||||||
|
pendingCount={pendingCount}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Action Buttons */}
|
{/* Right Action Buttons */}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue