Compare commits

..

4 Commits

Author SHA1 Message Date
38a94906d4 Improved texts and profile pic added 2026-06-03 23:15:59 +03:00
d62889f7b7 Refactoring file locations 2026-05-13 21:27:51 +03:00
e02eee4d30 Initial justfile 2026-05-13 21:10:49 +03:00
d2ede883d1 NavBar style fix 2026-05-13 21:10:41 +03:00
18 changed files with 167 additions and 119 deletions

11
justfile Normal file
View File

@@ -0,0 +1,11 @@
dev:
npm run dev
build:
npm run build
lint:
npm run lint
test:
echo "No test runner configured yet"

BIN
public/me.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View File

@@ -1,12 +1,12 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import { activeSectionState, themeState } from './state/atoms'; import { activeSectionState, themeState } from './state/atoms';
import Navbar from './components/Navbar/Navbar'; import Navbar from './components/Navbar';
import Hero from './components/Hero/Hero'; import Hero from './components/Hero';
import About from './components/About/About'; import About from './components/About';
import Projects from './components/Projects/Projects'; import Projects from './components/Projects';
import Contact from './components/Contact/Contact'; import Contact from './components/Contact';
import Footer from './components/Footer/Footer'; import Footer from './components/Footer';
import styles from './App.module.scss'; import styles from './App.module.scss';
const SECTIONS = { const SECTIONS = {

67
src/components/About.jsx Normal file
View File

@@ -0,0 +1,67 @@
import styles from '../styles/components/About.module.scss';
const STACK = ['Azure', '.NET', 'C#', 'JavaScript', 'React', 'Node.js', 'SQL'];
export default function About() {
return (
<section id="about" className={styles.about}>
<div className={styles.inner}>
<div className={styles.header}>
<span className={styles.sectionNum}>01.</span>
<h2 className={styles.sectionTitle}>About me</h2>
<div className={styles.line} />
</div>
<div className={styles.body}>
<div className={styles.text}>
<p>
I'm a curious software engineer with a passion for building scalable and efficient
applications. With deep knowledge in cloud, backend, and frontend development, I enjoy
working on projects that challenge me to learn new technologies and improve my skills.
</p>
<p>
I tend to build always something that is useful to others, and I find joy in creating tools
and applications that solve real-world problems. I believe that technology has the power to
make a positive impact on people's lives, and I strive to contribute to that impact through my work.
</p>
<p>
Here are some technologies I've been working with recently:
</p>
<ul className={styles.stack}>
{STACK.map((item) => (
<li key={item}>
<span className={styles.arrow}></span> {item}
</li>
))}
</ul>
</div>
<div className={styles.card}>
<div className={styles.avatar}>
<img src="/me.png" alt="Profile" className={styles.avatarImg} />
</div>
<div className={styles.meta}>
<p className={styles.metaLine}>
<span className={styles.metaKey}>location</span>
<span className={styles.metaValue}>Turku Archipelago, Finland</span>
</p>
<p className={styles.metaLine}>
<span className={styles.metaKey}>favorite book</span>
<span className={styles.metaValue}>The Lord of the Rings</span>
</p>
<div className={styles.metaLine}>
<span className={styles.metaKey}>favorite songs</span>
<div className={styles.metaLinks}>
<a href="https://www.youtube.com/watch?v=EqDcigWxZuU" target="_blank" rel="noreferrer">Rücksturz Agitation Free</a>
<a href="https://www.youtube.com/watch?v=2i2oJJwgLTk" target="_blank" rel="noreferrer">Year of Love Jenny Hval</a>
<a href="https://www.youtube.com/watch?v=C5lVJkp5TT4" target="_blank" rel="noreferrer">Пачка сигарет КИНО</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -1,62 +0,0 @@
import styles from './About.module.scss';
const STACK = ['Technology 1', 'Technology 2', 'Technology 3', 'Technology 4', 'Technology 5', 'Technology 6'];
export default function About() {
return (
<section id="about" className={styles.about}>
<div className={styles.inner}>
<div className={styles.header}>
<span className={styles.sectionNum}>01.</span>
<h2 className={styles.sectionTitle}>About me</h2>
<div className={styles.line} />
</div>
<div className={styles.body}>
<div className={styles.text}>
<p>
A paragraph about yourself and your background. What kind of work
do you do and what drives you? Keep it personal and authentic.
</p>
<p>
A second paragraph with more details hobbies, interests, or
anything else that gives visitors a sense of who you are beyond
your job title.
</p>
<p>
Here are some technologies I've been working with recently:
</p>
<ul className={styles.stack}>
{STACK.map((item) => (
<li key={item}>
<span className={styles.arrow}></span> {item}
</li>
))}
</ul>
</div>
<div className={styles.card}>
<div className={styles.avatar}>
<span className={styles.avatarInner}>YN</span>
</div>
<div className={styles.meta}>
<p className={styles.metaLine}>
<span className={styles.metaKey}>location</span>
<span>City, Country</span>
</p>
<p className={styles.metaLine}>
<span className={styles.metaKey}>status</span>
<span className={styles.green}>Available</span>
</p>
<p className={styles.metaLine}>
<span className={styles.metaKey}>focus</span>
<span>Your focus area</span>
</p>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -1,4 +1,4 @@
import styles from './Contact.module.scss'; import styles from '../styles/components/Contact.module.scss';
export default function Contact() { export default function Contact() {
return ( return (
@@ -12,12 +12,13 @@ export default function Contact() {
<div className={styles.body}> <div className={styles.body}>
<p className={styles.lede}> <p className={styles.lede}>
A short message inviting visitors to reach out. Let them know I'm currently employed, but my inbox is always open. Whether you have a question or
you're open to new opportunities, collaborations, or just a chat. just want to say hi, I'll try my best to get back to you!
</p> </p>
<p>I also have a small company if you are interested in collaboration or services.</p>
<a <a
href="mailto:your@email.com" href="mailto:veikko@lintujarvi.fi"
className={styles.emailBtn} className={styles.emailBtn}
> >
Say hello Say hello
@@ -25,9 +26,9 @@ export default function Contact() {
<ul className={styles.socials}> <ul className={styles.socials}>
{[ {[
{ label: 'GitHub', href: '#' }, { label: 'Gitea', href: 'https://gitea.tietokonepaja.fi/' },
{ label: 'LinkedIn', href: '#' }, { label: 'LinkedIn', href: 'https://www.linkedin.com/in/veikko-lintuj%C3%A4rvi-5888a6175/' },
{ label: 'Platform', href: '#' }, { label: 'Company', href: 'https://www.tietokonepaja.fi/' },
].map(({ label, href }) => ( ].map(({ label, href }) => (
<li key={label}> <li key={label}>
<a href={href} target="_blank" rel="noreferrer"> <a href={href} target="_blank" rel="noreferrer">

View File

@@ -1,11 +1,11 @@
import styles from './Footer.module.scss'; import styles from '../styles/components/Footer.module.scss';
export default function Footer() { export default function Footer() {
return ( return (
<footer className={styles.footer}> <footer className={styles.footer}>
<p> <p>
Designed &amp; built by{' '} Designed &amp; built by{' '}
<a href="#home">Your Name</a>{' '} <a href="#home">Veikko Lintujärvi</a>{' '}
<span className={styles.separator}>·</span>{' '} <span className={styles.separator}>·</span>{' '}
<span className={styles.stack}>React + Vite</span> <span className={styles.stack}>React + Vite</span>
</p> </p>

View File

@@ -1,4 +1,4 @@
import styles from './Hero.module.scss'; import styles from '../styles/components/Hero.module.scss';
export default function Hero() { export default function Hero() {
return ( return (
@@ -8,15 +8,15 @@ export default function Hero() {
<div className={styles.content}> <div className={styles.content}>
<p className={styles.greeting}>Hey, I'm</p> <p className={styles.greeting}>Hey, I'm</p>
<h1 className={styles.name}> <h1 className={styles.name}>
Your Name<span className={styles.dot}>.</span> Veikko Lintujärvi<span className={styles.dot}>.</span>
</h1> </h1>
<p className={styles.tagline}> <p className={styles.tagline}>
Your tagline goes here {' '} Making world a better place {' '}
<span className={styles.highlight}>make it memorable.</span> <span className={styles.highlight}>one line at a time.</span>
</p> </p>
<p className={styles.sub}> <p className={styles.sub}>
A short bio or description about yourself. What do you do, what do I'm a curious software engineer from Turku Archipelago, Finland. Right now
you care about, and what makes you interesting? I'm excited about cloud, Linux and AI.
</p> </p>
<div className={styles.cta}> <div className={styles.cta}>

View File

@@ -1,7 +1,7 @@
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { navOpenState, activeSectionState } from '../../state/atoms'; import { navOpenState, activeSectionState } from '../state/atoms';
import ThemeToggle from '../ThemeToggle/ThemeToggle'; import ThemeToggle from './ThemeToggle';
import styles from './Navbar.module.scss'; import styles from '../styles/components/Navbar.module.scss';
const NAV_LINKS = [ const NAV_LINKS = [
{ label: 'Home', section: 'home' }, { label: 'Home', section: 'home' },
@@ -41,6 +41,7 @@ export default function Navbar() {
))} ))}
</ul> </ul>
<div className={styles.navActions}>
<ThemeToggle /> <ThemeToggle />
<button <button
@@ -53,6 +54,7 @@ export default function Navbar() {
<span /> <span />
<span /> <span />
</button> </button>
</div>
</nav> </nav>
</header> </header>
); );

View File

@@ -1,4 +1,4 @@
import styles from './Projects.module.scss'; import styles from '../styles/components/Projects.module.scss';
const PROJECTS = [ const PROJECTS = [
{ {

View File

@@ -1,6 +1,6 @@
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { themeState } from '../../state/atoms'; import { themeState } from '../state/atoms';
import styles from './ThemeToggle.module.scss'; import styles from '../styles/components/ThemeToggle.module.scss';
export default function ThemeToggle() { export default function ThemeToggle() {
const [theme, setTheme] = useAtom(themeState); const [theme, setTheme] = useAtom(themeState);

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.about { .about {
padding: $space-24 $space-6; padding: $space-24 $space-6;
@@ -87,18 +87,15 @@
width: 100px; width: 100px;
height: 100px; height: 100px;
border-radius: 50%; border-radius: 50%;
background: linear-gradient(135deg, $color-primary 0%, $color-primary-mid 100%); overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 30px rgb(var(--color-primary-mid) / 0.3); box-shadow: 0 0 30px rgb(var(--color-primary-mid) / 0.3);
} }
.avatarInner { .avatarImg {
font-size: $text-xl; width: 100%;
font-weight: 700; height: 100%;
color: #fff; object-fit: cover;
letter-spacing: 0.05em; display: block;
} }
.meta { .meta {
@@ -110,7 +107,7 @@
.metaLine { .metaLine {
display: flex; display: flex;
justify-content: space-between; align-items: flex-start;
font-size: $text-sm; font-size: $text-sm;
color: $color-text-muted; color: $color-text-muted;
border-bottom: 1px solid $color-border; border-bottom: 1px solid $color-border;
@@ -125,8 +122,27 @@
font-family: $font-mono; font-family: $font-mono;
color: $color-text-dim; color: $color-text-dim;
font-size: $text-xs; font-size: $text-xs;
flex-shrink: 0;
width: 7.5rem;
} }
.green { .metaValue {
color: #4ade80; text-align: left;
}
.metaLinks {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: $space-2;
a {
color: $color-accent;
text-decoration: none;
font-size: $text-xs;
&:hover {
text-decoration: underline;
}
}
} }

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.contact { .contact {
padding: $space-24 $space-6 $space-16; padding: $space-24 $space-6 $space-16;

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.footer { .footer {
border-top: 1px solid $color-border; border-top: 1px solid $color-border;

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.hero { .hero {
position: relative; position: relative;

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.header { .header {
position: fixed; position: fixed;
@@ -88,6 +88,12 @@
} }
// Burger // Burger
.navActions {
display: flex;
align-items: center;
gap: $space-1;
}
.burger { .burger {
display: none; display: none;
flex-direction: column; flex-direction: column;
@@ -129,6 +135,13 @@
gap: $space-4; gap: $space-4;
transform: translateY(-110%); transform: translateY(-110%);
transition: transform $transition-base; transition: transform $transition-base;
z-index: 99;
button {
width: 100%;
text-align: left;
}
transition: transform $transition-base;
&.open { &.open {
transform: translateY(0); transform: translateY(0);

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.projects { .projects {
padding: $space-24 $space-6; padding: $space-24 $space-6;

View File

@@ -1,4 +1,4 @@
@use '../../styles/variables' as *; @use '../variables' as *;
.toggle { .toggle {
background: none; background: none;