initial commit

This commit is contained in:
2025-05-22 17:46:02 +02:00
parent a6d168c504
commit 6fb1e51c79
25 changed files with 1599 additions and 10 deletions

View File

@@ -0,0 +1,97 @@
---
import Section from "../Section.astro";
enum NavigationItemType {
Link = 0,
Text = 1,
}
type NavigationItem =
| {
path: string;
label: string;
type: NavigationItemType.Link;
}
| {
type: NavigationItemType.Text;
content: string;
};
type NavigationGroup = {
title: string;
class?: string;
items: Array<NavigationItem>;
};
const tree: Array<NavigationGroup> = [
{
title: "Übersicht",
items: [
{
path: "/",
type: NavigationItemType.Link,
label: "Startseite",
},
],
},
{
title: "Rechtliches",
items: [
{
path: "/legal/imprint",
label: "Impressum",
type: NavigationItemType.Link,
},
{
path: "/legal/privacy",
label: "Datenschutzerklärung",
type: NavigationItemType.Link,
},
],
},
{
title: "Zugehöriges",
items: [
{
path: "https://enrico.buehler.earth",
label: "Enrico Bühler",
type: NavigationItemType.Link,
},
],
},
{
title: "",
class: "ml-auto mr-0 self-end",
items: [
{
type: NavigationItemType.Text,
content: "Made with ❤️ in Rottweil",
},
],
},
];
---
<footer class="bg-neutral-accent">
<Section>
<div class="flex flex-row flex-wrap gap-12 w-full pb-8">
{
tree.map((group) => (
<div class={group.class}>
{group.title && <h3 class="mb-2">{group.title}</h3>}
<div class="flex flex-col">
{group.items.map((item) => {
switch (item.type) {
case NavigationItemType.Link:
return <a href={item.path}>{item.label}</a>;
case NavigationItemType.Text:
return <p>{item.content}</p>;
}
})}
</div>
</div>
))
}
</div>
</Section>
</footer>

View File

@@ -0,0 +1,16 @@
---
import Logo from "../Logo/Logo.astro";
---
<header id="nav-container" class="fixed -top-1 w-full h-height-header z-50">
<div
class="flex flex-row justify-between items-center h-full w-full max-w-max-section m-auto px-section-main-x"
>
<a
href="/"
class="w-[120px] h-[120px] flex justify-center items-center rounded-3xl p-2 backdrop-blur-3xl"
>
<Logo />
</a>
</div>
</header>

View File

@@ -0,0 +1,28 @@
<!--?xml version="1.0" encoding="UTF-8"?-->
<svg
id="Ebene_1"
data-name="Ebene 1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 643.6 382.49"
>
<path
class="fill-main"
d="M128.61,230.82v25.76c-3.39,3.13-15.9,9.57-36.95,9.57s-33.56-6.44-36.95-9.57v-69.51c-6.51-1.15-13.96-1.89-22.4-1.89s-15.9.75-22.4,1.89v71.69c0,30.24,34.38,52.18,81.75,52.18s81.75-21.95,81.75-52.18v-27.9c.54-3.26,10.53-11.58,29.7-16.61v-45.87c-44.16,8.16-74.5,32.3-74.5,62.43Z"
></path>
<path
class="fill-main"
d="M552.55,63.76c-27.7,0-50.91,7.57-65.32,19.94-12.48-7.97-28.41-13.93-46.65-17.17.74,3.66,1.14,7.42,1.14,11.28v34.8c19.17,5.03,29.16,13.33,29.7,16.56v52.56c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-63.83c3.41-3.08,15.75-9.34,36.33-9.34s32.92,6.26,36.33,9.34v63.83c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-66.1c0-30.06-34.12-51.88-81.13-51.88Z"
></path>
<path
class="fill-main"
d="M322.42,370.08c-61.63,0-108.1-28.12-108.1-65.41V77.82c0-37.29,46.48-65.41,108.1-65.41s108.1,28.12,108.1,65.41v226.86c0,37.29-46.47,65.41-108.1,65.41ZM322.42,57.2c-41.19,0-62.5,15.85-63.31,20.66v226.81c.81,4.76,22.11,20.61,63.31,20.61s62.5-15.85,63.31-20.66V77.82c-.81-4.76-22.12-20.61-63.31-20.61Z"
></path>
<path
class="fill-main"
d="M353.48,72.19c-32.05,10.89-52.91,31.4-53.44,56.03h-.03s0,.96,0,.96v32.77c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-32.73c.56-3.27,10.54-11.57,29.7-16.6v-31.07c-2.97-2.53-10.07-6.46-21.03-9.36Z"
></path>
<path
class="fill-main"
d="M322.42,290.86c8.44,0,15.9-.75,22.4-1.89v-58.15c0-30.13-30.35-54.26-74.5-62.43v45.87c19.17,5.03,29.16,13.33,29.7,16.56v58.15c6.51,1.15,13.96,1.89,22.4,1.89Z"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<defs>
<style>
.cls-1 {
fill: #654eff;
}
.cls-2 {
fill: #fff;
}
</style>
</defs>
<rect class="cls-1" x="87.76" y="87.76" width="824.48" height="824.48" rx="200.39" ry="200.39"/>
<g>
<path class="cls-2" d="M306.81,545.97v25.76c-3.39,3.13-15.9,9.57-36.95,9.57s-33.56-6.44-36.95-9.57v-69.51c-6.51-1.15-13.96-1.89-22.4-1.89s-15.9.75-22.4,1.89v71.69c0,30.24,34.38,52.18,81.75,52.18s81.75-21.95,81.75-52.18v-27.9c.54-3.26,10.53-11.58,29.7-16.61v-45.87c-44.16,8.16-74.5,32.3-74.5,62.43Z"/>
<path class="cls-2" d="M730.75,378.92c-27.7,0-50.91,7.57-65.32,19.94-12.48-7.97-28.41-13.93-46.65-17.17.74,3.66,1.14,7.42,1.14,11.28v34.8c19.17,5.03,29.16,13.33,29.7,16.56v52.56c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-63.83c3.41-3.08,15.75-9.34,36.33-9.34s32.92,6.26,36.33,9.34v63.83c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-66.1c0-30.06-34.12-51.88-81.13-51.88Z"/>
<path class="cls-2" d="M500.62,685.24c-61.63,0-108.1-28.12-108.1-65.41v-226.86c0-37.29,46.48-65.41,108.1-65.41s108.1,28.12,108.1,65.41v226.86c0,37.29-46.47,65.41-108.1,65.41ZM500.62,372.36c-41.19,0-62.5,15.85-63.31,20.66v226.81c.81,4.76,22.11,20.61,63.31,20.61s62.5-15.85,63.31-20.66v-226.81c-.81-4.76-22.12-20.61-63.31-20.61Z"/>
<path class="cls-2" d="M531.68,387.34c-32.05,10.89-52.91,31.4-53.44,56.03h-.03s0,.96,0,.96v32.77c6.51,1.15,13.96,1.89,22.4,1.89s15.9-.75,22.4-1.89v-32.73c.56-3.27,10.54-11.57,29.7-16.6v-31.07c-2.97-2.53-10.07-6.46-21.03-9.36Z"/>
<path class="cls-2" d="M500.62,606.01c8.44,0,15.9-.75,22.4-1.89v-58.15c0-30.13-30.35-54.26-74.5-62.43v45.87c19.17,5.03,29.16,13.33,29.7,16.56v58.15c6.51,1.15,13.96,1.89,22.4,1.89Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,27 @@
---
import type { HTMLAttributes } from "astro/types";
import { cva, type VariantProps } from "class-variance-authority";
const section = cva("relative w-full", {
variants: {
padding: {
true: "px-section-main-x py-section-main-y",
false: "p-0",
},
maxWidth: {
true: "max-w-max-section mx-auto",
false: "",
},
},
});
export interface Props
extends HTMLAttributes<"section">,
VariantProps<typeof section> {}
const { padding = true, maxWidth = true, ...props } = Astro.props;
---
<section {...props} class={section({ padding, maxWidth })}>
<slot />
</section>

