Compare commits

..

7 Commits

Author SHA1 Message Date
Joakim Repomaa
83f0783a43 fix hover effect for footer links
All checks were successful
Build and Deploy / build (push) Successful in 1m44s
2026-02-20 10:47:18 +02:00
Joakim Repomaa
1970350916 improve contrast of muted text in light mode
Some checks failed
Build and Deploy / build (push) Has been cancelled
2026-02-20 10:45:09 +02:00
Joakim Repomaa
e2c7b86cf0 update gitea url
All checks were successful
Build and Deploy / build (push) Successful in 1m42s
2026-02-19 22:41:41 +02:00
Joakim Repomaa
66dd269601 update meta
All checks were successful
Build and Deploy / build (push) Successful in 1m44s
2026-02-19 22:34:01 +02:00
Joakim Repomaa
45b7903b59 update favicon
All checks were successful
Build and Deploy / build (push) Successful in 1m42s
2026-02-19 22:29:53 +02:00
Joakim Repomaa
f604e50172 fix pdf layout
All checks were successful
Build and Deploy / build (push) Successful in 1m43s
2026-02-19 22:21:44 +02:00
Joakim Repomaa
96171576c7 cleanup
Some checks failed
Build and Deploy / build (push) Failing after 19s
2026-02-19 22:10:44 +02:00
18 changed files with 61 additions and 36 deletions

View File

