feat: add hub
This commit is contained in:
@@ -13,7 +13,10 @@ export default defineAppConfig({
|
||||
/** Printed with the date at the bottom of the PDF, e.g. "Berlin, 02.10.2026" */
|
||||
city: 'Berlin',
|
||||
linkedin: 'https://linkedin.com/in/joaquingottlebe',
|
||||
/** Accent color of the CV page (links, active language); the rest of the site keeps its primary color */
|
||||
/** Accent color of the CV page in light mode and in the PDF (links, active language); dark mode uses the site's primary color */
|
||||
accent: 'rgb(53 116 110)'
|
||||
},
|
||||
hub: {
|
||||
cv: { title: 'Lebenslauf', icon: 'i-lucide-file-user', to: '/cv' }
|
||||
}
|
||||
})
|
||||
|
||||
@@ -38,10 +38,13 @@ const { lang, t } = useCvLang()
|
||||
target="_blank"
|
||||
:icon="link.kind === 'github' ? 'i-lucide-github' : 'i-lucide-globe'"
|
||||
:label="link.label"
|
||||
:title="link.label"
|
||||
:aria-label="link.label"
|
||||
color="primary"
|
||||
variant="link"
|
||||
size="sm"
|
||||
class="p-0 print:hidden"
|
||||
:ui="CV_LINK_UI"
|
||||
/>
|
||||
<a
|
||||
v-for="link in group"
|
||||
@@ -58,10 +61,13 @@ const { lang, t } = useCvLang()
|
||||
target="_blank"
|
||||
icon="i-lucide-file-down"
|
||||
:label="file.name"
|
||||
:title="file.name"
|
||||
:aria-label="file.name"
|
||||
color="primary"
|
||||
variant="link"
|
||||
size="sm"
|
||||
class="p-0"
|
||||
:ui="CV_LINK_UI"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
+46
-36
@@ -1,7 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
// Always light: white background, also when the device is in dark mode
|
||||
definePageMeta({ colorMode: 'light' })
|
||||
|
||||
const { cv: profile } = useAppConfig()
|
||||
const { lang, t } = useCvLang()
|
||||
|
||||
@@ -33,10 +30,11 @@ const experience = computed(() => entries.value.filter(entry => !EDUCATION.inclu
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UMain :style="{ '--ui-primary': profile.accent }">
|
||||
<UMain class="cv" :style="{ '--cv-accent': profile.accent }">
|
||||
<UContainer class="max-w-3xl py-8 print:max-w-none print:px-[12mm] print:pt-[15mm] print:pb-0">
|
||||
<div class="mb-6 flex justify-end print:hidden">
|
||||
<UFieldGroup size="xs">
|
||||
<div class="mb-6 flex justify-end gap-2 print:hidden">
|
||||
<AppHeaderActions />
|
||||
<UFieldGroup>
|
||||
<UButton
|
||||
v-for="option in (['de', 'en'] as const)"
|
||||
:key="option"
|
||||
@@ -49,36 +47,43 @@ const experience = computed(() => entries.value.filter(entry => !EDUCATION.inclu
|
||||
</UFieldGroup>
|
||||
</div>
|
||||
|
||||
<header class="mb-10 flex items-center gap-5">
|
||||
<UAvatar v-if="profile.photo" :src="profile.photo" :alt="profile.name || t.photo" class="size-20 shrink-0" />
|
||||
<div class="min-w-0">
|
||||
<h1 class="text-2xl font-semibold text-highlighted">
|
||||
{{ profile.name || 'CV' }}
|
||||
</h1>
|
||||
<p v-if="profile.description[lang]" class="mt-1 text-sm text-muted">
|
||||
{{ profile.description[lang] }}
|
||||
</p>
|
||||
<div class="mt-1 flex flex-wrap gap-x-4">
|
||||
<UButton
|
||||
v-if="profile.email"
|
||||
:to="`mailto:${profile.email}`"
|
||||
:label="profile.email"
|
||||
color="primary"
|
||||
variant="link"
|
||||
class="p-0"
|
||||
/>
|
||||
<UButton
|
||||
v-if="profile.linkedin"
|
||||
:to="profile.linkedin"
|
||||
target="_blank"
|
||||
label="LinkedIn"
|
||||
color="primary"
|
||||
variant="link"
|
||||
class="p-0 print:hidden"
|
||||
/>
|
||||
<!-- In the PDF links are written out, since the label alone can't be followed on paper -->
|
||||
<a v-if="profile.linkedin" :href="profile.linkedin" class="hidden text-sm font-medium text-primary print:inline">{{ cvLinkText(profile.linkedin) }}</a>
|
||||
</div>
|
||||
<header class="mb-10">
|
||||
<UAvatar v-if="profile.photo" :src="profile.photo" :alt="profile.name || t.photo" class="mb-4 size-20" />
|
||||
<!-- Under the photo: name, description, links -->
|
||||
<h1 class="text-2xl font-semibold text-highlighted">
|
||||
{{ profile.name || 'CV' }}
|
||||
</h1>
|
||||
<p v-if="profile.description[lang]" class="mt-1 text-sm text-muted">
|
||||
{{ profile.description[lang] }}
|
||||
</p>
|
||||
<div class="mt-3 flex flex-wrap gap-x-4 gap-y-1">
|
||||
<UButton
|
||||
v-if="profile.email"
|
||||
:to="`mailto:${profile.email}`"
|
||||
icon="i-lucide-mail"
|
||||
:label="profile.email"
|
||||
:title="profile.email"
|
||||
:aria-label="profile.email"
|
||||
color="primary"
|
||||
variant="link"
|
||||
class="p-0"
|
||||
:ui="CV_LINK_UI"
|
||||
/>
|
||||
<UButton
|
||||
v-if="profile.linkedin"
|
||||
:to="profile.linkedin"
|
||||
target="_blank"
|
||||
icon="i-lucide-linkedin"
|
||||
label="LinkedIn"
|
||||
title="LinkedIn"
|
||||
aria-label="LinkedIn"
|
||||
color="primary"
|
||||
variant="link"
|
||||
class="p-0 print:hidden"
|
||||
:ui="CV_LINK_UI"
|
||||
/>
|
||||
<!-- In the PDF links are written out, since the label alone can't be followed on paper -->
|
||||
<a v-if="profile.linkedin" :href="profile.linkedin" class="hidden text-sm font-medium text-primary print:inline">{{ cvLinkText(profile.linkedin) }}</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -109,6 +114,11 @@ const experience = computed(() => entries.value.filter(entry => !EDUCATION.inclu
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* The CV's accent instead of the site's primary color in light mode (and so in the PDF); dark mode keeps the site's */
|
||||
html:not(.dark) .cv {
|
||||
--ui-primary: var(--cv-accent);
|
||||
}
|
||||
|
||||
/* Top and bottom of every printed page. The sides and the extra space above the first page come from the container's
|
||||
print padding, which also works in browsers that ignore @page margins */
|
||||
@page {
|
||||
|
||||
@@ -2,3 +2,6 @@
|
||||
export function cvLinkText(url: string): string {
|
||||
return url.replace(/^https?:\/\//, '').replace(/\/$/, '')
|
||||
}
|
||||
|
||||
/** Link buttons show only their icon on phones, where long labels don't fit; the label is then the tooltip and aria-label. The PDF shows the text without the icon (only the email is printed this way) */
|
||||
export const CV_LINK_UI = { label: 'hidden sm:inline print:inline', leadingIcon: 'print:hidden' }
|
||||
|
||||
Reference in New Issue
Block a user