api done
This commit is contained in:
@@ -31,9 +31,14 @@ export default function Footer() {
|
||||
|
||||
function Social({ href, label, children }: { href: string; label: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<a href={href} target="_blank" rel="noreferrer" aria-label={label}
|
||||
className="rounded p-2 transition-transform duration-200 hover:scale-110 hover:text-[var(--c-other)]">
|
||||
{children}
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
aria-label={label}
|
||||
className="group relative inline-flex items-center justify-center w-12 h-12 rounded-xl bg-brandGradient text-white shadow-glow transition-transform duration-200 hover:scale-110"
|
||||
>
|
||||
<span className="text-xl group-hover:scale-110 transition-transform">{children}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,20 +17,19 @@ export default function ContactMeForm() {
|
||||
if (!opened) {
|
||||
setOpened(true)
|
||||
setOpeningBehind(false)
|
||||
setContentMoveUp(false)
|
||||
setContentMoveUp(false)
|
||||
// Wait for the rotate-opening animation to finish before moving content up
|
||||
// The actual moveUp will be handled in onTransitionEnd
|
||||
} else {
|
||||
setContentMoveUp(false)
|
||||
setOpeningBehind(false)
|
||||
setTimeout(() => setOpened(false), 1000) // match transition duration
|
||||
setTimeout(() => setOpened(false), 1000) // match transition duration
|
||||
}
|
||||
}
|
||||
|
||||
const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
|
||||
if (opened && e.propertyName === "transform") {
|
||||
setContentMoveUp(true)
|
||||
// Move the opening behind after the animation
|
||||
setContentMoveUp(true)
|
||||
setTimeout(() => setOpeningBehind(true), 10)
|
||||
}
|
||||
if (!opened && e.propertyName === "transform") {
|
||||
@@ -39,6 +38,7 @@ export default function ContactMeForm() {
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<div className={styles["contact-me"]}>
|
||||
<div
|
||||
ref={openingRef}
|
||||
@@ -56,11 +56,10 @@ export default function ContactMeForm() {
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
contentMoveUp
|
||||
? `${styles.content} ${styles["content-moveup"]}`
|
||||
: styles.content
|
||||
}
|
||||
className={[
|
||||
styles.content,
|
||||
contentMoveUp ? styles["content-moveup"] : ''
|
||||
].filter(Boolean).join(' ')}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
.contact-me {
|
||||
margin: 5em auto;
|
||||
margin: 15em auto;
|
||||
margin-top: 15em;
|
||||
margin-bottom: 3em;
|
||||
position: relative;
|
||||
|
||||
aspect-ratio: 16 / 9;
|
||||
|
||||
background-color: #c8c8c8;
|
||||
background: var(--c-background-light);
|
||||
max-width: 100vw;
|
||||
border: 2px solid var(--c-lines);
|
||||
border-radius: 0.75em;
|
||||
width: 30em;
|
||||
}
|
||||
.contact-me + .mail-box{
|
||||
|
||||
}
|
||||
/* .mail-box sibling styles were unused; removed to satisfy linter */
|
||||
|
||||
.contact-me .opening {
|
||||
width: 100%;
|
||||
@@ -17,21 +18,17 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
z-index: 2;
|
||||
transform-origin: top;
|
||||
|
||||
padding-top: 4em;
|
||||
|
||||
clip-path: polygon(0 0, 100% 0, 50% 50%);
|
||||
background-color: #d2d2d2;
|
||||
|
||||
transition: all 1s ease;
|
||||
|
||||
background: linear-gradient(135deg, var(--c-boxes), var(--c-other));
|
||||
transition: transform 1s ease, background 0.5s ease;
|
||||
text-align: center;
|
||||
color: var(--c-text);
|
||||
}
|
||||
.rotate-opening{
|
||||
background-color: #c8c8c8;
|
||||
background: linear-gradient(135deg, var(--c-background-light), var(--c-boxes));
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
|
||||
@@ -52,22 +49,22 @@
|
||||
.content-moveup{
|
||||
transform: translateY(-70%);
|
||||
}
|
||||
.content-moveup-index {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
.content-moveup-index { z-index: 2 !important; }
|
||||
|
||||
.contact-me .content form{
|
||||
width: 80%;
|
||||
width: 90%;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
background-color: #deefff;
|
||||
padding: 1em;
|
||||
border: 0.5em dashed #88d4ed;
|
||||
border-radius: 0.25em;
|
||||
background: color-mix(in hsl, var(--c-background-light), transparent 35%);
|
||||
backdrop-filter: blur(6px);
|
||||
padding: 1.5em;
|
||||
border: 0.35em dashed var(--c-lines);
|
||||
border-radius: 0.75em;
|
||||
color: var(--c-text);
|
||||
}
|
||||
.contact-me .content form div{
|
||||
width: -webkit-fill-available;
|
||||
@@ -77,26 +74,37 @@
|
||||
.contact-me .content form input[type=submit]{
|
||||
margin: auto;
|
||||
border: none;
|
||||
background: #4ca4d5;
|
||||
color: #ffffff;
|
||||
padding: 1em 1.5em;
|
||||
background: linear-gradient(135deg, var(--c-other), var(--c-boxes));
|
||||
color: var(--c-text);
|
||||
padding: 0.85em 1.5em;
|
||||
cursor: pointer;
|
||||
border-radius: 1em;
|
||||
border-radius: 0.75em;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 0 12px -3px rgba(112,162,136,0.5);
|
||||
transition: transform 0.2s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
.contact-me .content form input[type=submit]:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0 20px -2px rgba(112,162,136,0.65);
|
||||
}
|
||||
|
||||
.contact-me .content form input[type=text],
|
||||
.contact-me .content form input[type=email],
|
||||
.contact-me .content form textarea{
|
||||
background-color: #bfe8ff;
|
||||
border: none;
|
||||
border-bottom: 0.15em solid #064c7d;
|
||||
padding: 0.5em;
|
||||
|
||||
background: var(--c-background-light);
|
||||
border: 1px solid var(--c-lines);
|
||||
padding: 0.6em 0.75em;
|
||||
border-radius: 0.5em;
|
||||
color: var(--c-text);
|
||||
}
|
||||
.contact-me .content form input[type=text]::placeholder,
|
||||
.contact-me .content form input[type=email]::placeholder,
|
||||
.contact-me .content form textarea::placeholder{ color: color-mix(in srgb, var(--c-lines), white 25%); }
|
||||
|
||||
.opening-behind { z-index: 0 !important; }
|
||||
|
||||
.contact-me .cover {
|
||||
border-radius: 1em;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -104,9 +112,10 @@
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
clip-path: polygon(0 0, 50% 50%, 100% 0, 100% 100%, 0 100%);
|
||||
background-color: #f0f0f0;
|
||||
background: var(--c-background);
|
||||
}
|
||||
.contact-me .triangle{
|
||||
border-radius: 1em;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
@@ -114,7 +123,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
clip-path: polygon(100% 0, 0 100%, 100% 100%);
|
||||
background-color: rgb(255 255 255);
|
||||
background: linear-gradient(135deg, var(--c-boxes), var(--c-background-light));
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
@@ -140,6 +149,13 @@
|
||||
@media only screen and (max-width: 990px){
|
||||
.contact-me{
|
||||
aspect-ratio: unset;
|
||||
margin-top: 7ch;
|
||||
margin-top: 3ch;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
.contact-me .opening,
|
||||
.contact-me .cover,
|
||||
.contact-me .triangle { display: none; }
|
||||
.contact-me .content { position: relative; width: 100%; transform: none !important; }
|
||||
.contact-me .content form { backdrop-filter: none; border: 1px solid var(--c-lines); }
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #c2a67d;
|
||||
color: #5e5747;
|
||||
/* Use brand palette accents and lines for door */
|
||||
background-color: var(--c-background-light);
|
||||
color: var(--c-text);
|
||||
|
||||
border-radius: 1em;
|
||||
|
||||
@@ -50,7 +51,7 @@
|
||||
}
|
||||
|
||||
.door i{
|
||||
color: #5e5747;
|
||||
color: var(--c-text);
|
||||
font-size: 5em;
|
||||
display: inline-block;
|
||||
animation: shake 0.4s ease-in-out infinite;
|
||||
@@ -70,8 +71,8 @@
|
||||
left: 0;
|
||||
padding: 1em 3em;
|
||||
padding-bottom: 0;
|
||||
background-color: #cdc19c;
|
||||
color: #5e5747;
|
||||
background-color: var(--c-background-light);
|
||||
color: var(--c-text);
|
||||
border-top-left-radius: 1em;
|
||||
border-top-right-radius: 1em;
|
||||
}
|
||||
@@ -125,7 +126,7 @@
|
||||
.portfolio div {
|
||||
width: 100%;
|
||||
padding: 3em;
|
||||
background-color: #cdc19c;
|
||||
background-color: var(--c-background-light);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
@@ -141,7 +142,7 @@
|
||||
.portfolio div article {
|
||||
display: flex;
|
||||
border-radius: 0em;
|
||||
background-color: #9c885c;
|
||||
background-color: var(--c-boxes);
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -4,26 +4,28 @@ import type { ReactNode } from 'react';
|
||||
type Tier = { id: string; title: string; price: number; desc: string; color: string; icon: ReactNode };
|
||||
|
||||
const tiers: Tier[] = [
|
||||
{ id: 'coffee', title: 'Coffee', price: 3, desc: 'Fuel late-night coding sessions.', color: '#d97706', icon: <FaCoffee /> },
|
||||
{ id: 'battery', title: 'Drone Battery', price: 30, desc: 'Extend aerial filming time.', color: '#16a34a', icon: <FaBatteryFull /> },
|
||||
{ id: 'gpu', title: 'GPU Upgrade', price: 200, desc: 'Speed up rendering and ML tasks.', color: '#6366f1', icon: <FaMicrochip /> },
|
||||
{ id: 'coffee', title: 'Coffee', price: 3, desc: 'Fuel late-night coding sessions.', color: 'var(--c-other)', icon: <FaCoffee /> },
|
||||
{ id: 'battery', title: 'Drone Battery', price: 30, desc: 'Extend aerial filming time.', color: 'var(--c-other)', icon: <FaBatteryFull /> },
|
||||
{ id: 'gpu', title: 'GPU Upgrade', price: 200, desc: 'Speed up rendering and ML tasks.', color: 'var(--c-other)', icon: <FaMicrochip /> },
|
||||
];
|
||||
|
||||
export default function DonationShop() {
|
||||
return (
|
||||
<section id="shop" className="section">
|
||||
<div className="container">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-2 text-rainbow">Support My Creative Journey</h2>
|
||||
<p className="text-gray-300">Instead of buying products, consider donating to support my creative journey.</p>
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-2 text-rainbow">Support My Creative Journey</h2>
|
||||
<p className="text-brand-text/80">Instead of buying products, consider donating to support my creative journey.</p>
|
||||
<div className="grid md:grid-cols-3 gap-6 mt-6">
|
||||
{tiers.map(t => (
|
||||
<div key={t.id} className="card p-5 flex flex-col">
|
||||
<div className="text-5xl mb-3" style={{ color: t.color }}>{t.icon}</div>
|
||||
<div className="text-5xl mb-3 inline-flex items-center justify-center w-20 h-20 rounded-xl bg-brandGradient text-white shadow-glow">
|
||||
{t.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold" style={{ color: t.color }}>{t.title}</h3>
|
||||
<p className="text-[var(--c-lines)] mt-1">{t.desc}</p>
|
||||
<div className="mt-auto flex items-center justify-between pt-4">
|
||||
<span className="text-2xl font-bold" style={{ color: t.color }}>${t.price}</span>
|
||||
<button className="px-4 py-2 rounded-lg font-semibold text-white bg-gradient-to-r from-fuchsia-600 to-orange-500 hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all" onClick={() => alert(`Thank you for supporting with ${t.title}!`)}>Donate</button>
|
||||
<button className="px-4 py-2 rounded-lg font-semibold text-brand-text bg-gradient-to-r from-[var(--c-other)] to-[var(--c-lines)] hover:shadow-glow transition-all" onClick={() => alert(`Thank you for supporting with ${t.title}!`)}>Donate</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -13,11 +13,11 @@ export default function HeroCarousel() {
|
||||
return (
|
||||
<section id="home" className="relative min-h-[80vh] md:min-h-[85vh] flex items-center justify-center overflow-hidden">
|
||||
{/* Background Gradient and animated glows */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-slate-800 via-slate-900 to-black -z-10" />
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[var(--c-background-light)] via-[var(--c-background)] to-[var(--c-background)] -z-10" />
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute top-1/4 left-1/4 w-64 h-64 bg-fuchsia-600/10 rounded-full blur-3xl animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-orange-500/10 rounded-full blur-3xl animate-pulse delay-1000" />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 h-80 bg-violet-400/10 rounded-full blur-3xl animate-pulse delay-2000" />
|
||||
<div className="absolute top-1/4 left-1/4 w-64 h-64 bg-brand-accent/10 rounded-full blur-3xl animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-brand-lines/10 rounded-full blur-3xl animate-pulse delay-1000" />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 h-80 bg-brand-boxes/10 rounded-full blur-3xl animate-pulse delay-2000" />
|
||||
</div>
|
||||
|
||||
<div className="relative container mx-auto px-4 py-10 grid lg:grid-cols-2 gap-10 items-center">
|
||||
@@ -25,18 +25,18 @@ export default function HeroCarousel() {
|
||||
<div className="text-center lg:text-left">
|
||||
<h1 className="text-4xl md:text-6xl font-bold mb-4 leading-tight">
|
||||
<span className="text-rainbow">Welcome to</span><br />
|
||||
<span className="text-white">Vontor.cz</span>
|
||||
<span className="text-brand-text">Vontor.cz</span>
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl text-gray-300 mb-6">Creative Tech & Design by <span className="text-fuchsia-600 font-semibold">Bruno Vontor</span></p>
|
||||
<p className="text-lg md:text-xl text-brand-text/80 mb-6">Creative Tech & Design by <span className="text-brand-accent font-semibold">Bruno Vontor</span></p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
|
||||
<a href="#portfolio" className="px-8 py-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300 transform hover:scale-105">View Portfolio</a>
|
||||
<a href="#contact" className="px-8 py-3 border-2 border-violet-400 text-violet-400 font-semibold rounded-lg hover:bg-violet-400 hover:text-white transition-all duration-300">Get In Touch</a>
|
||||
<a href="#portfolio" className="px-8 py-3 bg-gradient-to-r from-[var(--c-other)] to-[var(--c-lines)] text-brand-text font-semibold rounded-lg hover:shadow-glow transition-all duration-300 transform hover:scale-105">View Portfolio</a>
|
||||
<a href="#contact" className="px-8 py-3 border-2 border-brand-lines text-brand-lines font-semibold rounded-lg hover:bg-brand-lines hover:text-brand-bg transition-all duration-300">Get In Touch</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Video carousel */}
|
||||
<div className="relative">
|
||||
<div className="relative aspect-video bg-slate-800 rounded-xl overflow-hidden shadow-2xl">
|
||||
<div className="relative aspect-video bg-brand-bgLight rounded-xl overflow-hidden shadow-2xl">
|
||||
{videos.map((v,i) => (
|
||||
<iframe
|
||||
key={v}
|
||||
@@ -47,12 +47,12 @@ export default function HeroCarousel() {
|
||||
allowFullScreen
|
||||
/>
|
||||
))}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent pointer-events-none" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-brand-bg/60 to-transparent pointer-events-none" />
|
||||
</div>
|
||||
{/* Indicators */}
|
||||
<div className="flex justify-center mt-4 space-x-2">
|
||||
{videos.map((_,i) => (
|
||||
<button key={i} onClick={()=>setIndex(i)} aria-label={`Go to slide ${i+1}`} className={`w-3 h-3 rounded-full transition-all duration-300 ${i===index? 'bg-fuchsia-600':'bg-gray-600 hover:bg-gray-400'}`} />
|
||||
<button key={i} onClick={()=>setIndex(i)} aria-label={`Go to slide ${i+1}`} className={`w-3 h-3 rounded-full transition-all duration-300 ${i===index? 'bg-brand-accent':'bg-brand-lines/40 hover:bg-brand-lines/60'}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
|
||||
export default function HostingSecuritySection() {
|
||||
return (
|
||||
<section id="hosting" className="py-20">
|
||||
<div className="container mx-auto px-4">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-rainbow">Hosting & Protection</h2>
|
||||
<div className="card p-6 md:p-8">
|
||||
<p className="text-gray-300">We host our applications ourselves, which reduces hosting costs as projects scale.</p>
|
||||
<p className="text-gray-300 mt-2">All websites are protected by Cloudflare and optimized for performance.</p>
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-rainbow">Hosting & Protection</h2>
|
||||
<div className="card p-6 md:p-8">
|
||||
<p className="text-brand-text opacity-80">We host our applications ourselves, which reduces hosting costs as projects scale.</p>
|
||||
<p className="text-brand-text opacity-80 mt-2">All websites are protected by Cloudflare and optimized for performance.</p>
|
||||
<div className="grid grid-cols-3 md:grid-cols-6 gap-4 text-center text-sm mt-6">
|
||||
{['Server', 'Cloudflare', 'Docker', 'SSL', 'Monitoring', 'Scaling'].map(item => (
|
||||
<div key={item} className="p-3 rounded-lg bg-slate-700/50 text-violet-300 transition-transform duration-200 hover:scale-105">{item}</div>
|
||||
<div key={item} className="p-3 rounded-lg bg-brandGradient text-white shadow-glow transition-transform duration-200 hover:scale-105 flex flex-col items-center justify-center">
|
||||
<span className="text-xs tracking-wide">{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ nav{
|
||||
background: linear-gradient(117deg, rgba(34,34,34,1) 0%, rgba(59,54,54,1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#222222",endColorstr="#3b3636",GradientType=1);*/
|
||||
|
||||
color: #fff;
|
||||
color: var(--c-text);
|
||||
text-align: center;
|
||||
|
||||
margin: auto;
|
||||
@@ -52,7 +52,7 @@ nav a{
|
||||
text-decoration: none;
|
||||
}
|
||||
nav a:hover{
|
||||
color: #fff;
|
||||
color: var(--c-text);
|
||||
}
|
||||
/* Unify link/summary layout to prevent distortion */
|
||||
nav a,
|
||||
@@ -75,7 +75,7 @@ nav a::before {
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
background-color: var(--c-other);
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ nav a:hover::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
nav summary:hover {
|
||||
color: #fff;
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
/* underline effect shared for links and summary */
|
||||
@@ -96,7 +96,7 @@ nav summary::before {
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
background-color: var(--c-other);
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ export default function HomeNav() {
|
||||
|
||||
return (
|
||||
<nav className={styles.nav}>
|
||||
<FaBars
|
||||
className={`${styles.toggle} ${navOpen ? styles.toggleRotated : ""}`}
|
||||
<div
|
||||
className={`inline-flex items-center justify-center w-12 h-12 rounded-xl bg-brandGradient text-white shadow-glow cursor-pointer ${styles.toggle} ${navOpen ? styles.toggleRotated : ""}`}
|
||||
onClick={toggleNav}
|
||||
aria-label="Toggle navigation"
|
||||
aria-expanded={navOpen}
|
||||
/>
|
||||
>
|
||||
<FaBars />
|
||||
</div>
|
||||
|
||||
<ul className={`${styles.navList} ${navOpen ? styles.open : ""}`}>
|
||||
<li id="nav-logo" className={styles.logo}>
|
||||
@@ -30,7 +32,9 @@ export default function HomeNav() {
|
||||
<details>
|
||||
<summary>
|
||||
Services
|
||||
<FaChevronDown className={`${styles.caret} ml-2 inline-block`} aria-hidden="true" />
|
||||
<span className="inline-flex items-center justify-center w-6 h-6 rounded-md bg-brandGradient text-white ml-2 shadow-glow">
|
||||
<FaChevronDown className={styles.caret} aria-hidden="true" />
|
||||
</span>
|
||||
</summary>
|
||||
<ul className={styles.submenu}>
|
||||
<li><a href="#web">Web development</a></li>
|
||||
|
||||
@@ -16,19 +16,19 @@ export default function SiteNav() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header className={`sticky top-0 z-50 transition-all ${scrolled ? 'bg-slate-800/95 backdrop-blur-md shadow-lg' : 'bg-transparent'}`}>
|
||||
<nav className="relative container mx-auto px-4 flex items-center justify-between h-16 text-[var(--c-text)] font-medium">
|
||||
<header className={`sticky top-0 z-50 transition-all ${scrolled ? 'bg-brand-bg/95 backdrop-blur-md shadow-lg' : 'bg-transparent'}`}>
|
||||
<nav className="relative container mx-auto px-4 flex items-center justify-between h-16 text-brand-text font-medium">
|
||||
<div className="text-xl tracking-wide font-semibold">
|
||||
<NavLink to="/" className="inline-block px-2 py-1 rounded nav-item text-rainbow font-bold">vontor.cz</NavLink>
|
||||
</div>
|
||||
<button
|
||||
aria-label="Toggle navigation"
|
||||
onClick={() => setOpen(o => !o)}
|
||||
className="md:hidden p-2 rounded glow focus:outline-none"
|
||||
className="md:hidden p-2 rounded-xl glow focus:outline-none bg-brandGradient text-white shadow-glow"
|
||||
>
|
||||
{open ? <FaTimes /> : <FaBars />}
|
||||
</button>
|
||||
<ul className={`md:flex md:items-center md:gap-8 md:static absolute left-0 w-full md:w-auto transition-all duration-300 ${open ? 'top-16 bg-slate-800/95 pb-6 rounded-lg backdrop-blur-md' : 'top-[-500px]'}`}>
|
||||
<ul className={`md:flex md:items-center md:gap-8 md:static absolute left-0 w-full md:w-auto transition-all duration-300 ${open ? 'top-16 bg-brand-bg/95 pb-6 rounded-lg backdrop-blur-md' : 'top-[-500px]'}`}>
|
||||
<li className="flex"><NavLink to="/" onClick={()=>setOpen(false)} className={linkCls}>Home</NavLink></li>
|
||||
<li className="flex"><NavLink to="/portfolio" onClick={()=>setOpen(false)} className={linkCls}>Portfolio</NavLink></li>
|
||||
<li className="flex"><NavLink to="/skills" onClick={()=>setOpen(false)} className={linkCls}>Skills</NavLink></li>
|
||||
@@ -42,7 +42,7 @@ export default function SiteNav() {
|
||||
className={`nav-item px-3 py-2 flex items-center gap-1`}
|
||||
aria-haspopup="true" aria-expanded={servicesOpen}
|
||||
>
|
||||
More <FaChevronDown className={`transition-transform ${servicesOpen ? 'rotate-180' : ''}`} />
|
||||
<span className="inline-flex items-center gap-1">More <span className="inline-flex items-center justify-center w-6 h-6 rounded-md bg-brandGradient text-white"><FaChevronDown className={`transition-transform ${servicesOpen ? 'rotate-180' : ''}`} /></span></span>
|
||||
</button>
|
||||
{/* Mobile inline dropdown */}
|
||||
<div className={`md:hidden w-full mt-2 ${servicesOpen ? 'block' : 'hidden'}`}>
|
||||
@@ -69,5 +69,5 @@ export default function SiteNav() {
|
||||
);
|
||||
}
|
||||
|
||||
const linkCls = ({ isActive }: { isActive: boolean }) => `nav-item px-3 py-2 rounded transition-colors ${isActive ? 'active text-[var(--c-other)] font-semibold' : 'hover:text-[var(--c-other)]'}`;
|
||||
const linkCls = ({ isActive }: { isActive: boolean }) => `nav-item px-3 py-2 rounded transition-colors ${isActive ? 'active text-brand-accent font-semibold' : 'hover:text-brand-accent'}`;
|
||||
const dropdownCls = "block px-2 py-1 rounded hover:bg-[color-mix(in_hsl,var(--c-other),transparent_85%)]";
|
||||
@@ -8,11 +8,11 @@ const categories: { name: string; items: string[] }[] = [
|
||||
|
||||
export default function SkillsSection() {
|
||||
return (
|
||||
<section id="skills" className="py-20 bg-gradient-to-b from-slate-900 to-slate-800">
|
||||
<section id="skills" className="py-20 bg-gradient-to-b from-brand-bg to-brand-bgLight">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-4xl font-bold mb-4 text-rainbow">Skills</h2>
|
||||
<p className="text-gray-300 max-w-2xl mx-auto">Core technologies and tools I use across backend, frontend, infrastructure and hardware.</p>
|
||||
<p className="text-brand-text/80 max-w-2xl mx-auto">Core technologies and tools I use across backend, frontend, infrastructure and hardware.</p>
|
||||
</div>
|
||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{categories.map(cat => (
|
||||
@@ -20,9 +20,9 @@ export default function SkillsSection() {
|
||||
<h3 className="font-semibold mb-4 text-rainbow tracking-wide">{cat.name}</h3>
|
||||
<ul className="space-y-2 text-sm">
|
||||
{cat.items.map(i => (
|
||||
<li key={i} className="flex items-center gap-2 text-gray-300">
|
||||
<span className="inline-block w-2 h-2 rounded-full bg-fuchsia-600" />
|
||||
<span className="group-hover:text-white transition-colors">{i}</span>
|
||||
<li key={i} className="flex items-center gap-2 text-brand-text/80">
|
||||
<span className="inline-block w-2 h-2 rounded-full bg-brand-accent" />
|
||||
<span className="group-hover:text-brand-text transition-colors">{i}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
export default function TradingGraph() {
|
||||
return (
|
||||
<section id="live" className="py-20 bg-gradient-to-b from-slate-900 to-slate-800">
|
||||
<section id="live" className="py-20 bg-gradient-to-b from-brand-bg to-brand-bgLight">
|
||||
<div className="container mx-auto px-4">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-rainbow">Live Performance</h2>
|
||||
<div className="card p-4 md:p-6">
|
||||
<div className="mb-3 text-sm text-gray-400">Trading212 graph placeholder</div>
|
||||
<div className="aspect-[16/9] w-full rounded border border-slate-700 bg-black/40 grid place-items-center">
|
||||
<span className="text-gray-400">Graph will appear here</span>
|
||||
<div className="mb-3 text-sm text-brand-text/60">Trading212 graph placeholder</div>
|
||||
<div className="aspect-[16/9] w-full rounded border border-brand-lines/50 bg-brand-bg/40 grid place-items-center">
|
||||
<span className="text-brand-text/60">Graph will appear here</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,8 +28,8 @@ body {
|
||||
font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji";
|
||||
color: var(--c-text);
|
||||
background: radial-gradient(1200px 800px at 10% 10%, var(--c-background-light), transparent 60%),
|
||||
radial-gradient(1000px 700px at 90% 20%, rgba(135,169,218,0.15), transparent 60%),
|
||||
linear-gradient(180deg, var(--c-background) 0%, #02162f 100%);
|
||||
radial-gradient(1000px 700px at 90% 20%, color-mix(in hsl, var(--c-lines), transparent 85%), transparent 60%),
|
||||
linear-gradient(180deg, var(--c-background) 0%, color-mix(in hsl, var(--c-background), black 15%) 100%);
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -157,3 +157,20 @@ button:active { transform: translateY(1px) }
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use project palette for list markers (bullets) and summary markers */
|
||||
li::marker,
|
||||
ol li::marker,
|
||||
ul li::marker,
|
||||
summary::marker {
|
||||
color: var(--c-boxes);
|
||||
}
|
||||
|
||||
/* Ensure fallback for older browsers by tinting bullets via ::before where used */
|
||||
li.custom-marker::before {
|
||||
content: "\2022"; /* bullet */
|
||||
color: var(--c-boxes);
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,35 @@
|
||||
import ContactMeForm from "../../components/Forms/ContactMe/ContactMeForm";
|
||||
|
||||
export default function ContactPage(){
|
||||
return (
|
||||
<section className="section">
|
||||
<div className="container">
|
||||
<h2 className="text-2xl md:text-3xl font-bold mb-4">Get in Touch</h2>
|
||||
<p className="text-[var(--c-lines)] mb-6">Reach out via email or phone. Social links are in the footer.</p>
|
||||
<div className="glass p-6 max-w-lg">
|
||||
<h2 className="text-2xl md:text-3xl font-bold mb-2 text-rainbow">Get in Touch</h2>
|
||||
<p className="text-brand-lines mb-6">Reach out via the form or use the details below.</p>
|
||||
|
||||
{/* Desktop/tablet: envelope animation + slide-out form */}
|
||||
<div className="hidden md:block">
|
||||
<ContactMeForm />
|
||||
</div>
|
||||
|
||||
{/* Mobile: simple card version without envelope */}
|
||||
<div className="md:hidden">
|
||||
<div className="card p-5">
|
||||
<form className="space-y-3">
|
||||
<div>
|
||||
<label className="block text-sm text-brand-lines mb-1">Your email</label>
|
||||
<input type="email" required className="w-full rounded-lg bg-brand-bgLight/40 border border-brand-lines/40 focus:outline-none focus:ring-2 focus:ring-brand-accent px-3 py-2 text-brand-text placeholder:text-brand-lines/70" placeholder="Enter your email" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-brand-lines mb-1">Message</label>
|
||||
<textarea required rows={5} className="w-full rounded-lg bg-brand-bgLight/40 border border-brand-lines/40 focus:outline-none focus:ring-2 focus:ring-brand-accent px-3 py-2 text-brand-text placeholder:text-brand-lines/70" placeholder="How can I help?" />
|
||||
</div>
|
||||
<button type="submit" className="px-4 py-2 rounded-lg font-semibold text-white bg-brandGradient shadow-glow">Send</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="glass p-6 max-w-lg mt-8">
|
||||
<p><strong>Email:</strong> <a href="mailto:brunovontor@gmail.com" className="hover:text-[var(--c-other)]">brunovontor@gmail.com</a></p>
|
||||
<p className="mt-2"><strong>Phone:</strong> <a href="tel:+420605512624" className="hover:text-[var(--c-other)]">+420 605 512 624</a></p>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +109,7 @@ export default function Downloader() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!url || probing}
|
||||
className="px-3 py-2 rounded bg-blue-600 text-white disabled:opacity-50"
|
||||
className="px-3 py-2 rounded bg-brand-accent text-brand-text disabled:opacity-50"
|
||||
>
|
||||
{probing ? "Probing..." : "Get info"}
|
||||
</button>
|
||||
@@ -117,7 +117,7 @@ export default function Downloader() {
|
||||
type="button"
|
||||
onClick={onDownload}
|
||||
disabled={!canDownload || downloading}
|
||||
className="px-3 py-2 rounded bg-emerald-600 text-white disabled:opacity-50"
|
||||
className="px-3 py-2 rounded bg-brand-accent text-brand-text disabled:opacity-50"
|
||||
>
|
||||
{downloading ? "Downloading..." : "Download"}
|
||||
</button>
|
||||
@@ -134,7 +134,7 @@ export default function Downloader() {
|
||||
className="w-40 h-24 object-cover rounded border"
|
||||
/>
|
||||
)}
|
||||
<div className="text-sm text-gray-800 space-y-1">
|
||||
<div className="text-sm text-brand-text/90 space-y-1">
|
||||
<div>
|
||||
<span className="font-medium">Title:</span> {info.title || "-"}
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
.introduction article header {}
|
||||
/* header rules intentionally left out; keep markup clean */
|
||||
|
||||
.introduction article:nth-child(1) {
|
||||
width: 100%;
|
||||
@@ -71,7 +71,9 @@
|
||||
list-style: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(255, 255, 255, 35%);
|
||||
/* use design palette for animated dots */
|
||||
background: var(--c-boxes);
|
||||
opacity: 0.35;
|
||||
animation: animate 4s linear infinite;
|
||||
bottom: -150px;
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ export default {
|
||||
fontFamily: {
|
||||
inter: ['Inter', 'ui-sans-serif', 'system-ui'],
|
||||
},
|
||||
backgroundImage: {
|
||||
brandGradient: 'linear-gradient(135deg, var(--c-boxes), var(--c-other))',
|
||||
brandGlass: 'linear-gradient(180deg, color-mix(in hsl, var(--c-background-light), transparent 30%), color-mix(in hsl, black, transparent 70%))'
|
||||
},
|
||||
colors: {
|
||||
brand: {
|
||||
bg: 'var(--c-background)',
|
||||
|
||||
Reference in New Issue
Block a user