From 8f1cd47c456b1e451111bb53326fec4e1a3956cf Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Thu, 18 Dec 2025 14:54:10 +0000 Subject: [PATCH] Initial commit --- Dockerfile | 11 +++++++ docker-compose.yml | 7 +++++ index.html | 12 ++++++++ package.json | 26 +++++++++++++++++ postcss.config.js | 6 ++++ src/App.jsx | 18 ++++++++++++ src/components/BrandLogo.jsx | 8 ++++++ src/components/Bubbles.jsx | 15 ++++++++++ src/components/Footer.jsx | 15 ++++++++++ src/components/Navbar.jsx | 39 +++++++++++++++++++++++++ src/components/ObfuscatedMail.jsx | 24 ++++++++++++++++ src/components/TeamMember.jsx | 43 +++++++++++++++++++++++++++ src/data/content.js | 41 ++++++++++++++++++++++++++ src/index.css | 5 ++++ src/main.jsx | 5 ++++ src/sections/Hero.jsx | 48 +++++++++++++++++++++++++++++++ src/sections/Projects.jsx | 36 +++++++++++++++++++++++ src/sections/Team.jsx | 19 ++++++++++++ src/utils/animations.jsx | 24 ++++++++++++++++ tailwind.config.js | 10 +++++++ vite.config.js | 6 ++++ 21 files changed, 418 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 index.html create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 src/App.jsx create mode 100644 src/components/BrandLogo.jsx create mode 100644 src/components/Bubbles.jsx create mode 100644 src/components/Footer.jsx create mode 100644 src/components/Navbar.jsx create mode 100644 src/components/ObfuscatedMail.jsx create mode 100644 src/components/TeamMember.jsx create mode 100644 src/data/content.js create mode 100644 src/index.css create mode 100644 src/main.jsx create mode 100644 src/sections/Hero.jsx create mode 100644 src/sections/Projects.jsx create mode 100644 src/sections/Team.jsx create mode 100644 src/utils/animations.jsx create mode 100644 tailwind.config.js create mode 100644 vite.config.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..14c362d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:20-alpine AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=builder /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6eb39ca --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + liquid-web: + build: . + container_name: liquid-website + restart: unless-stopped + ports: + - "8081:80" diff --git a/index.html b/index.html new file mode 100644 index 0000000..b3970be --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Liquid Development + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..bdd956d --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "liquid-website", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "framer-motion": "^11.0.0", + "lucide-react": "^0.300.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.32", + "tailwindcss": "^3.4.1", + "vite": "^5.0.0" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..83df37f --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Navbar } from './components/Navbar'; +import { Footer } from './components/Footer'; +import { Hero } from './sections/Hero'; +import { Projects } from './sections/Projects'; +import { Team } from './sections/Team'; + +export default function LiquidDevelopment() { + return ( +
+ + + + +
+
+ ); +} diff --git a/src/components/BrandLogo.jsx b/src/components/BrandLogo.jsx new file mode 100644 index 0000000..7fa761e --- /dev/null +++ b/src/components/BrandLogo.jsx @@ -0,0 +1,8 @@ +import React from 'react'; + +export const BrandLogo = ({ className = "w-12 h-12" }) => ( + + + + +); diff --git a/src/components/Bubbles.jsx b/src/components/Bubbles.jsx new file mode 100644 index 0000000..ecb5b67 --- /dev/null +++ b/src/components/Bubbles.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { motion } from 'framer-motion'; + +export const Bubbles = () => ( +
+ {Array.from({ length: 15 }).map((_, i) => ( + + ))} +
+); diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx new file mode 100644 index 0000000..5365ded --- /dev/null +++ b/src/components/Footer.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Github } from 'lucide-react'; +import { BrandLogo } from './BrandLogo'; +import { SOCIALS } from '../data/content'; + +export const Footer = () => ( + +); diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx new file mode 100644 index 0000000..1cdab3e --- /dev/null +++ b/src/components/Navbar.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Github, Mail } from 'lucide-react'; +import { BrandLogo } from './BrandLogo'; +import { ObfuscatedMail } from './ObfuscatedMail'; +import { NAV_LINKS, SOCIALS } from '../data/content'; + +export const Navbar = () => { + // Extract email address from "mailto:..." string if necessary + const rawEmail = SOCIALS.email.replace('mailto:', ''); + + return ( + + ); +}; diff --git a/src/components/ObfuscatedMail.jsx b/src/components/ObfuscatedMail.jsx new file mode 100644 index 0000000..4b234e6 --- /dev/null +++ b/src/components/ObfuscatedMail.jsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; + +export const ObfuscatedMail = ({ email, className, children, title }) => { + // Start with a dummy link so bots don't see 'mailto:' + const [href, setHref] = useState("#"); + + // Only reveal the real email when the user hovers or focuses + const reveal = () => { + setHref(`mailto:${email}`); + }; + + return ( + + {children} + + ); +}; diff --git a/src/components/TeamMember.jsx b/src/components/TeamMember.jsx new file mode 100644 index 0000000..d36dd49 --- /dev/null +++ b/src/components/TeamMember.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import { Github, Mail, Globe } from 'lucide-react'; +import { ObfuscatedMail } from './ObfuscatedMail'; + +export const TeamMember = ({ name, nickname, img, gh, email, website, role, role2 }) => ( + +
+
+ +
+ {name} +
+ +
+

{name}

+ @{nickname.toLowerCase()} + +
+ FOUNDER + DEVELOPER +
+ +
+ {/* Obfuscated Member Mail */} + + + + + + + + + + +
+
+
+); diff --git a/src/data/content.js b/src/data/content.js new file mode 100644 index 0000000..e0fd911 --- /dev/null +++ b/src/data/content.js @@ -0,0 +1,41 @@ +import { Github, Mail } from 'lucide-react'; + +export const NAV_LINKS = ['Home', 'Projects', 'Team']; + +export const SOCIALS = { + github: "https://github.com/LiquidDevelopmentDE/", + email: "mailto:hello@liquid-dev.de" +}; + +export const TEAM_MEMBERS = [ + { + name: "Felix", + nickname: "Flixcoo", + role: "FOUNDER", + role2: "DEVELOPER", + img: "https://github.com/flixcoo.png", + gh: "https://github.com/flixcoo", + email: "felix@liquid-dev.de", + website: "https://felixkirchner.de" + }, + { + name: "Yannick", + nickname: "Gelbeinhalb", + role: "FOUNDER", + role2: "DEVELOPER", + img: "https://github.com/GelbEinhalb.png", + gh: "https://github.com/GelbEinhalb", + email: "yannick@liquid-dev.de", + website: "https://yannick-weigert.de" + }, + { + name: "Mathis", + nickname: "Sneeex", + role: "FOUNDER", + role2: "DEVELOPER", + img: "https://github.com/mathiskir.png", + gh: "https://github.com/mathiskir", + email: "mathis@liquid-dev.de", + website: "https://mathiskirchner.de" + } +]; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..6f3c729 --- /dev/null +++ b/src/index.css @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; +html { scroll-behavior: smooth; } +body { margin: 0; background: #0e0e0e; } diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..aa9fccf --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,5 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import './index.css' +ReactDOM.createRoot(document.getElementById('root')).render() diff --git a/src/sections/Hero.jsx b/src/sections/Hero.jsx new file mode 100644 index 0000000..fcad5aa --- /dev/null +++ b/src/sections/Hero.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import { ArrowRight } from 'lucide-react'; +import { BrandLogo } from '../components/BrandLogo'; +import { Bubbles } from '../components/Bubbles'; +import { ObfuscatedMail } from '../components/ObfuscatedMail'; +import { SOCIALS } from '../data/content'; + +export const Hero = () => { + const rawEmail = SOCIALS.email.replace('mailto:', ''); + + return ( +
+
+ +
+ + + + + + {/* Obfuscated Title Link */} + +

+ LIQUID DEVELOPMENT +

+
+
+ + German Development Team + + + + Explore Work + + + {/* Obfuscated Text Button */} + + Contact Team + + +
+
+ ); +}; diff --git a/src/sections/Projects.jsx b/src/sections/Projects.jsx new file mode 100644 index 0000000..af69689 --- /dev/null +++ b/src/sections/Projects.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { ArrowRight, Smartphone } from 'lucide-react'; +import { FadeInWhenVisible } from '../utils/animations'; + +export const Projects = () => ( +
+
+
+

Projects

+ +
+
+
IN DEVELOPMENT
+

GameTracker App

+

An all-in-one app to track card- and board games, manage players and groups and get statistics about your played games.

+
{['Flutter', 'iOS', 'Android', 'Statistics'].map(tag => ({tag}))}
+ View Project Status +
+
+
+
+
+
+
+
+
+
+
+
+
Soon available on
iOS & Android
+
+
+
+
+
+); diff --git a/src/sections/Team.jsx b/src/sections/Team.jsx new file mode 100644 index 0000000..3dc5678 --- /dev/null +++ b/src/sections/Team.jsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { FadeInWhenVisible } from '../utils/animations'; +import { TeamMember } from '../components/TeamMember'; +import { TEAM_MEMBERS } from '../data/content'; + +export const Team = () => ( +
+
+

The Team

Meet the creators.

+
+ {TEAM_MEMBERS.map((member, index) => ( + + + + ))} +
+
+
+); diff --git a/src/utils/animations.jsx b/src/utils/animations.jsx new file mode 100644 index 0000000..9a1db2b --- /dev/null +++ b/src/utils/animations.jsx @@ -0,0 +1,24 @@ +import React, { useRef } from 'react'; +import { motion, useInView } from 'framer-motion'; + +export const fadeInUp = { + hidden: { opacity: 0, y: 30 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: "easeOut" } } +}; + +export const FadeInWhenVisible = ({ children, delay = 0 }) => { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-50px" }); + return ( +
+ + {children} + +
+ ); +}; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..3718949 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,10 @@ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..9ffcc67 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +})