1
0

feat: Finish animations, add imprint/privacy pages

This commit is contained in:
2026-03-05 13:50:40 +01:00
parent 7f44ed1112
commit 9bfae3bcee
11 changed files with 306 additions and 171 deletions
+25 -1
View File
@@ -48,7 +48,7 @@ function getCurrentYear() {
<div class="legal"> <div class="legal">
<span class="list-title">Legal</span> <span class="list-title">Legal</span>
<ul> <ul>
<li><a href="/privacy-policy">Privacy Policy</a></li> <li><a href="/privacy">Privacy Policy</a></li>
<li><a href="/imprint">Imprint</a></li> <li><a href="/imprint">Imprint</a></li>
</ul> </ul>
</div> </div>
@@ -136,3 +136,27 @@ function getCurrentYear() {
margin-top: 8rem; margin-top: 8rem;
} }
</style> </style>
<script>
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(SplitText);
gsap.registerPlugin(ScrollTrigger);
const footer = document.querySelector("footer");
if (footer) {
gsap.from(footer, {
scrollTrigger: {
trigger: footer,
start: "top bottom",
},
duration: 2,
opacity: 0,
yPercent: 10,
ease: "expo.out",
});
}
</script>
-24
View File
@@ -96,27 +96,3 @@
border: 2px solid var(--clr-ts-red-400); border: 2px solid var(--clr-ts-red-400);
} }
</style> </style>
<script>
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(SplitText);
gsap.registerPlugin(ScrollTrigger);
const footer = document.querySelector("footer");
if (footer) {
gsap.from(footer, {
scrollTrigger: {
trigger: footer,
start: "top 90%",
},
duration: 2,
opacity: 0,
yPercent: 10,
ease: "expo.out",
});
}
</script>
+11 -7
View File
@@ -8,10 +8,12 @@ import SkipNavLink from "./SkipNavLink.astro";
<SkipNavLink contentId="main-content" /> <SkipNavLink contentId="main-content" />
{/* Logo */} {/* Logo */}
<Logo class="logo" /> <a class="header-logo" href="/">
<Logo class="logo" />
</a>
{/* Contact Link */} {/* Contact Link */}
<a href="mailto:office@tideshiftdigital.com"> <a class="header-contact" href="mailto:office@tideshiftdigital.com">
<span class="heading-gradient">Contact us</span> <span class="heading-gradient">Contact us</span>
<ArrowUpRight class="icon char" /> <ArrowUpRight class="icon char" />
</a> </a>
@@ -35,14 +37,16 @@ import SkipNavLink from "./SkipNavLink.astro";
z-index: 10; z-index: 10;
} }
.logo { .header-logo {
width: 12.5rem;
transform: translate3d(-0.75rem, 0, 0);
grid-column: 1 / 3; grid-column: 1 / 3;
} }
a { .logo {
width: 12.5rem;
transform: translate3d(-0.75rem, 0, 0);
}
.header-contact {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
+2 -2
View File
@@ -131,8 +131,8 @@ import { Picture } from "astro:assets";
tl.addLabel("heading", 0); tl.addLabel("heading", 0);
tl.addLabel("heading-text", 0.6); tl.addLabel("heading-text", 0.6);
tl.addLabel("image", 1); tl.addLabel("image", 0.8);
tl.addLabel("image-text", 1.4); tl.addLabel("image-text", 1.1);
new SplitText(aboutSection.querySelector("h2"), { new SplitText(aboutSection.querySelector("h2"), {
type: "words, chars", type: "words, chars",
@@ -114,6 +114,7 @@ import ArrowUpRight from "../icons/ArrowUpRight.astro";
tl.addLabel("image", 0.2); tl.addLabel("image", 0.2);
tl.addLabel("heading", 0.5); tl.addLabel("heading", 0.5);
tl.addLabel("text", 0.6); tl.addLabel("text", 0.6);
tl.addLabel("arrow", 0.6);
new SplitText(contactSection.querySelector("h2"), { new SplitText(contactSection.querySelector("h2"), {
type: "words, chars", type: "words, chars",
@@ -187,5 +188,16 @@ import ArrowUpRight from "../icons/ArrowUpRight.astro";
}); });
}, },
}); });
tl.from(
contactSection.querySelector("a > svg"),
{
duration: 1,
opacity: 0,
yPercent: -10,
ease: "expo.out",
},
"arrow",
);
} }
</script> </script>
+1 -1
View File
@@ -119,7 +119,7 @@ const services: Array<ComponentProps<typeof ServicesCard>> = [
tl.addLabel("heading", 0); tl.addLabel("heading", 0);
tl.addLabel("text", 0.3); tl.addLabel("text", 0.3);
tl.addLabel("cards", 0.8); tl.addLabel("cards", 0.5);
new SplitText(servicesSection.querySelector("h2"), { new SplitText(servicesSection.querySelector("h2"), {
type: "words, chars", type: "words, chars",
-1
View File
@@ -3,7 +3,6 @@ import Footer from "../components/Footer.astro";
import GlobalStyles from "../components/GlobalStyles.astro"; import GlobalStyles from "../components/GlobalStyles.astro";
import Header from "../components/Header.astro"; import Header from "../components/Header.astro";
import PlausibleAnalytics from "../components/PlausibleAnalytics.astro"; import PlausibleAnalytics from "../components/PlausibleAnalytics.astro";
import SkipNavLink from "../components/SkipNavLink.astro";
const { pageTitle } = Astro.props; const { pageTitle } = Astro.props;
const title = pageTitle const title = pageTitle
+92
View File
@@ -0,0 +1,92 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout pageTitle="Imprint">
<div class="imprint">
<h1 class="heading-gradient">Imprint</h1>
<div>
<p>Tideshift Digital e.U.</p>
<p>Inhaber Michael Rieger</p>
</div>
<div>
<p>
Dienstleistungen in der automatischen Datenverarbeitung und
Informationstechnik
</p>
</div>
<div>
<p>UID-Nr: ATU82509206</p>
<p>FN: 660619Z</p>
<p>FB-Gericht: Handelsgericht Wien</p>
<p>Sitz: 1030 Wien</p>
<p>Grasbergergasse 9/1 | Austria</p>
<p>Tel: +43 (0) 670 350 53 50</p>
<p>E-Mail: office@tideshiftdigital.com</p>
</div>
</div>
</BaseLayout>
<style>
.imprint {
padding-inline: 5rem;
max-width: var(--max-content-width);
margin-inline: auto;
> div {
margin-top: 2rem;
}
}
h1 {
margin-top: 10rem;
font-size: var(--fs-page-title);
line-height: var(--leading-title);
letter-spacing: var(--tracking-narrow);
font-weight: 600;
}
* + * {
margin-top: 0.25rem;
}
</style>
<script>
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(SplitText);
const page = document.querySelector(".imprint");
if (page) {
new SplitText(page.querySelector("h1"), {
type: "words, chars",
autoSplit: true,
mask: "chars",
charsClass: "char",
onSplit: (self) => {
gsap.from(self.chars, {
duration: 1,
yPercent: -120,
scale: 1.2,
stagger: 0.015,
ease: "expo.out",
onComplete: () => self.revert(),
});
},
});
gsap.from(page.querySelectorAll(":scope > div"), {
duration: 1,
delay: 0.3,
opacity: 0,
yPercent: -20,
ease: "expo.out",
stagger: 0.1,
});
}
</script>
-41
View File
@@ -1,41 +0,0 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout pageTitle="Imprint">
<main class="imprint">
<h1>Imprint</h1>
<div>
<p>Tideshift Digital e.U.</p>
<p>Inhaber Michael Rieger</p>
</div>
<div>
<p>
Dienstleistungen in der automatischen Datenverarbeitung und
Informationstechnik
</p>
</div>
<div>
<p>UID-Nr: ATU82509206</p>
<p>FN: 660619Z</p>
<p>FB-Gericht: Handelsgericht Wien</p>
<p>Sitz: 1030 Wien</p>
<p>Grasbergergasse 9/1/7 | Austria</p>
<p>Tel: +43 (0) 670 350 53 50</p>
<p>E-Mail: office@tideshiftdigital.com</p>
</div>
</main>
</BaseLayout>
<style scoped>
h1 {
margin-top: 2rem;
}
main > * + * {
margin-top: 1rem;
}
</style>
-94
View File
@@ -1,94 +0,0 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout pageTitle="Privacy Policy">
<main class="content">
<h1>Privacy Policy</h1>
<div>
<p>
<strong>Tideshift Digital e.U.</strong> (“we”, “our”, “us”) respects
your privacy and is committed to protecting any data related to your
use of this website.
</p>
<h2>Analytics</h2>
<p>
We use <strong>
<a
target="_blank"
href="https://umami.is/"
class="hoverable"
rel="noreferrer noopener">self-hosted Umami</a
>
</strong> to measure basic website usage (such as page views and
referrers). No personal data, cookies, or IP addresses are collected
or stored.
</p>
<h2>Hosting</h2>
<p>
This website is hosted by <strong>
<a
target="_blank"
href="https://www.hetzner.com/"
class="hoverable"
rel="noreferrer noopener">Hetzner Online GmbH</a
></strong
>. Standard server logs may be collected automatically for
technical and security purposes. These logs can include IP
addresses and access times. The logs are used solely for server
maintenance and security and are not combined with any other
data or used for analytics.
</p>
<h2>Data Retention</h2>
<p>
Analytics data collected by Umami are stored temporarily and
only in an anonymized, aggregated form. No personally
identifiable information is retained. Server logs are stored by
Hetzner in accordance with their standard retention policies,
primarily for operational and security purposes.
</p>
<h2>Legal Basis</h2>
<p>
Data processing through analytics and hosting is based on our
legitimate interest (Article 6(1)(f) GDPR) in maintaining and
improving our websites performance and security.
</p>
<h2>Your Rights</h2>
<p>
Since we do not collect or process personal data directly, no
action is generally required from you. However, if you have any
questions or concerns regarding data protection, you may contact
us at
<a href="mailto:privacy@tideshiftdigital.com" class="hoverable"
>privacy@tideshiftdigital.com</a
>.
</p>
<h2>Data Controller</h2>
<p>
The data controller responsible for this website is:<br />
<strong>Tideshift Digital e.U.</strong><br />
Email: <a
href="mailto:privacy@tideshiftdigital.com"
class="hoverable">privacy@tideshiftdigital.com</a
>
</p>
</div>
</main>
</BaseLayout>
<style>
* + * {
margin-top: 1rem;
}
h1 {
margin-top: 2rem;
}
</style>
+163
View File
@@ -0,0 +1,163 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout pageTitle="Privacy Policy">
<div class="privacy">
<h1 class="heading-gradient">Privacy Policy</h1>
<div class="content">
<p>
<strong>Tideshift Digital e.U.</strong> (“we”, “our”, “us”) respects
your privacy and is committed to protecting any data related to your
use of this website.
</p>
<section>
<h2 class="heading-gradient">Analytics</h2>
<p>
We use <strong>
<a
target="_blank"
href="https://umami.is/"
class="hoverable"
rel="noreferrer noopener">self-hosted Umami</a
>
</strong> to measure basic website usage (such as page views and
referrers). No personal data, cookies, or IP addresses are collected
or stored.
</p>
</section>
<section>
<h2 class="heading-gradient">Hosting</h2>
<p>
This website is hosted by <strong>
<a
target="_blank"
href="https://www.hetzner.com/"
class="hoverable"
rel="noreferrer noopener">Hetzner Online GmbH</a
></strong
>. Standard server logs may be collected automatically for
technical and security purposes. These logs can include IP
addresses and access times. The logs are used solely for
server maintenance and security and are not combined with
any other data or used for analytics.
</p>
</section>
<section>
<h2 class="heading-gradient">Data Retention</h2>
<p>
Analytics data collected by Umami are stored temporarily and
only in an anonymized, aggregated form. No personally
identifiable information is retained. Server logs are stored
by Hetzner in accordance with their standard retention
policies, primarily for operational and security purposes.
</p>
</section>
<section>
<h2 class="heading-gradient">Legal Basis</h2>
<p>
Data processing through analytics and hosting is based on
our legitimate interest (Article 6(1)(f) GDPR) in
maintaining and improving our websites performance and
security.
</p>
</section>
<section>
<h2 class="heading-gradient">Your Rights</h2>
<p>
Since we do not collect or process personal data directly,
no action is generally required from you. However, if you
have any questions or concerns regarding data protection,
you may contact us at
<a
href="mailto:privacy@tideshiftdigital.com"
class="hoverable">privacy@tideshiftdigital.com</a
>.
</p>
</section>
<section>
<h2 class="heading-gradient">Data Controller</h2>
<p>
The data controller responsible for this website is:<br />
<strong>Tideshift Digital e.U.</strong><br />
Email: <a
href="mailto:privacy@tideshiftdigital.com"
class="hoverable">privacy@tideshiftdigital.com</a
>
</p>
</section>
</div>
</div>
</BaseLayout>
<style>
.privacy {
padding-inline: 5rem;
max-width: var(--max-content-width);
margin-inline: auto;
> div {
margin-top: 2rem;
}
}
h1 {
margin-top: 10rem;
font-size: var(--fs-page-title);
line-height: var(--leading-title);
letter-spacing: var(--tracking-narrow);
font-weight: 600;
}
.content {
max-width: 80ch;
> * + * {
margin-top: 1rem;
}
}
</style>
<script>
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(SplitText);
const page = document.querySelector(".privacy");
if (page) {
new SplitText(page.querySelector("h1"), {
type: "words, chars",
autoSplit: true,
mask: "chars",
charsClass: "char",
onSplit: (self) => {
gsap.from(self.chars, {
duration: 1,
yPercent: -120,
scale: 1.2,
stagger: 0.015,
ease: "expo.out",
onComplete: () => self.revert(),
});
},
});
gsap.from(page.querySelectorAll(".content > *"), {
duration: 1,
delay: 0.3,
opacity: 0,
yPercent: -20,
ease: "expo.out",
stagger: 0.1,
});
}
</script>