Compare commits
24 Commits
f26edad96e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bc47a53a07 | |||
| 873cacdf0a | |||
| 211c6cf3ea | |||
| 18f52ab751 | |||
| f98c6062e1 | |||
| cd42922983 | |||
| 1c97147a6d | |||
| c5e385318b | |||
| 6f2dbfd966 | |||
| bc6c112704 | |||
| f314a0672a | |||
| 6a7b08a30b | |||
| 694c84e98b | |||
| 09a69c9e8f | |||
| dd073b27bf | |||
| 516930a7c2 | |||
| e56723e39b | |||
| a1e3e14f7b | |||
| 52f5d7aac5 | |||
| 0f01b72a5e | |||
| 27ef550db8 | |||
| 296a17ebbc | |||
| c90ecc885f | |||
| 06bed6cc60 |
@@ -2,27 +2,28 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<!-- Standard Meta -->
|
<!-- Standard Meta -->
|
||||||
|
<title>Liquid Development</title>
|
||||||
|
<meta name="description" content="Open-source software development team">
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<meta name="description" content="Open-source software development team">
|
<meta name="robots" content="index"/>
|
||||||
|
|
||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://liquid-dev.de/">
|
<meta property="og:url" content="https://liquid-dev.de/">
|
||||||
<meta property="og:title" content="Liquid Development">
|
<meta property="og:title" content="Liquid Development">
|
||||||
<meta property="og:description" content="Open-source software development team">
|
<meta property="og:description" content="Open-source software development team">
|
||||||
<meta property="og:image" content="public/social-share.webp">
|
<meta property="og:image" content="https://liquid-dev.de/social-share.webp">
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta name="twitter:url" content="https://liquid-dev.de/">
|
<meta name="twitter:url" content="https://liquid-dev.de/">
|
||||||
<meta name="twitter:title" content="Liquid Development">
|
<meta name="twitter:title" content="Liquid Development">
|
||||||
<meta name="twitter:description" content="Open-source software development team">
|
<meta name="twitter:description" content="Open-source software development team">
|
||||||
<meta name="twitter:image" content="public/social-share.webp">
|
<meta name="twitter:image" content="https://liquid-dev.de/social-share.webp">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="public/favicon.ico">
|
<link rel="icon" type="image/png" href="public/favicon.ico">
|
||||||
<title>Liquid Development</title>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -11,7 +11,9 @@
|
|||||||
"framer-motion": "^11.0.0",
|
"framer-motion": "^11.0.0",
|
||||||
"lucide-react": "^0.300.0",
|
"lucide-react": "^0.300.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
|
"react-snowfall": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.43",
|
"@types/react": "^18.2.43",
|
||||||
@@ -2229,6 +2231,21 @@
|
|||||||
"react": "^18.3.1"
|
"react": "^18.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-fast-compare": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/react-icons": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.17.0",
|
"version": "0.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
||||||
@@ -2239,6 +2256,19 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-snowfall": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-snowfall/-/react-snowfall-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-KAPMiGnxt11PEgC2pTVrTQsvk5jt1kLUtG+ZamiKLphTZ7GiYT1Aa5kX6jp4jKWq1kqJHchnGT9CDm4g86A5Gg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-fast-compare": "^3.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || 17.x || 18.x || 19.x",
|
||||||
|
"react-dom": "^16.8 || 17.x || 18.x || 19.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
"framer-motion": "^11.0.0",
|
"framer-motion": "^11.0.0",
|
||||||
"lucide-react": "^0.300.0",
|
"lucide-react": "^0.300.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
|
"react-snowfall": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.43",
|
"@types/react": "^18.2.43",
|
||||||
|
|||||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 326 KiB |
46
src/App.jsx
46
src/App.jsx
@@ -1,18 +1,36 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Navbar } from './components/Navbar';
|
import {Navbar} from './components/Navbar';
|
||||||
import { Footer } from './components/Footer';
|
import {Footer} from './components/Footer';
|
||||||
import { Hero } from './sections/Hero';
|
import {Hero} from './sections/Hero';
|
||||||
import { Projects } from './sections/Projects';
|
import {Projects} from './sections/Projects';
|
||||||
import { Team } from './sections/Team';
|
import {Team} from './sections/Team';
|
||||||
|
import Snowfall from 'react-snowfall'
|
||||||
|
|
||||||
export default function LiquidDevelopment() {
|
export default function LiquidDevelopment() {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#0e0e0e] text-white font-sans selection:bg-[#00A3FF] selection:text-white overflow-x-hidden">
|
<div
|
||||||
<Navbar />
|
className="min-h-screen bg-[#0e0e0e] text-white font-sans selection:bg-[#00A3FF] selection:text-white overflow-x-hidden">
|
||||||
<Hero />
|
<div style={{
|
||||||
<Projects />
|
position: 'fixed',
|
||||||
<Team />
|
width: '100vw',
|
||||||
<Footer />
|
height: '100vh',
|
||||||
</div>
|
top: 0,
|
||||||
);
|
left: 0,
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 9999,
|
||||||
|
}}>
|
||||||
|
<Snowfall
|
||||||
|
snowflakeCount={80}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Navbar/>
|
||||||
|
|
||||||
|
<Hero/>
|
||||||
|
|
||||||
|
<Projects/>
|
||||||
|
<Team/>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
|
|
||||||
export const BrandLogo = ({ className = "w-12 h-12" }) => (
|
export const BrandLogo = ({className = "w-12 h-12"}) => (
|
||||||
<svg viewBox="0 0 512 512" className={className} fill="none" xmlns="http://www.w3.org/2000/svg">
|
<img
|
||||||
<path d="M396.7 413.6L298.5 217.2V96h21.3c11.8 0 21.3-9.6 21.3-21.3V53.3C341.1 41.5 331.6 32 319.8 32H191.8c-11.8 0-21.3 9.6-21.3 21.3v21.3c0 11.8 9.6 21.3 21.3 21.3h21.3v121.2L115.1 413.6c-10.6 21.2 4.9 46.4 28.5 46.4h224.5c23.7 0 39.1-25.2 28.6-46.4zM245.3 170.7c11.8 0 21.3 9.6 21.3 21.3s-9.6 21.3-21.3 21.3-21.3-9.6-21.3-21.3 9.6-21.3 21.3-21.3zm-42.7 64c11.8 0 21.3 9.6 21.3 21.3s-9.6 21.3-21.3 21.3-21.3-9.6-21.3-21.3 9.6-21.3 21.3-21.3zm85.4 0c11.8 0 21.3 9.6 21.3 21.3s-9.6 21.3-21.3 21.3-21.3-9.6-21.3-21.3 9.6-21.3 21.3-21.3z" className="fill-current text-[#00A3FF]" stroke="currentColor" strokeWidth="20" strokeLinejoin="round"/>
|
src="/logo.png"
|
||||||
<path d="M138 380 Q 256 340 374 380 L 368 440 H 144 Z" className="fill-[#00A3FF] opacity-80" />
|
alt="Liquid Development logo"
|
||||||
</svg>
|
className={className}
|
||||||
);
|
draggable={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
@@ -1,15 +1,40 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import {motion} from 'framer-motion';
|
||||||
|
|
||||||
export const Bubbles = () => (
|
export const Bubbles = () => {
|
||||||
<div className="absolute inset-0 overflow-hidden pointer-events-none z-0">
|
const sizes = [20, 40, 60, 80];
|
||||||
{Array.from({ length: 15 }).map((_, i) => (
|
|
||||||
<motion.div key={i} className="absolute rounded-full bg-[#00A3FF]/20 backdrop-blur-sm border border-[#00A3FF]/30"
|
return (
|
||||||
initial={{ y: "120vh", x: Math.random() * 100 + "vw", scale: Math.random() * 0.5 + 0.5, opacity: 0 }}
|
<div className="absolute inset-0 overflow-hidden pointer-events-none z-0">
|
||||||
animate={{ y: "-20vh", opacity: [0, 1, 0] }}
|
{Array.from({length: 15}).map((_, i) => {
|
||||||
transition={{ duration: Math.random() * 10 + 10, repeat: Infinity, ease: "linear", delay: Math.random() * 10 }}
|
const size = sizes[i % sizes.length];
|
||||||
style={{ width: Math.random() * 50 + 20 + "px", height: Math.random() * 50 + 20 + "px" }}
|
|
||||||
/>
|
return (
|
||||||
))}
|
<motion.div
|
||||||
</div>
|
key={i}
|
||||||
);
|
className="absolute rounded-full"
|
||||||
|
initial={{
|
||||||
|
y: "120vh",
|
||||||
|
x: Math.random() * 100 + "vw",
|
||||||
|
opacity: 0
|
||||||
|
}}
|
||||||
|
animate={{y: "-20vh", opacity: [0, 0.7, 0]}}
|
||||||
|
transition={{
|
||||||
|
duration: Math.random() * 10 + 15,
|
||||||
|
repeat: Infinity,
|
||||||
|
ease: "linear",
|
||||||
|
delay: Math.random() * 10
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: `${size}px`,
|
||||||
|
height: `${size}px`,
|
||||||
|
aspectRatio: '1/1',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
border: `${size / 5}px solid rgba(0, 163, 255, 0.6)`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,15 +1,50 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Github } from 'lucide-react';
|
import {BrandLogo} from './BrandLogo';
|
||||||
import { BrandLogo } from './BrandLogo';
|
import {ObfuscatedMail} from './ObfuscatedMail';
|
||||||
import { SOCIALS } from '../data/content';
|
import {SOCIALS} from '../data/content';
|
||||||
|
|
||||||
export const Footer = () => (
|
export const Footer = () => (
|
||||||
<footer id="contact" className="py-12 border-t border-white/10 bg-black relative overflow-hidden">
|
<footer id="contact" className="py-12 border-t border-white/10 bg-black relative overflow-hidden">
|
||||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-1/2 h-1 bg-[#00A3FF] blur-[100px] opacity-50"></div>
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-1/2 h-1 bg-[#00A3FF] blur-[100px] opacity-50"></div>
|
||||||
<div className="max-w-7xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-8">
|
<div className="max-w-7xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-8">
|
||||||
<div className="flex items-center gap-3"><BrandLogo className="w-8 h-8 text-gray-600" /><span className="font-bold text-gray-500">LIQUID DEVELOPMENT</span></div>
|
<div className="flex items-center gap-3"><BrandLogo className="w-8 h-8 text-gray-600"/>
|
||||||
<div className="flex gap-6"><a href={SOCIALS.github} className="text-gray-400 hover:text-[#00A3FF] transition-colors"><Github size={24} /></a></div>
|
<span className="font-bold text-gray-500">LIQUID DEVELOPMENT</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center mt-8 text-gray-600 text-sm">© {new Date().getFullYear()} Liquid Development. All rights reserved.</div>
|
<div className="flex gap-8">
|
||||||
</footer>
|
{SOCIALS.map((social) => {
|
||||||
|
const Icon = social.icon;
|
||||||
|
const isEmail = !social.link.startsWith('http');
|
||||||
|
|
||||||
|
if (isEmail) {
|
||||||
|
return (
|
||||||
|
<ObfuscatedMail
|
||||||
|
key={social.name}
|
||||||
|
email={social.link}
|
||||||
|
className="text-gray-400 hover:text-[#00A3FF] transition-colors"
|
||||||
|
title={social.name}
|
||||||
|
>
|
||||||
|
<Icon size={24}/>
|
||||||
|
</ObfuscatedMail>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={social.name}
|
||||||
|
href={social.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="text-gray-400 hover:text-[#00A3FF] transition-colors"
|
||||||
|
title={social.name}
|
||||||
|
>
|
||||||
|
<Icon size={24}/>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-center mt-8 text-gray-600 text-sm">© {new Date().getFullYear()} Liquid Development.
|
||||||
|
All rights reserved.
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,39 +1,57 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Github, Mail } from 'lucide-react';
|
import {BrandLogo} from './BrandLogo';
|
||||||
import { BrandLogo } from './BrandLogo';
|
import {ObfuscatedMail} from './ObfuscatedMail';
|
||||||
import { ObfuscatedMail } from './ObfuscatedMail';
|
import {NAV_LINKS, SOCIALS} from '../data/content';
|
||||||
import { NAV_LINKS, SOCIALS } from '../data/content';
|
|
||||||
|
|
||||||
export const Navbar = () => {
|
export const Navbar = () => {
|
||||||
// Extract email address from "mailto:..." string if necessary
|
return (
|
||||||
const rawEmail = SOCIALS.email.replace('mailto:', '');
|
<nav className="fixed top-0 left-0 right-0 z-50 backdrop-blur-xl bg-[#0e0e0e]/90 border-b border-white/5">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<BrandLogo className="w-8 h-8 text-[#00A3FF]"/>
|
||||||
|
<span className="font-bold text-lg md:text-xl tracking-wider text-white">
|
||||||
|
LIQUID <span className="text-[#00A3FF]">DEVELOPMENT</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:flex gap-6 text-sm font-medium text-gray-300 items-center">
|
||||||
|
{NAV_LINKS.map((item) => (
|
||||||
|
<a key={item} href={`#${item.toLowerCase()}`}
|
||||||
|
className="hover:text-[#00A3FF] transition-colors uppercase tracking-wide text-xs">{item}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
|
||||||
return (
|
{SOCIALS.map((social) => {
|
||||||
<nav className="fixed top-0 left-0 right-0 z-50 backdrop-blur-xl bg-[#0e0e0e]/90 border-b border-white/5">
|
const Icon = social.icon;
|
||||||
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
const isEmail = !social.link.startsWith('http');
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<BrandLogo className="w-8 h-8 text-[#00A3FF]" />
|
|
||||||
<span className="font-bold text-lg md:text-xl tracking-wider text-white">LIQUID<span className="text-[#00A3FF]">DEVELOPMENT</span></span>
|
|
||||||
</div>
|
|
||||||
<div className="hidden md:flex gap-6 text-sm font-medium text-gray-300 items-center">
|
|
||||||
{NAV_LINKS.map((item) => (
|
|
||||||
<a key={item} href={`#${item.toLowerCase()}`} className="hover:text-[#00A3FF] transition-colors uppercase tracking-wide text-xs">{item}</a>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<a href={SOCIALS.github} target="_blank" rel="noreferrer" className="bg-white/10 hover:bg-[#00A3FF] text-white p-2 rounded-full transition-all" title="GitHub">
|
|
||||||
<Github size={18} />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* Obfuscated Email Button */}
|
if (isEmail) {
|
||||||
<ObfuscatedMail
|
return (
|
||||||
email={rawEmail}
|
<ObfuscatedMail
|
||||||
className="bg-white/10 hover:bg-[#00A3FF] text-white p-2 rounded-full transition-all flex items-center justify-center"
|
key={social.name}
|
||||||
title="Contact Us"
|
email={social.link}
|
||||||
>
|
className="bg-white/10 hover:bg-[#00A3FF] text-white p-2 rounded-full transition-all flex items-center justify-center"
|
||||||
<Mail size={18} />
|
title={social.name}
|
||||||
</ObfuscatedMail>
|
>
|
||||||
</div>
|
<Icon size={18}/>
|
||||||
</div>
|
</ObfuscatedMail>
|
||||||
</nav>
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={social.name}
|
||||||
|
href={social.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="bg-white/10 hover:bg-[#00A3FF] text-white p-2 rounded-full transition-all"
|
||||||
|
title={social.name}
|
||||||
|
>
|
||||||
|
<Icon size={18}/>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const ObfuscatedMail = ({ email, className, children, title }) => {
|
export const ObfuscatedMail = ({email, className, children, title}) => {
|
||||||
// Start with a dummy link so bots don't see 'mailto:'
|
const handleClick = (e) => {
|
||||||
const [href, setHref] = useState("#");
|
e.preventDefault();
|
||||||
|
window.location.href = `mailto:${email}`;
|
||||||
|
};
|
||||||
|
|
||||||
// Only reveal the real email when the user hovers or focuses
|
return (
|
||||||
const reveal = () => {
|
<button
|
||||||
setHref(`mailto:${email}`);
|
onClick={handleClick}
|
||||||
};
|
className={className}
|
||||||
|
title={title || "Send email"}
|
||||||
return (
|
type="button"
|
||||||
<a
|
>
|
||||||
href={href}
|
{children}
|
||||||
onMouseEnter={reveal}
|
</button>
|
||||||
onFocus={reveal}
|
);
|
||||||
onClick={reveal}
|
|
||||||
className={className}
|
|
||||||
title={title || "Send email"}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,43 +1,71 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import {motion} from 'framer-motion';
|
||||||
import { Github, Mail, Globe } from 'lucide-react';
|
import {Github, Mail, Globe} from 'lucide-react';
|
||||||
import { ObfuscatedMail } from './ObfuscatedMail';
|
import {ObfuscatedMail} from './ObfuscatedMail';
|
||||||
|
import {ROLES} from '../data/content';
|
||||||
|
|
||||||
export const TeamMember = ({ name, nickname, img, gh, email, website, role, role2 }) => (
|
export const TeamMember = ({name, nickname, imageLink, githubLink, email, website, roles}) => (
|
||||||
<motion.div whileHover={{ y: -5 }} className="group relative bg-[#121212] rounded-2xl p-6 border border-white/10 flex flex-col items-center text-center overflow-hidden shadow-lg hover:border-[#00A3FF]/40 transition-all duration-300">
|
<motion.div whileHover={{y: -5}}
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
className="group relative bg-[#121212] rounded-2xl p-6 border border-white/10 flex flex-col items-center text-center overflow-hidden shadow-lg hover:border-[#00A3FF]/40 transition-all duration-300">
|
||||||
<div className="absolute top-0 w-full h-1 bg-[#00A3FF] scale-x-0 group-hover:scale-x-100 transition-transform duration-500 origin-left"></div>
|
<div
|
||||||
|
className="absolute inset-0 bg-gradient-to-b from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"
|
||||||
<div className="w-28 h-28 rounded-full mb-5 p-1 border-2 border-[#00A3FF]/30 group-hover:border-[#00A3FF] transition-colors relative z-10">
|
|
||||||
<img src={img} alt={name} className="w-full h-full rounded-full object-cover bg-gray-800" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative z-10 w-full">
|
|
||||||
<h4 className="text-xl font-bold text-white mb-1">{name}</h4>
|
|
||||||
<span className="text-sm font-mono text-gray-500 mb-4 block">@{nickname.toLowerCase()}</span>
|
|
||||||
|
|
||||||
<div className="flex gap-2 justify-center mb-6">
|
|
||||||
<span className="px-3 py-1 rounded-md bg-[#00A3FF]/10 text-[#00A3FF] text-xs font-bold border border-[#00A3FF]/20 tracking-wider">FOUNDER</span>
|
|
||||||
<span className="px-3 py-1 rounded-md bg-blue-500/10 text-blue-300 text-xs font-bold border border-blue-500/20 tracking-wider">DEVELOPER</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3 justify-center w-full">
|
|
||||||
{/* Obfuscated Member Mail */}
|
|
||||||
<ObfuscatedMail
|
|
||||||
email={email}
|
|
||||||
className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center group/icon"
|
|
||||||
title="Email"
|
|
||||||
>
|
>
|
||||||
<Mail size={18} />
|
</div>
|
||||||
</ObfuscatedMail>
|
<div
|
||||||
|
className="absolute top-0 w-full h-1 bg-[#00A3FF] scale-x-0 group-hover:scale-x-100 transition-transform duration-500 origin-left"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href={gh} target="_blank" rel="noreferrer" className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center" title="GitHub">
|
<div
|
||||||
<Github size={18} />
|
className="w-28 h-28 rounded-full mb-5 p-1 border-2 border-[#00A3FF]/30 group-hover:border-[#00A3FF] transition-colors relative z-10">
|
||||||
</a>
|
<img src={imageLink} alt={name} className="w-full h-full rounded-full object-cover bg-gray-800"/>
|
||||||
<a href={website} target="_blank" rel="noreferrer" className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center" title="Website">
|
</div>
|
||||||
<Globe size={18} />
|
|
||||||
</a>
|
<div className="relative z-10 w-full">
|
||||||
</div>
|
<h4 className="text-xl font-bold text-white mb-1">{name}</h4>
|
||||||
</div>
|
<span className="text-sm font-mono text-gray-500 mb-4 block">@{nickname.toLowerCase()}</span>
|
||||||
</motion.div>
|
|
||||||
|
<div className="flex gap-2 justify-center mb-6">
|
||||||
|
{roles.map((roleId) => {
|
||||||
|
const roleData = ROLES.find(r => r.id === roleId);
|
||||||
|
if (!roleData) return null;
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={roleId}
|
||||||
|
className="px-3 py-1 rounded-md text-xs font-bold border tracking-wider"
|
||||||
|
style={{
|
||||||
|
backgroundColor: `${roleData.bgColor}1A`,
|
||||||
|
color: roleData.textColor,
|
||||||
|
borderColor: `${roleData.borderColor}33`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{roleData.role}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-3 justify-center w-full">
|
||||||
|
{/* Obfuscated Member Mail */}
|
||||||
|
<ObfuscatedMail
|
||||||
|
email={email}
|
||||||
|
className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center group/icon"
|
||||||
|
title="Email"
|
||||||
|
>
|
||||||
|
<Mail size={18}/>
|
||||||
|
</ObfuscatedMail>
|
||||||
|
|
||||||
|
<a href={githubLink} target="_blank" rel="noreferrer"
|
||||||
|
className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center"
|
||||||
|
title="GitHub">
|
||||||
|
<Github size={18}/>
|
||||||
|
</a>
|
||||||
|
<a href={website} target="_blank" rel="noreferrer"
|
||||||
|
className="flex-1 py-2 rounded-lg bg-white/5 hover:bg-[#00A3FF] hover:text-white text-gray-400 transition-all flex justify-center items-center"
|
||||||
|
title="Website">
|
||||||
|
<Globe size={18}/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,41 +1,58 @@
|
|||||||
import { Github, Mail } from 'lucide-react';
|
import { Github, Mail } from 'lucide-react';
|
||||||
|
import { FaDiscord } from 'react-icons/fa';
|
||||||
|
|
||||||
export const NAV_LINKS = ['Home', 'Projects', 'Team'];
|
export const NAV_LINKS = ['Home', 'Projects', 'Team'];
|
||||||
|
|
||||||
export const SOCIALS = {
|
export const SOCIALS = [
|
||||||
github: "https://github.com/LiquidDevelopmentDE/",
|
{
|
||||||
email: "mailto:hello@liquid-dev.de"
|
name: "GitHub",
|
||||||
};
|
link: "https://github.liquid-dev.de",
|
||||||
|
icon: Github
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Discord",
|
||||||
|
link: "https://discord.liquid-dev.de",
|
||||||
|
icon: FaDiscord
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "E-Mail",
|
||||||
|
link: "hello@liquid-dev.de",
|
||||||
|
icon: Mail
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export const TEAM_MEMBERS = [
|
export const TEAM_MEMBERS = [
|
||||||
{
|
{
|
||||||
name: "Felix",
|
name: "Felix",
|
||||||
nickname: "Flixcoo",
|
nickname: "Flixcoo",
|
||||||
role: "FOUNDER",
|
roles: [0, 1],
|
||||||
role2: "DEVELOPER",
|
imageLink: "https://github.com/flixcoo.png",
|
||||||
img: "https://github.com/flixcoo.png",
|
githubLink: "https://github.com/flixcoo",
|
||||||
gh: "https://github.com/flixcoo",
|
email: "felix@liquid-dev.de",
|
||||||
email: "felix@liquid-dev.de",
|
website: "https://felixkirchner.de"
|
||||||
website: "https://felixkirchner.de"
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "Yannick",
|
||||||
name: "Yannick",
|
nickname: "Gelbeinhalb",
|
||||||
nickname: "Gelbeinhalb",
|
roles: [0, 1],
|
||||||
role: "FOUNDER",
|
imageLink: "https://github.com/GelbEinhalb.png",
|
||||||
role2: "DEVELOPER",
|
githubLink: "https://github.com/GelbEinhalb",
|
||||||
img: "https://github.com/GelbEinhalb.png",
|
email: "yannick@liquid-dev.de",
|
||||||
gh: "https://github.com/GelbEinhalb",
|
website: "https://yannick-weigert.de"
|
||||||
email: "yannick@liquid-dev.de",
|
},
|
||||||
website: "https://yannick-weigert.de"
|
{
|
||||||
},
|
name: "Mathis",
|
||||||
{
|
nickname: "Sneeex",
|
||||||
name: "Mathis",
|
roles: [0, 1],
|
||||||
nickname: "Sneeex",
|
imageLink: "https://github.com/sneeex.png",
|
||||||
role: "FOUNDER",
|
githubLink: "https://github.com/sneeex",
|
||||||
role2: "DEVELOPER",
|
email: "mathis@liquid-dev.de",
|
||||||
img: "https://github.com/mathiskir.png",
|
website: "https://mathiskirchner.de"
|
||||||
gh: "https://github.com/mathiskir",
|
}
|
||||||
email: "mathis@liquid-dev.de",
|
];
|
||||||
website: "https://mathiskirchner.de"
|
|
||||||
}
|
|
||||||
|
export const ROLES = [
|
||||||
|
{id: 0, role: "FOUNDER", bgColor: "#1e40af", borderColor: "#1e40af", textColor: "#60a5fa"},
|
||||||
|
{id: 1, role: "DEVELOPER", bgColor: "#0284c7", borderColor: "#0284c7", textColor: "#00b8f9"},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
html { scroll-behavior: smooth; }
|
html {
|
||||||
body { margin: 0; background: #0e0e0e; }
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #0e0e0e;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ import React from 'react'
|
|||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import App from './App.jsx'
|
import App from './App.jsx'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode><App /></React.StrictMode>)
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode><App/></React.StrictMode>)
|
||||||
|
|||||||
@@ -7,42 +7,86 @@ import { ObfuscatedMail } from '../components/ObfuscatedMail';
|
|||||||
import { SOCIALS } from '../data/content';
|
import { SOCIALS } from '../data/content';
|
||||||
|
|
||||||
export const Hero = () => {
|
export const Hero = () => {
|
||||||
const rawEmail = SOCIALS.email.replace('mailto:', '');
|
const emailSocial = SOCIALS.find(s => !s.link.startsWith('http'));
|
||||||
|
const rawEmail = emailSocial ? emailSocial.link : 'hello@liquid-dev.de';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="home" className="relative h-screen flex items-center justify-center pt-20 overflow-hidden">
|
<section
|
||||||
<div className="absolute inset-0 opacity-10" style={{ backgroundImage: 'radial-gradient(#ffffff 1px, transparent 1px)', backgroundSize: '40px 40px' }}></div>
|
id="home"
|
||||||
<Bubbles />
|
className="relative h-screen flex items-center justify-center pt-20 overflow-hidden"
|
||||||
<div className="relative z-10 text-center px-6 max-w-6xl mx-auto">
|
>
|
||||||
<motion.div initial={{ scale: 0.8, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} transition={{ duration: 0.8 }} className="mx-auto mb-8 w-24 h-24 md:w-32 md:h-32 rounded-full bg-[#00A3FF]/5 flex items-center justify-center border border-[#00A3FF]/30 shadow-[0_0_60px_-10px_rgba(0,163,255,0.4)]">
|
<div
|
||||||
<BrandLogo className="w-14 h-14 md:w-20 md:h-20 text-[#00A3FF]" />
|
className="absolute inset-0 opacity-10"
|
||||||
</motion.div>
|
style={{
|
||||||
|
backgroundImage: 'radial-gradient(#ffffff 1px, transparent 1px)',
|
||||||
<motion.div initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ delay: 0.2 }}>
|
backgroundSize: '40px 40px',
|
||||||
{/* Obfuscated Title Link */}
|
}}
|
||||||
<ObfuscatedMail email={rawEmail} className="block cursor-pointer hover:opacity-80 transition-opacity duration-300">
|
/>
|
||||||
<h1 className="text-4xl md:text-7xl font-extrabold tracking-tighter mb-6">
|
|
||||||
LIQUID <span className="text-transparent bg-clip-text bg-gradient-to-r from-[#00A3FF] to-cyan-200">DEVELOPMENT</span>
|
|
||||||
</h1>
|
|
||||||
</ObfuscatedMail>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
<motion.p initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ delay: 0.4 }} className="text-lg md:text-2xl text-gray-400 mb-10 max-w-2xl mx-auto font-light">German Development Team</motion.p>
|
<Bubbles />
|
||||||
|
|
||||||
<motion.div initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ delay: 0.6 }} className="flex flex-col sm:flex-row gap-6 justify-center items-center">
|
<div className="relative z-10 text-center px-6 max-w-6xl mx-auto">
|
||||||
<a href="#projects" className="px-8 py-3 rounded-full border border-[#00A3FF] hover:bg-[#00A3FF]/10 text-white font-bold transition-all flex items-center justify-center gap-2">
|
<motion.div
|
||||||
Explore Work
|
initial={{ scale: 0.8, opacity: 0 }}
|
||||||
</a>
|
animate={{ scale: 1, opacity: 1 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
{/* Obfuscated Text Button */}
|
className="mx-auto mb-8 w-24 h-24 md:w-32 md:h-32 rounded-full bg-[#00A3FF]/5 flex items-center justify-center border border-[#00A3FF]/30 shadow-[0_0_60px_-10px_rgba(0,163,255,0.4)]"
|
||||||
<ObfuscatedMail
|
>
|
||||||
email={rawEmail}
|
<BrandLogo className="w-14 h-14 md:w-20 md:h-20 text-[#00A3FF]" />
|
||||||
className="group flex items-center gap-2 text-white hover:text-gray-400 transition-colors font-medium cursor-pointer"
|
</motion.div>
|
||||||
>
|
|
||||||
Contact Team <ArrowRight size={18} className="group-hover:translate-x-1 transition-transform text-[#00A3FF]"/>
|
<motion.div
|
||||||
</ObfuscatedMail>
|
initial={{ y: 20, opacity: 0 }}
|
||||||
</motion.div>
|
animate={{ y: 0, opacity: 1 }}
|
||||||
</div>
|
transition={{ delay: 0.2 }}
|
||||||
</section>
|
>
|
||||||
);
|
<h1 className="text-4xl md:text-7xl font-extrabold tracking-tighter mb-6">
|
||||||
|
<ObfuscatedMail
|
||||||
|
email={rawEmail}
|
||||||
|
className="cursor-pointer hover:opacity-80 transition-opacity duration-300 bg-transparent border-none p-0 font-extrabold tracking-tighter text-4xl md:text-7xl text-white"
|
||||||
|
>
|
||||||
|
LIQUID
|
||||||
|
<span className="ml-3 text-transparent bg-clip-text bg-gradient-to-r from-[#00A3FF] to-cyan-200">
|
||||||
|
DEVELOPMENT
|
||||||
|
</span>
|
||||||
|
</ObfuscatedMail>
|
||||||
|
</h1>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
initial={{ y: 20, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
transition={{ delay: 0.4 }}
|
||||||
|
className="text-lg md:text-2xl text-gray-400 mb-10 max-w-2xl mx-auto font-light"
|
||||||
|
>
|
||||||
|
Open-source software development team
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ y: 20, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
transition={{ delay: 0.6 }}
|
||||||
|
className="flex flex-col sm:flex-row gap-6 justify-center items-center"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#projects"
|
||||||
|
className="px-8 py-3 rounded-full border border-[#00A3FF] hover:bg-[#00A3FF]/10 text-white font-bold transition-all flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
Explore Work
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ObfuscatedMail
|
||||||
|
email={rawEmail}
|
||||||
|
className="group flex items-center gap-2 text-white hover:text-gray-400 transition-colors font-medium cursor-pointer"
|
||||||
|
>
|
||||||
|
Contact Team
|
||||||
|
<ArrowRight
|
||||||
|
size={18}
|
||||||
|
className="group-hover:translate-x-1 transition-transform text-[#00A3FF]"
|
||||||
|
/>
|
||||||
|
</ObfuscatedMail>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,36 +1,87 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowRight, Smartphone } from 'lucide-react';
|
import {ArrowRight, Smartphone} from 'lucide-react';
|
||||||
import { FadeInWhenVisible } from '../utils/animations';
|
import {FadeInWhenVisible} from '../utils/animations';
|
||||||
|
|
||||||
export const Projects = () => (
|
export const Projects = () => (
|
||||||
<section id="projects" className="py-32 relative z-10 bg-gradient-to-b from-[#0e0e0e] to-[#050505] overflow-hidden">
|
<section id="projects" className="py-32 relative z-10 bg-gradient-to-b from-[#0e0e0e] to-[#050505] overflow-hidden">
|
||||||
<div className="absolute right-0 top-1/4 w-1/2 h-1/2 bg-[#00A3FF]/10 blur-[120px] rounded-full pointer-events-none"></div>
|
<div
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
className="absolute right-0 top-1/4 w-1/2 h-1/2 bg-[#00A3FF]/10 blur-[120px] rounded-full pointer-events-none"
|
||||||
<div className="mb-20"><h2 className="text-4xl md:text-5xl font-bold mb-4">Projects</h2><div className="h-1 w-24 bg-[#00A3FF] rounded-full"></div></div>
|
></div>
|
||||||
<FadeInWhenVisible>
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="grid lg:grid-cols-2 gap-12 items-center bg-[#121212] rounded-3xl p-8 md:p-12 border border-white/10 hover:border-[#00A3FF]/30 transition-all duration-500 shadow-2xl">
|
<div className="mb-20"><h2 className="text-4xl md:text-5xl font-bold mb-4">Projects</h2>
|
||||||
<div>
|
<div className="h-1 w-24 bg-[#00A3FF] rounded-full"></div>
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-[#00A3FF]/10 text-[#00A3FF] text-xs font-bold mb-6 border border-[#00A3FF]/20"><span className="animate-pulse w-2 h-2 rounded-full bg-[#00A3FF]"></span> IN DEVELOPMENT</div>
|
</div>
|
||||||
<h3 className="text-3xl md:text-4xl font-bold text-white mb-4">GameTracker App</h3>
|
<FadeInWhenVisible>
|
||||||
<p className="text-gray-300 text-lg mb-6 leading-relaxed">An all-in-one app to track card- and board games, manage players and groups and get statistics about your played games.</p>
|
<div
|
||||||
<div className="flex flex-wrap gap-2 mb-8">{['Flutter', 'iOS', 'Android', 'Statistics'].map(tag => (<span key={tag} className="px-3 py-1 bg-white/5 border border-white/10 rounded-md text-sm text-gray-400">{tag}</span>))}</div>
|
className="grid lg:grid-cols-2 gap-12 items-center bg-[#121212] rounded-3xl p-8 md:p-12 border border-white/10 hover:border-[#00A3FF]/30 transition-all duration-500 shadow-2xl"
|
||||||
<a href="https://github.com/LiquidDevelopmentDE/game-tracker" target="_blank" rel="noreferrer" className="inline-flex items-center text-white font-semibold hover:text-[#00A3FF] transition-colors group">View Project Status <ArrowRight className="ml-2 group-hover:translate-x-1 transition-transform" size={20} /></a>
|
>
|
||||||
</div>
|
<div>
|
||||||
<div className="relative h-[460px] bg-gradient-to-br from-gray-900 to-black rounded-xl border border-white/10 flex items-center justify-center overflow-hidden group">
|
<div
|
||||||
<div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-10"></div>
|
className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-[#00A3FF]/10 text-[#00A3FF] text-xs font-bold mb-6 border border-[#00A3FF]/20"
|
||||||
<div className="relative w-[180px] h-[370px] bg-gray-800 rounded-[2.5rem] border-[6px] border-gray-700 shadow-2xl flex flex-col overflow-hidden transform group-hover:scale-105 group-hover:rotate-[-2deg] transition-all duration-500">
|
>
|
||||||
<div className="h-6 w-24 bg-black absolute top-0 left-1/2 -translate-x-1/2 rounded-b-xl z-20"></div>
|
<span className="animate-pulse w-2 h-2 rounded-full bg-[#00A3FF]"></span>
|
||||||
<div className="h-full bg-gray-900 flex flex-col pt-10 px-3">
|
IN DEVELOPMENT
|
||||||
<div className="h-5 w-24 bg-[#00A3FF]/20 rounded mb-5 self-center"></div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-2 mb-3"><div className="h-20 bg-gray-800 rounded-lg border border-white/5"></div><div className="h-20 bg-gray-800 rounded-lg border border-white/5"></div></div>
|
<h3 className="text-3xl md:text-4xl font-bold text-white mb-4">GameTracker App</h3>
|
||||||
<div className="h-28 bg-gray-800 rounded-lg border border-white/5 mb-3"></div>
|
<p className="text-gray-300 text-lg mb-6 leading-relaxed">
|
||||||
<div className="flex-1 bg-gray-800/50 rounded-t-xl border-t border-white/5 mt-2"></div>
|
An all-in-one app to track card- and
|
||||||
|
board games, manage players and groups and get statistics about your played games.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
className="flex flex-wrap gap-2 mb-8"
|
||||||
|
>
|
||||||
|
{['Flutter', 'iOS', 'Android', 'Statistics'].map(tag => (
|
||||||
|
<span key={tag}
|
||||||
|
className="px-3 py-1 bg-white/5 border border-white/10 rounded-md text-sm text-gray-400"
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<a href="https://github.com/LiquidDevelopmentDE/game-tracker"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center text-white font-semibold hover:text-[#00A3FF] transition-colors group"
|
||||||
|
>
|
||||||
|
View Project Repository
|
||||||
|
<ArrowRight
|
||||||
|
className="ml-2 group-hover:translate-x-1 transition-transform" size={20}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="relative h-[460px] bg-gradient-to-br from-gray-900 to-black rounded-xl border border-white/10 flex items-center justify-center overflow-hidden group"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-10"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="relative w-[180px] h-[370px] bg-gray-800 rounded-[2.5rem] border-[6px] border-gray-700 shadow-2xl flex flex-col overflow-hidden transform group-hover:scale-105 group-hover:rotate-[-2deg] transition-all duration-500"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="h-6 w-24 bg-black absolute top-0 left-1/2 -translate-x-1/2 rounded-b-xl z-20"
|
||||||
|
></div>
|
||||||
|
<div className="h-full bg-gray-900 flex flex-col pt-10 px-3">
|
||||||
|
<div className="h-5 w-24 bg-[#00A3FF]/20 rounded mb-5 self-center"></div>
|
||||||
|
<div className="grid grid-cols-2 gap-2 mb-3">
|
||||||
|
<div className="h-20 bg-gray-800 rounded-lg border border-white/5"></div>
|
||||||
|
<div className="h-20 bg-gray-800 rounded-lg border border-white/5"></div>
|
||||||
|
</div>
|
||||||
|
<div className="h-28 bg-gray-800 rounded-lg border border-white/5 mb-3"></div>
|
||||||
|
<div className="flex-1 bg-gray-800/50 rounded-t-xl border-t border-white/5 mt-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="absolute bottom-6 right-6 bg-black/80 backdrop-blur-md border border-[#00A3FF]/50 p-3 rounded-lg flex items-center gap-3 shadow-lg transform group-hover:translate-y-2 transition-transform z-30"
|
||||||
|
>
|
||||||
|
<div className="text-right">
|
||||||
|
<div className="text-xs text-gray-400">Soon available on</div>
|
||||||
|
<div className="text-sm font-bold text-white">iOS & Android</div>
|
||||||
|
</div>
|
||||||
|
<Smartphone size={24} className="text-[#00A3FF]"/></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</FadeInWhenVisible>
|
||||||
<div className="absolute bottom-6 right-6 bg-black/80 backdrop-blur-md border border-[#00A3FF]/50 p-3 rounded-lg flex items-center gap-3 shadow-lg transform group-hover:translate-y-2 transition-transform z-30"><div className="text-right"><div className="text-xs text-gray-400">Soon available on</div><div className="text-sm font-bold text-white">iOS & Android</div></div><Smartphone size={24} className="text-[#00A3FF]" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</FadeInWhenVisible>
|
</section>
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FadeInWhenVisible } from '../utils/animations';
|
import {FadeInWhenVisible} from '../utils/animations';
|
||||||
import { TeamMember } from '../components/TeamMember';
|
import {TeamMember} from '../components/TeamMember';
|
||||||
import { TEAM_MEMBERS } from '../data/content';
|
import {TEAM_MEMBERS} from '../data/content';
|
||||||
|
|
||||||
export const Team = () => (
|
export const Team = () => (
|
||||||
<section id="team" className="py-24 relative z-10 bg-gradient-to-b from-[#050505] to-black">
|
<section id="team" className="py-24 relative z-10 bg-gradient-to-b from-[#050505] to-black">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="text-center mb-16"><h2 className="text-3xl md:text-4xl font-bold mb-4">The Team</h2><p className="text-gray-400">Meet the creators.</p></div>
|
<div className="text-center mb-16">
|
||||||
<div className="grid md:grid-cols-3 gap-8 justify-center max-w-5xl mx-auto">
|
<h2 className="text-3xl md:text-4xl font-bold mb-4">
|
||||||
{TEAM_MEMBERS.map((member, index) => (
|
The Team
|
||||||
<FadeInWhenVisible key={member.name} delay={0.1 * (index + 1)}>
|
</h2>
|
||||||
<TeamMember {...member} />
|
<p
|
||||||
</FadeInWhenVisible>
|
className="text-gray-400">Meet the creators.
|
||||||
))}
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="grid md:grid-cols-3 gap-8 justify-center max-w-5xl mx-auto">
|
||||||
</section>
|
{TEAM_MEMBERS.map((member, index) => (
|
||||||
|
<FadeInWhenVisible key={member.name} delay={0.1 * (index + 1)}>
|
||||||
|
<TeamMember {...member} />
|
||||||
|
</FadeInWhenVisible>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, {useRef} from 'react';
|
||||||
import { motion, useInView } from 'framer-motion';
|
import {motion, useInView} from 'framer-motion';
|
||||||
|
|
||||||
export const fadeInUp = {
|
export const fadeInUp = {
|
||||||
hidden: { opacity: 0, y: 30 },
|
hidden: {opacity: 0, y: 30},
|
||||||
visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: "easeOut" } }
|
visible: {opacity: 1, y: 0, transition: {duration: 0.6, ease: "easeOut"}}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FadeInWhenVisible = ({ children, delay = 0 }) => {
|
export const FadeInWhenVisible = ({children, delay = 0}) => {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
const isInView = useInView(ref, { once: true, margin: "-50px" });
|
const isInView = useInView(ref, {once: true, margin: "-50px"});
|
||||||
return (
|
return (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
<motion.div
|
<motion.div
|
||||||
variants={fadeInUp}
|
variants={fadeInUp}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate={isInView ? "visible" : "hidden"}
|
animate={isInView ? "visible" : "hidden"}
|
||||||
transition={{ delay }}
|
transition={{delay}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user