feat: add cv

This commit is contained in:
2026-10-02 17:32:02 +02:00
parent ddbb6f37b5
commit e82561862a
13 changed files with 473 additions and 1 deletions
+79
View File
@@ -0,0 +1,79 @@
import type { H3Event } from 'h3'
interface SelectValue {
value: string
}
interface FileValue {
url: string
visible_name: string
}
export interface CvRow {
id: number
From: string | null
To: string | null
Type: SelectValue | null
Institution: string | null
Area: string | null
area_german?: string | null
Place: SelectValue | null
Grade: string | null
file?: FileValue[] | null
urls?: string | null
}
export function cvTable(event: H3Event): string {
const { baserowCvTableId } = useRuntimeConfig(event)
if (!baserowCvTableId) {
throw createError({ statusCode: 500, statusMessage: 'NUXT_BASEROW_CV_TABLE_ID is not set' })
}
return baserowCvTableId
}
/** Baserow hands out file URLs with its internal protocol (http); serve them from the configured Baserow URL instead */
function fileUrl(url: string, baserowUrl: string): string {
const { pathname } = new URL(url)
return new URL(pathname, baserowUrl).href
}
function toCvLink(line: string): CvLink | null {
// "https://…", or "Label https://…" for custom link text
const match = line.match(/^(.*?)[\s:|–-]*(https?:\/\/\S+)$/)
if (!match) return null
let url: URL
try {
url = new URL(match[2]!)
} catch {
return null
}
const path = url.pathname.replace(/\/+$/, '')
const kind = url.hostname === 'github.com' ? 'github' : 'web'
const fallback = kind === 'github' ? path.slice(1) : url.hostname + path
return { label: match[1]!.trim() || fallback, url: url.href, kind }
}
/** One URL per line; a blank line starts a new group */
function toCvLinks(text: string | null | undefined): CvLink[][] {
return (text ?? '')
.split(/\n\s*\n/)
.map(block => block.split('\n').map(line => toCvLink(line.trim())).filter((link): link is CvLink => !!link))
.filter(group => group.length)
}
export function toCvEntry(row: CvRow, baserowUrl: string): CvEntry | null {
if (!row.From) return null
return {
id: row.id,
from: row.From,
to: row.To || null,
type: (row.Type?.value as CvType | undefined) ?? null,
institution: (row.Institution ?? '').trim(),
area: (row.Area ?? '').trim(),
areaGerman: (row.area_german ?? '').trim(),
place: row.Place?.value ?? null,
grade: row.Grade ?? null,
files: (row.file ?? []).map(file => ({ name: file.visible_name, url: fileUrl(file.url, baserowUrl) })),
links: toCvLinks(row.urls)
}
}