View File

@@ -0,0 +1,36 @@
---
import { cn } from "@/lib/utils.ts";
const anim = {
old: {
name: "pageLeave",
duration: "0.0s",
easing: "ease-out",
fillMode: "forwards",
},
new: {
name: "pageEnter",
duration: "0.7s",
easing: "cubic-bezier(0.23, 1, 0.32, 1)",
fillMode: "forwards",
},
};
export interface Props {
inset?: boolean;
}
const slideAnimation = {
forwards: anim,
backwards: anim,
};
const { inset = true } = Astro.props;
---
<main
transition:animate={slideAnimation}
class={cn("min-h-screen", inset ? "pt-height-header" : "")}
>
<slot />
</main>

View File

@@ -0,0 +1,16 @@
---
import "@/styles/markdown.css";
import Section from "@/components/Section.astro";
import MainLayout from "./MainLayout.astro";
import RootLayout from "./RootLayout.astro";
const { frontmatter } = Astro.props;
---
<RootLayout title={frontmatter.title}>
<MainLayout>
<Section>
<slot />
</Section>
</MainLayout>
</RootLayout>

View File

@@ -0,0 +1,38 @@
---
import Footer from "@/components/Layout/Footer.astro";
import Header from "@/components/Layout/Header.astro";
import "@/styles/global.css";
import "@fontsource/inter";
import { ClientRouter } from "astro:transitions";
export interface Props {
title: string;
showHeader?: boolean;
}
const { title, showHeader = true } = Astro.props;
---
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Kreative Webentwicklung aus Rottweil" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
<slot name="head" />
<script
is:inline
defer
data-domain="unom.io"
src="https://analytics.unom.io/js/plausible.js"></script>
<meta name="generator" content={Astro.generator} />
<title>unom - {title}</title>
<ClientRouter />
</head>
<body>
{showHeader && <Header transition:name="header" transition:persist />}
<slot />
<Footer />
</body>
</html>

6
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import clsx, { type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

12
src/pages/index.astro Normal file
View File

@@ -0,0 +1,12 @@
---
import RootLayout from "@/layouts/RootLayout.astro";
import "../styles/global.css";
import MainLayout from "@/layouts/MainLayout.astro";
import Landing from "@/sections/Landing/Landing.astro";
---
<RootLayout showHeader={false} title="Kreative Webentwicklung">
<MainLayout inset={false}>
<Landing />
</MainLayout>
</RootLayout>

View File

@@ -0,0 +1,48 @@
---
layout: "@/layouts/MarkdownLayout.astro"
title: Downloads
---
# Impressum
Angaben gemäß § 5 TMG
Enrico Bühler
unom
Schroffenstraße 44
78628 Rottweil
## Kontakt
E-Mail: <buehler@unom.io>
Website: <https://enrico.buehler.earth>
### Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV
Enrico Bühler
Schroffenstraße 44
78628 Rottweil
## Verbraucher­streit­beilegung/Universal­schlichtungs­stelle
Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.
### Haftung für Inhalte
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.
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. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
### Haftung für Links
Unser Angebot enthält 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. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar.
Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
### Urheberrecht
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. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet.
Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
Quelle:
<https://www.e-recht24.de>

View File

@@ -0,0 +1,20 @@
---
import { Image } from "astro:assets";
import bgDark from "./unom_Logo_5_Dark.webp";
import LogoQuadBG from "@/components/Logo/LogoQuadBG.astro";
---
<div class="w-full h-screen object-cover">
<div class="w-full h-full flex items-center justify-center absolute">
<div class="w-[200px]">
<LogoQuadBG />
</div>
</div>
<Image
class="h-full object-cover"
src={bgDark}
width={3840}
height={2160}
alt="Ein 3D Rendering des unom Logos"
/>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

157
src/styles/global.css Normal file
View File

@@ -0,0 +1,157 @@
@import "./timing-functions.css" layer(base);
@import "./page-transition.css" layer(base);
@import "tailwindcss";
:root {
--main: oklch(100 0 0);
--brand: oklch(0.5609 0.2483 280.67);
--neutral: oklch(0.155 0.0395 285.68);
--neutral-accent: oklch(0.1 0.0395 285.68);
--highlight: oklch(50.38% 0.293655 285.3753);
--success: oklch(91.1% 0.1605 148.89);
--error: oklch(67.36% 0.2339 0.92);
--font-display: "Ubuntu", ui-sans-serif, system-ui, sans-serif;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-mono: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
--radius: 0.625rem;
}
@theme inline static {
--color-main: var(--main);
--color-secondary: var(--secondary);
--color-brand: var(--brand);
--color-neutral: var(--neutral);
--color-neutral-accent: var(--neutral-accent);
--color-highlight: var(--highlight);
--color-success: var(--success);
--color-error: var(--error);
--font-display: var(--font-display);
--radius-card: var(--radius);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
@theme {
--spacing-main: 20px;
--spacing-card: 1rem;
--spacing-section-main-x: 25px;
--spacing-section-main-y: 25px;
--spacing-padding-card: 1.25rem;
--spacing-height-header: 100px;
--container-max-section: 100%;
}
/* @variant dark {
:root {
--main: oklch(1 0 0);
--secondary: oklch(0.8 0 0);
--primary: oklch(84.44% 0.2131 153.61);
--neutral: oklch(16.36% 0.0088 172.9);
--neutral-accent: oklch(19.73% 0.032 168.99);
--highlight: oklch(66.39% 0.2398 3.2);
--success: oklch(91.1% 0.1605 148.89);
--error: oklch(67.36% 0.2339 0.92);
}
} */
@variant lg {
:root {
--container-max-section: 1000px;
--spacing-height-header: 90px;
}
}
@variant xl {
:root {
--container-max-section: 1550px;
--spacing-section-main-x: 100px;
--spacing-section-main-y: 45px;
--spacing-height-header: 150px;
}
}
@layer base {
html {
@apply bg-neutral text-main font-sans;
scroll-behavior: smooth;
}
code {
@apply font-mono;
}
h1 {
@apply text-main font-display;
}
h1 {
@apply text-3xl font-bold;
}
h2 {
@apply text-2xl font-semibold;
}
h3 {
@apply text-xl font-medium;
}
h4 {
@apply text-lg;
}
a {
@apply underline;
}
a:hover {
@apply decoration-main text-main;
}
[astro-icon] {
fill: currentColor;
}
td {
@apply px-3 py-1 border;
}
article {
& h1,
h2,
h3,
h4,
h5 {
@apply mt-6;
}
& h1,
h2,
h3,
h4,
h5,
p,
ol,
ul {
@apply mb-4;
}
}
p,
li {
@apply max-w-[600px] text-base text-secondary;
line-height: 1.5;
}
}

25
src/styles/markdown.css Normal file
View File

@@ -0,0 +1,25 @@
@reference "./global.css";
h1 {
@apply mb-4! mt-8!;
}
h1,
h2,
h3,
h4,
h5 {
@apply mb-4! mt-6!;
}
p {
@apply mb-2! whitespace-break-spaces;
}
ul {
@apply ml-4!;
}
li {
@apply ml-4!;
}

View File

@@ -0,0 +1,18 @@
@keyframes pageEnter {
from {
transform: translateY(40px);
opacity: 0;
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes pageLeave {
from {
opacity: 1;
}
to {
opacity: 0;
}
}

View File

@@ -0,0 +1,23 @@
@theme {
--ease-in-sine: cubic-bezier(0.47, 0, 0.745, 0.715);
--ease-out-sine: cubic-bezier(0.39, 0.575, 0.565, 1);
--ease-in-out-sine: cubic-bezier(0.445, 0.05, 0.55, 0.95);
--ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
--ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
--ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);
--ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
--ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
--ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
--ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
--ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035);
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
--ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
--ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335);
--ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
--ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
}