@@ -35,7 +35,7 @@ body {
/* Web layout - 5 colors using light-dark() for dark mode */ /* Web layout - 5 colors using light-dark() for dark mode */
--color-bg: light-dark(#fafafa, #0c0c0e); --color-bg: light-dark(#fafafa, #0c0c0e);
--color-fg: light-dark(#18181b, #fafafa); --color-fg: light-dark(#18181b, #fafafa);
--color-muted: light-dark(#71717a, #a1a1aa); --color-muted: light-dark(#56565d, #a1a1aa);
--color-accent: light-dark(#0e7490, #22d3ee); --color-accent: light-dark(#0e7490, #22d3ee);
--color-hot: light-dark(#c2410c, #fb923c); --color-hot: light-dark(#c2410c, #fb923c);

View File

@@ -2,9 +2,12 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" type="image/png" sizes="32x32" href="%sveltekit.assets%/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="%sveltekit.assets%/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="%sveltekit.assets%/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="192x192" href="%sveltekit.assets%/icon-192x192.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Professional CV - Developer Portfolio" /> <meta name="description" content="Developer Portfolio" />
<meta name="theme-color" content="#0891b2" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="#0891b2" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#22d3ee" media="(prefers-color-scheme: dark)" /> <meta name="theme-color" content="#22d3ee" media="(prefers-color-scheme: dark)" />
%sveltekit.head% %sveltekit.head%

View File

@@ -0,0 +1,9 @@
<script lang="ts">
interface Props {
label: string;
}
let { label }: Props = $props();
</script>
<span class="text-accent before:content-['['] after:content-[']']">{label}</span>

View File

@@ -3,7 +3,11 @@
import Section from './Section.svelte'; import Section from './Section.svelte';
import TimelineItem from './TimelineItem.svelte'; import TimelineItem from './TimelineItem.svelte';
let { education }: { education: Education[] } = $props(); interface Props {
education: Education[];
}
let { education }: Props = $props();
</script> </script>
<Section title="Education"> <Section title="Education">

View File

@@ -3,7 +3,11 @@
import Section from './Section.svelte'; import Section from './Section.svelte';
import TimelineItem from './TimelineItem.svelte'; import TimelineItem from './TimelineItem.svelte';
let { experience }: { experience: Experience[] } = $props(); interface Props {
experience: Experience[];
}
let { experience }: Props = $props();
</script> </script>
<Section title="Experience"> <Section title="Experience">

View File

@@ -8,14 +8,14 @@
href="https://svelte.dev" href="https://svelte.dev"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="text-accent hover:text-accent transition-colors">SvelteKit</a class="text-accent hover:text-accent/80 transition-colors">SvelteKit</a
> >
+ +
<a <a
href="https://sveltiacms.app/" href="https://sveltiacms.app/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="text-accent hover:text-accent transition-colors">Sveltia CMS</a class="text-accent hover:text-accent/80 transition-colors">Sveltia CMS</a
> >
</p> </p>
<p class="mt-2"> <p class="mt-2">

View File

@@ -1,8 +1,13 @@
<script lang="ts"> <script lang="ts">
import type { Profile } from '$lib/types.js'; import type { Profile } from '$lib/types.js';
import BracketLabel from './BracketLabel.svelte';
import EncodedEmail from './EncodedEmail.svelte'; import EncodedEmail from './EncodedEmail.svelte';
let { profile }: { profile: Profile } = $props(); interface Props {
profile: Profile;
}
let { profile }: Props = $props();
</script> </script>
<header class="border-b-2 border-fg/10 pb-8 mb-8"> <header class="border-b-2 border-fg/10 pb-8 mb-8">
@@ -28,12 +33,12 @@
<div class="flex flex-col gap-2 text-sm"> <div class="flex flex-col gap-2 text-sm">
<div class="flex items-center gap-2 text-muted hover:text-accent transition-colors"> <div class="flex items-center gap-2 text-muted hover:text-accent transition-colors">
<span class="text-accent">[E]</span> <BracketLabel label="E" />
<EncodedEmail email={profile.email} class="hover:text-accent transition-colors" /> <EncodedEmail email={profile.email} class="hover:text-accent transition-colors" />
</div> </div>
<div class="flex items-center gap-2 text-muted"> <div class="flex items-center gap-2 text-muted">
<span class="text-accent">[L]</span> <BracketLabel label="L" />
{profile.location} {profile.location}
</div> </div>
@@ -43,7 +48,7 @@
rel="noopener noreferrer" rel="noopener noreferrer"
class="flex items-center gap-2 text-muted hover:text-accent transition-colors" class="flex items-center gap-2 text-muted hover:text-accent transition-colors"
> >
<span class="text-accent">[G]</span> <BracketLabel label="G" />
github.com/{profile.github} github.com/{profile.github}
</a> </a>
@@ -54,7 +59,7 @@
rel="noopener noreferrer" rel="noopener noreferrer"
class="flex items-center gap-2 text-muted hover:text-accent transition-colors" class="flex items-center gap-2 text-muted hover:text-accent transition-colors"
> >
<span class="text-accent">[W]</span> <BracketLabel label="W" />
{profile.website.replace(/^https?:\/\//, '')} {profile.website.replace(/^https?:\/\//, '')}
</a> </a>
{/if} {/if}

View File

@@ -6,26 +6,19 @@
import PDFTimelineItem from './PDFTimelineItem.svelte'; import PDFTimelineItem from './PDFTimelineItem.svelte';
import { MailIcon, MapPinIcon, GithubIcon, GlobeIcon } from 'svelte-feather-icons'; import { MailIcon, MapPinIcon, GithubIcon, GlobeIcon } from 'svelte-feather-icons';
let { interface Props {
profile,
experience,
education,
skills,
ownProjects,
contributions,
}: {
profile: Profile; profile: Profile;
experience: Experience[]; experience: Experience[];
education: Education[]; education: Education[];
skills: Skill[]; skills: Skill[];
ownProjects: Project[]; ownProjects: Project[];
contributions: Project[]; contributions: Project[];
} = $props(); }
let { profile, experience, education, skills, ownProjects, contributions }: Props = $props();
</script> </script>
<div <div class="font-sans max-w-[210mm] mx-auto bg-pdf-bg text-pdf-fg leading-relaxed text-sm">
class="font-sans max-w-[210mm] mx-auto px-[20mm] py-[18mm] bg-pdf-bg text-pdf-fg leading-relaxed text-sm"
>
<!-- Header --> <!-- Header -->
<header class="mb-6 pb-4 border-b-2 border-pdf-fg"> <header class="mb-6 pb-4 border-b-2 border-pdf-fg">
<div class="flex items-start justify-between gap-4"> <div class="flex items-start justify-between gap-4">

View File

@@ -3,11 +3,13 @@
import ProjectList from './ProjectList.svelte'; import ProjectList from './ProjectList.svelte';
import Section from './Section.svelte'; import Section from './Section.svelte';
let { interface Props {
ownProjects, ownProjects: Project[];
contributions, contributions: Project[];
username, username: string;
}: { ownProjects: Project[]; contributions: Project[]; username: string } = $props(); }
let { ownProjects, contributions, username }: Props = $props();
</script> </script>
<Section title="Projects"> <Section title="Projects">

View File

@@ -3,7 +3,11 @@
import Section from './Section.svelte'; import Section from './Section.svelte';
import Tags from './Tags.svelte'; import Tags from './Tags.svelte';
let { skills }: { skills: Skill[] } = $props(); interface Props {
skills: Skill[];
}
let { skills }: Props = $props();
</script> </script>
<Section title="Skills"> <Section title="Skills">

View File

@@ -125,6 +125,8 @@ const config: CmsConfig = {
name: 'gitea', name: 'gitea',
app_id: 'a046b53c-787a-4b76-bd3a-633221a38954', app_id: 'a046b53c-787a-4b76-bd3a-633221a38954',
repo: 'repomaa/cv', repo: 'repomaa/cv',
base_url: 'https://git.freun.dev',
api_root: 'https://git.freun.dev/api/v1',
}, },
collections: [profile, experience, education, skills], collections: [profile, experience, education, skills],
}; };

View File

@@ -9,6 +9,5 @@
<style> <style>
@page { @page {
size: A4; size: A4;
margin: 15mm;
} }
</style> </style>

View File

@@ -1,5 +1,5 @@
import type { RequestHandler } from './$types.js'; import type { RequestHandler } from './$types.js';
import type { LaunchOptions } from 'puppeteer'; import type { LaunchOptions, PDFOptions } from 'puppeteer';
import { dev } from '$app/environment'; import { dev } from '$app/environment';
import puppeteer from 'puppeteer'; import puppeteer from 'puppeteer';
import * as cheerio from 'cheerio'; import * as cheerio from 'cheerio';
@@ -12,14 +12,14 @@ export const prerender = true;
const cwd = process.cwd(); const cwd = process.cwd();
// PDF generation configuration // PDF generation configuration
const PDF_CONFIG = { const PDF_CONFIG: PDFOptions = {
format: 'A4' as const, format: 'A4',
printBackground: true, printBackground: true,
preferCSSPageSize: true, preferCSSPageSize: true,
margin: { margin: {
top: '20mm', top: '15mm',
right: '20mm', right: '20mm',
bottom: '20mm', bottom: '15mm',
left: '20mm', left: '20mm',
}, },
}; };

BIN
static/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
static/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 B

BIN
static/icon-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB