fixed a LOT of repetition
This commit is contained in:
61
src/components/Box.astro
Normal file
61
src/components/Box.astro
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
interface Props {
|
||||
accent?: string;
|
||||
isTitle?: boolean
|
||||
}
|
||||
|
||||
const { accent, isTitle } = Astro.props as Props;
|
||||
|
||||
let opachity = 0.05;
|
||||
if (isTitle) {
|
||||
opachity = 0.2;
|
||||
}
|
||||
---
|
||||
|
||||
<div class="container">
|
||||
{accent && <div class="accent" style={`background-color: ${accent}; width:4px; border-radius: 999px; flex-shrink: 0;`}></div>}
|
||||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style define:vars={{color: `rgba(255,255,255,${opachity})`}}>
|
||||
.container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
min-height: 120px;
|
||||
padding: 1rem;
|
||||
background: var(--color);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.18);
|
||||
color: white;
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.24);
|
||||
border-color: rgba(255,255,255,0.14);
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
min-height: 100px;
|
||||
padding: 0.85rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,78 +1,76 @@
|
||||
---
|
||||
const { title, description } = Astro.props;
|
||||
import Box from "../Box.astro";
|
||||
---
|
||||
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<form method="POST" action="https://example.com/example">
|
||||
<input type="text" name="name" id="nameInput" class="name" placeholder="John Doe" autocomplete="name">
|
||||
<input type="email" name="email" id="emailInput" class="email" placeholder="john@example.com" autocomplete="email">
|
||||
<textarea name="message" id="messageInput" placeholder="Your message here"></textarea>
|
||||
<input type="submit" value="Indienen" class="submitBtn">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<Box>
|
||||
<form method="POST" action="https://example.com/example">
|
||||
<input type="text" name="name" id="nameInput" class="name" placeholder="John Doe" autocomplete="name">
|
||||
<input type="email" name="email" id="emailInput" class="email" placeholder="john@example.com" autocomplete="email">
|
||||
<textarea name="message" id="messageInput" placeholder="Your message here"></textarea>
|
||||
<input type="submit" value="Indienen" class="submitBtn">
|
||||
</form>
|
||||
</Box>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
min-height: 120px
|
||||
padding: 1rem 1rem 1rem 0.9rem;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.18);
|
||||
color: white;
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
|
||||
margin-top: 0.5rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.24);
|
||||
border-color: rgba(255,255,255,0.14);
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
border-radius: 10pt;
|
||||
padding:10px;
|
||||
font-size: .8rem;
|
||||
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: rgba(18, 18, 28, 0.24);
|
||||
backdrop-filter: blur(2px);
|
||||
box-shadow: 0 24px 50px rgba(0, 0, 0, 0.18);
|
||||
transition: all 200ms ease;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
font-size: 0.75rem;
|
||||
padding: 0.8rem 1rem;
|
||||
}
|
||||
|
||||
transition: transform var(--transition-time), border-color var(--transition-time), background var(--transition-time), box-shadow var(--transition-time);
|
||||
padding: 0.95rem 1.2rem;
|
||||
input::placeholder, textarea::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
input:focus, textarea:focus {
|
||||
outline: none;
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
background: rgba(18, 18, 28, 0.4);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 3px rgba(255, 255, 255, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
input:hover, textarea:hover {
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
background: rgba(18, 18, 28, 0.35);
|
||||
}
|
||||
|
||||
.submitBtn {
|
||||
background: linear-gradient(135deg, rgba(140, 90, 20, 0.4), rgba(96, 67, 8, 0.3));
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: unset !important;
|
||||
background: rgba(96, 67, 8, 0.24);
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.submitBtn:hover {
|
||||
background: linear-gradient(135deg, rgba(160, 110, 30, 0.5), rgba(116, 87, 18, 0.4));
|
||||
border-color: rgba(255, 255, 255, 0.25);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.submitBtn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
gap: .5rem;
|
||||
width: 50%;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
form input {
|
||||
@@ -87,15 +85,14 @@ const { title, description } = Astro.props;
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
min-height: 100px;
|
||||
padding: 0.85rem 0.85rem 0.85rem 0.75rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.8rem 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
14
src/components/Contact/ContactImage.astro
Normal file
14
src/components/Contact/ContactImage.astro
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
import Box from "../Box.astro";
|
||||
---
|
||||
|
||||
<Box>
|
||||
<div class="image"></div>
|
||||
</Box>
|
||||
<style>
|
||||
.image {
|
||||
width: 40vw;
|
||||
height: 400px;
|
||||
background: white;
|
||||
}
|
||||
</style>
|
||||
@@ -1,48 +1,43 @@
|
||||
---
|
||||
import TitleCard from '../TitleCard.astro';
|
||||
import ContactForm from './ContactForm.astro';
|
||||
import ContactImage from './ContactImage.astro';
|
||||
import Section from '../Section.astro';
|
||||
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<section class="contact-section" aria-label="Contact">
|
||||
<Section className="contact-section" label="Contact">
|
||||
<TitleCard title="Contact" description="Neem gerust contact met me op!"/>
|
||||
<ContactForm/>
|
||||
</section>
|
||||
</div>
|
||||
<div class="formContaner">
|
||||
<ContactForm />
|
||||
<div class="imgContainer">
|
||||
<ContactImage />
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<style>
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02)),
|
||||
rgb(74, 74, 74);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
|
||||
.formContaner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
align-items: start;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 1rem;
|
||||
}
|
||||
|
||||
.contact-section {
|
||||
min-width: 0;
|
||||
.image {
|
||||
width: 40vw;
|
||||
height: 400px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
|
||||
/* Mobile: collapse to one column,
|
||||
so "Kennis" ends up fully under contact */
|
||||
@media (max-width: 768px) {
|
||||
#container {
|
||||
margin: 5px;
|
||||
padding: 1rem;
|
||||
.imgContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.formContaner {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,69 +1,35 @@
|
||||
---
|
||||
const { experience } = Astro.props;
|
||||
|
||||
import Box from "../Box.astro";
|
||||
const color: string = experience.color
|
||||
---
|
||||
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="accent"></div>
|
||||
<Box accent={color}>
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h3 class="main-title">{experience.name}</h3>
|
||||
<p class="sub-title">{experience.role}</p>
|
||||
|
||||
<div class="content">
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h3 class="main-title">{experience.name}</h3>
|
||||
<p class="sub-title">{experience.role}</p>
|
||||
<p class="description">
|
||||
{experience.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="description">
|
||||
{experience.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="dateContainer">
|
||||
<p>
|
||||
{experience.start.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })}
|
||||
-
|
||||
{experience.end
|
||||
? experience.end.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
|
||||
: 'Nu'}
|
||||
</p>
|
||||
</div>
|
||||
<div class="dateContainer">
|
||||
<p>
|
||||
{experience.start.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })}
|
||||
-
|
||||
{experience.end
|
||||
? experience.end.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
|
||||
: 'Nu'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<style define:vars={{color}}>
|
||||
.container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
min-height: 120px;
|
||||
padding: 1rem 1rem 1rem 0.9rem;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.18);
|
||||
color: white;
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.24);
|
||||
border-color: rgba(255,255,255,0.14);
|
||||
}
|
||||
|
||||
.accent {
|
||||
width: 4px;
|
||||
border-radius: 999px;
|
||||
background: var(--color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -109,12 +75,6 @@ const color: string = experience.color
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
min-height: 100px;
|
||||
padding: 0.85rem 0.85rem 0.85rem 0.75rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.titleRow {
|
||||
flex-direction: column;
|
||||
gap: 0.55rem;
|
||||
|
||||
@@ -2,44 +2,20 @@
|
||||
import { siteData } from '../../data/site';
|
||||
import ExperienceBox from './ExperienceBox.astro';
|
||||
import TitleCard from '../TitleCard.astro';
|
||||
|
||||
import Section from '../Section.astro';
|
||||
const experience = [...siteData.experience];
|
||||
const sortedExperience = experience.sort((a, b) => b.start.getTime() - a.start.getTime());
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<section class="experience-section" aria-label="Experience">
|
||||
<div class="experience-list">
|
||||
<TitleCard title="Ervaringen" description="Hieronder zie je alle werkervaring die ik tot nu toe hebv opgedaan. "/>
|
||||
{sortedExperience.map((experience) => (
|
||||
<ExperienceBox experience={experience} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<Section className="experience-section" label="Ervaring">
|
||||
<div class="experience-list">
|
||||
<TitleCard title="Ervaringen" description="Hieronder zie je alle werkervaring die ik tot nu toe hebv opgedaan. "/>
|
||||
{sortedExperience.map((experience) => (
|
||||
<ExperienceBox experience={experience} />
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<style>
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02)),
|
||||
rgb(74, 74, 74);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.experience-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.experience-list {
|
||||
display: flex;
|
||||
@@ -51,13 +27,6 @@ const sortedExperience = experience.sort((a, b) => b.start.getTime() - a.start.g
|
||||
/* Mobile: collapse to one column,
|
||||
so "Kennis" ends up fully under experience */
|
||||
@media (max-width: 768px) {
|
||||
#container {
|
||||
margin: 5px;
|
||||
padding: 1rem;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.experience-section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,32 @@
|
||||
---
|
||||
import { siteData } from '../../data/site';
|
||||
import {age} from "../../utils/getAge"
|
||||
import {study} from "../../utils/getCurrentStudy"
|
||||
|
||||
import hero_img from "../../assets/hero.png"
|
||||
|
||||
import Button from "../Button.astro"
|
||||
import EmailButton from "./EmailButton.astro"
|
||||
import Section from '../Section.astro';
|
||||
|
||||
const hero_img_src = `url(${hero_img.src})`;
|
||||
|
||||
const socials = [...siteData.socials];
|
||||
const occupation = siteData.occupation;
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<Section className="hero-section" label="Hero" isHero={true}>
|
||||
<div class="titleContainer">
|
||||
<h1 class="main-title">Valentijn van der Jagt</h1>
|
||||
<h3 class="sub-title">{age} Jaar - {study?.label}</h3>
|
||||
<h3 class="sub-title">{age} Jaar - {occupation}</h3>
|
||||
<h3></h3>
|
||||
</div>
|
||||
|
||||
<div class="buttonContainer">
|
||||
<Button icon="mdi:git" label="Gitea" href="https://git.herpiederpiee.nl/valentijn?tab=repositories"/>
|
||||
<Button icon="mdi:linkedin" label="LinkedIn" href="https://nl.linkedin.com/in/valentijn-van-der-jagt"/>
|
||||
{socials.map((link) => (
|
||||
<Button icon={link.icon} label={link.platform} href={link.url} />
|
||||
))}
|
||||
<EmailButton icon="mdi:email-outline" label="E-mail" />
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<style define:vars={{hero_img_src}}>
|
||||
|
||||
|
||||
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
min-height: clamp(420px, 58vh, 680px);
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
background: radial-gradient(circle at 15% 18%, rgba(255, 246, 228, 0.32), transparent 24%),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(10, 10, 10, 0.24)),
|
||||
var(--hero_img_src);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
animation: driftBackground 16s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
<style>
|
||||
.buttonContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -105,10 +82,6 @@ const hero_img_src = `url(${hero_img.src})`;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
#container {
|
||||
padding: 1.5rem 1.2rem;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -122,10 +95,6 @@ const hero_img_src = `url(${hero_img.src})`;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
#container {
|
||||
min-height: 360px;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
justify-content: center;
|
||||
gap: 0.8rem;
|
||||
|
||||
@@ -2,44 +2,22 @@
|
||||
import { siteData } from '../../data/site';
|
||||
import ProjectBox from './ProjectBox.astro';
|
||||
import TitleCard from '../TitleCard.astro';
|
||||
import Section from '../Section.astro';
|
||||
|
||||
const projects = [...siteData.projects];
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<section class="projects-section" aria-label="Projects">
|
||||
<div class="projects-list">
|
||||
<TitleCard title="Projecten" description="Hieronder zie je een aantal van mijn favoriete persoonlijke projecten!"/>
|
||||
{projects.map((project) => (
|
||||
<ProjectBox project={project} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<Section className="projects-section" label="Projecten">
|
||||
<div class="projects-list">
|
||||
<TitleCard title="Projecten" description="Hieronder zie je een aantal van mijn favoriete persoonlijke projecten!"/>
|
||||
{projects.map((project) => (
|
||||
<ProjectBox project={project} />
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
|
||||
<style>
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02)),
|
||||
rgb(74, 74, 74);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.projects-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.projects-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -50,13 +28,6 @@ const projects = [...siteData.projects];
|
||||
/* Mobile: collapse to one column,
|
||||
so "Kennis" ends up fully under studies */
|
||||
@media (max-width: 768px) {
|
||||
#container {
|
||||
margin: 5px;
|
||||
padding: 1rem;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.projects-section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
@@ -6,63 +6,31 @@ import {techColors} from "../../data/site"
|
||||
const colors: { [id: string] : string; } = {...techColors}
|
||||
|
||||
import Button from "../Button.astro";
|
||||
import Box from "../Box.astro";
|
||||
---
|
||||
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
|
||||
<h3 class="main-title">{project.title}</h3>
|
||||
<p class="sub-title">{project.description}</p>
|
||||
<div class="tech-stack">
|
||||
{project.tech.map((item: string) => {
|
||||
const color = colors[item] || colors["Default"];
|
||||
return (
|
||||
<span class="tech-badge" style={`--brand-color: ${color}`}>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Box>
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
|
||||
<h3 class="main-title">{project.title}</h3>
|
||||
<p class="sub-title">{project.description}</p>
|
||||
<div class="tech-stack">
|
||||
{project.tech.map((item: string) => {
|
||||
const color = colors[item] || colors["Default"];
|
||||
return (
|
||||
<span class="tech-badge" style={`--brand-color: ${color}`}>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Button label="Bekijk Project" href={project.link} icon="mdi:link"/>
|
||||
</div>
|
||||
<Button label="Bekijk Project" href={project.link} icon="mdi:link"/>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<style>
|
||||
/* ... Existing Styles Stay Exactly the Same ... */
|
||||
.container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
min-height: 120px;
|
||||
padding: 1rem 1rem 1rem 0.9rem;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.18);
|
||||
color: white;
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
|
||||
margin-top:0.5rem;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.24);
|
||||
border-color: rgba(255,255,255,0.14);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.titleRow {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@@ -113,12 +81,6 @@ import Button from "../Button.astro";
|
||||
|
||||
/* Keep your existing media queries */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
min-height: 100px;
|
||||
padding: 0.85rem 0.85rem 0.85rem 0.75rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.titleRow {
|
||||
flex-direction: column;
|
||||
gap: 0.55rem;
|
||||
|
||||
74
src/components/Section.astro
Normal file
74
src/components/Section.astro
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
|
||||
interface Props {
|
||||
className: string;
|
||||
label: string;
|
||||
isHero?: boolean;
|
||||
}
|
||||
|
||||
const { className, label, isHero } = Astro.props;
|
||||
import hero_img from '../assets/hero.png';
|
||||
|
||||
|
||||
let containerBackground;
|
||||
if (isHero) {
|
||||
containerBackground = `radial-gradient(circle at 15% 18%, rgba(255, 246, 228, 0.32), transparent 24%),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(10, 10, 10, 0.24)),
|
||||
url("${hero_img.src}")`;
|
||||
} else {
|
||||
containerBackground = `linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02)),
|
||||
rgb(74, 74, 74)`;
|
||||
}
|
||||
|
||||
---
|
||||
<div id="container">
|
||||
<section class={className} aria-label={label}>
|
||||
<slot/>
|
||||
</section>
|
||||
</div>
|
||||
<style define:vars={{containerBackground}}>
|
||||
|
||||
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
|
||||
|
||||
background: var(--containerBackground);
|
||||
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
animation: driftBackground 10s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
/* Mobile: collapse to one column,
|
||||
so "Kennis" ends up fully under studies */
|
||||
@media (max-width: 768px) {
|
||||
#container {
|
||||
margin: 5px;
|
||||
padding: 1rem;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes driftBackground {
|
||||
0% { background-position: center top; }
|
||||
100% { background-position: 12% 62%; }
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -2,45 +2,22 @@
|
||||
import { siteData } from '../../data/site';
|
||||
import StudyBox from './StudyBox.astro';
|
||||
import TitleCard from '../TitleCard.astro';
|
||||
import Section from '../Section.astro';
|
||||
|
||||
const studies = [...siteData.studies];
|
||||
const sortedStudies = studies.sort((a, b) => b.start.getTime() - a.start.getTime());
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<section class="studies-section" aria-label="Studies">
|
||||
<div class="studies-list">
|
||||
<TitleCard title="Opleidingen" description="Hieronder zie je alle opleidingen die ik heb gevolgd tot nu toe. "/>
|
||||
{sortedStudies.map((study) => (
|
||||
<StudyBox study={study} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<Section className="studies-section" label="Studies">
|
||||
<div class="studies-list">
|
||||
<TitleCard title="Opleidingen" description="Hieronder zie je alle opleidingen die ik heb gevolgd tot nu toe. "/>
|
||||
{sortedStudies.map((study) => (
|
||||
<StudyBox study={study} />
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<style>
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02)),
|
||||
rgb(74, 74, 74);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 24px 60px rgba(16, 14, 12, 0.18);
|
||||
overflow: hidden;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.studies-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.studies-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -48,18 +25,5 @@ const sortedStudies = studies.sort((a, b) => b.start.getTime() - a.start.getTime
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Mobile: collapse to one column,
|
||||
so "Kennis" ends up fully under studies */
|
||||
@media (max-width: 768px) {
|
||||
#container {
|
||||
margin: 5px;
|
||||
padding: 1rem;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.studies-section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,33 +1,29 @@
|
||||
---
|
||||
const { study } = Astro.props;
|
||||
|
||||
import Box from "../Box.astro";
|
||||
const color: string = study.color
|
||||
---
|
||||
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="accent" aria-hidden="true"></div>
|
||||
<Box accent={color}>
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h3 class="main-title">{study.study}</h3>
|
||||
<p class="sub-title">{study.school} · {study.level}</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h3 class="main-title">{study.study}</h3>
|
||||
<p class="sub-title">{study.school} · {study.level}</p>
|
||||
</div>
|
||||
|
||||
<div class="dateContainer">
|
||||
<p>
|
||||
{study.start.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })}
|
||||
-
|
||||
{study.end
|
||||
? study.end.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
|
||||
: 'Nu'}
|
||||
</p>
|
||||
</div>
|
||||
<div class="dateContainer">
|
||||
<p>
|
||||
{study.start.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })}
|
||||
-
|
||||
{study.end
|
||||
? study.end.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
|
||||
: 'Nu'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<style define:vars={{color}}>
|
||||
.container {
|
||||
|
||||
@@ -1,49 +1,17 @@
|
||||
---
|
||||
const { title, description } = Astro.props;
|
||||
import Box from "./Box.astro";
|
||||
---
|
||||
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h2 class="main-title">{title}</h2>
|
||||
<p class="sub-title">{description}</p>
|
||||
</div>
|
||||
<Box isTitle={true}>
|
||||
<div class="titleRow">
|
||||
<div class="titleContainer">
|
||||
<h2 class="main-title">{title}</h2>
|
||||
<p class="sub-title">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 1rem;
|
||||
min-height: 80px;
|
||||
padding: 1rem 1rem 1rem 0.9rem;
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.18);
|
||||
color: white;
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.24);
|
||||
border-color: rgba(255,255,255,0.14);
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.titleRow {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@@ -72,12 +40,6 @@ const { title, description } = Astro.props;
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
min-height: 100px;
|
||||
padding: 0.85rem 0.85rem 0.85rem 0.75rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.titleRow {
|
||||
flex-direction: column;
|
||||
gap: 0.55rem;
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
export const siteData = {
|
||||
/*
|
||||
Personal Information
|
||||
*/
|
||||
name: "Valentijn van der Jagt",
|
||||
email: "valentijnkijkuit@outlook.com",
|
||||
about: "Softwareontwikkelaar met passie voor praktische oplossingen. Ervaring met Java, Python, IoT en moderne webtechnologieën. Momenteel student Technische Informatica aan Hogeschool Rotterdam.",
|
||||
occupation: "Student Technische Informatica",
|
||||
birthDate: new Date("2006-06-27"),
|
||||
|
||||
experience: [
|
||||
{
|
||||
name: "Brightpark",
|
||||
role: "Stagaire Junior Developer",
|
||||
description: "Bij Brightpark heb ik mijn eerste ervaring opgedaan in het werkveld van Software Ontwikkeling. Ik heb hier gewerkt aan meerdere projecten. Een van de leukere was een iOS app die helpt bij het meten van huizen door gebruik te maken van de Bosch GLM- series meetapperatuur. Deze app heb ik gemaakt in Flutter, met wat kleine stappen Swift in om de meetapperatuur werkend te krijgen.",
|
||||
start: new Date("2024-09-10"),
|
||||
end: new Date("2025-05-1"),
|
||||
tech: ["Flutter", "Swift", "Svelte", "Laravel"],
|
||||
color: "#30e7ffe9"
|
||||
}
|
||||
],
|
||||
|
||||
/*
|
||||
Online Presence
|
||||
*/
|
||||
socials: [
|
||||
{ icon: "mdi:git", platform: "Gitea", url: "https://git.herpiederpiee.nl/valentijn?tab=repositories" },
|
||||
{ icon: "mdi:linkedin", platform: "LinkedIn", url: "https://nl.linkedin.com/in/valentijn-van-der-jagt" },
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
title: "Albert Heijn Bonus Scraper",
|
||||
@@ -10,12 +35,16 @@ export const siteData = {
|
||||
link: "https://git.herpiederpiee.nl/valentijn/Appie-Bonus-Scraper/"
|
||||
},
|
||||
{
|
||||
title: "Spotify Windows Intergratie ",
|
||||
title: "Spotify Windows Integratie ",
|
||||
description: "Een Python-applicatie die via de Spotify Web API real-time playback-data synchroniseert met een custom Windows Taskbar-widget. Maakt gebruik van Tkinter voor een hardware-versnelde, transparante overlay die naadloos integreert met de Windows Shell-omgeving",
|
||||
tech: ["Python", "Tkinter", "Spotify API"],
|
||||
link: "https://git.herpiederpiee.nl/valentijn/Windows-Spotify-Taskbar/"
|
||||
},
|
||||
],
|
||||
|
||||
/*
|
||||
Academic Path
|
||||
*/
|
||||
studies: [
|
||||
{
|
||||
school: "Hogeschool Rotterdam",
|
||||
@@ -35,17 +64,6 @@ export const siteData = {
|
||||
end: new Date("2025-06-18"),
|
||||
color: "#8FE508"
|
||||
}
|
||||
],
|
||||
experience: [
|
||||
{
|
||||
name: "Brightpark",
|
||||
role: "Stagaire Junior Developer",
|
||||
description: "Bij Brightpark heb ik mijn eerste ervaring opgedaan in het werkveld van Software Ontwikkeling. Ik heb hier gewerkt aan meerdere projecten. Een van de leukere was een iOS app die helpt bij het meten van huizen door gebruik te maken van de Bosch GLM- series meetapperatuur. Deze app heb ik gemaakt in Flutter, met wat kleine stappen Swift in om de meetapperatuur werkend te krijgen.",
|
||||
start: new Date("2024-09-10"),
|
||||
end: new Date("2025-05-1"),
|
||||
tech: ["Flutter", "Swift", "Svelte", "Laravel"],
|
||||
color: "#30e7ffe9"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { siteData } from '../data/site';
|
||||
|
||||
type Study = {
|
||||
school: string;
|
||||
study: string;
|
||||
label: string;
|
||||
start: Date;
|
||||
end: Date | null;
|
||||
};
|
||||
|
||||
|
||||
function getStudy(studies: Study[]){
|
||||
if (studies.length === 0) return null;
|
||||
|
||||
return studies.reduce((latest, study) => {
|
||||
if (latest.end === null) return latest;
|
||||
if (study.end === null) return study;
|
||||
|
||||
return study.start.getTime() > latest.start.getTime() ? study : latest;
|
||||
});
|
||||
}
|
||||
|
||||
export const study = getStudy(siteData.studies)
|
||||
Reference in New Issue
Block a user