@anja.codes/create-vitakit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +47 -2
- package/deployments.mjs +178 -0
- package/index.mjs +99 -0
- package/package.json +40 -4
- package/scaffold.mjs +124 -0
- package/template/.gitignore.template +19 -0
- package/template/_forgejo/workflows/codeberg.yml +37 -0
- package/template/_forgejo/workflows/deploy.yml +31 -0
- package/template/_github/workflows/cloudflare.yml +33 -0
- package/template/_github/workflows/cv.yml +36 -0
- package/template/_github/workflows/deploy.yml +53 -0
- package/template/_github/workflows/workers.yml +39 -0
- package/template/app/app.vue +5 -0
- package/template/app/assets/css/main.css +129 -0
- package/template/app/layouts/default.vue +39 -0
- package/template/app/pages/[...slug].vue +30 -0
- package/template/app/pages/cv.vue +34 -0
- package/template/app/pages/index.vue +62 -0
- package/template/app/pages/publications.vue +27 -0
- package/template/content/education.yml +18 -0
- package/template/content/employment.yml +18 -0
- package/template/content/pages/cv.md +9 -0
- package/template/content/pages/index.md +11 -0
- package/template/content/pages/publications.md +8 -0
- package/template/content/pages/research.md +32 -0
- package/template/content/profile.yml +33 -0
- package/template/content/publications.bib +43 -0
- package/template/content/supervision.yml +12 -0
- package/template/content/talks.yml +17 -0
- package/template/content/teaching.yml +17 -0
- package/template/cv-tex/cv.tex +39 -0
- package/template/cv-tex/cv.yml +7 -0
- package/template/cv-tex/latexmkrc +5 -0
- package/template/cv-tex/preamble.tex +7 -0
- package/template/cv-tex/prose/research-statement.tex +17 -0
- package/template/gitlab-ci.yml.template +28 -0
- package/template/nuxt.config.ts +32 -0
- package/template/package.json.template +33 -0
- package/template/public/img/portrait.svg +6 -0
- package/template/public/img/tree.svg +10 -0
- package/template/tsconfig.json +9 -0
- package/template/wrangler.json.template +10 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Builds the PDF CV and attaches it to the workflow run.
|
|
2
|
+
#
|
|
3
|
+
# The PDF is an artifact, not part of the website: it may contain entries
|
|
4
|
+
# marked `visibility: cv` (address, phone, referees). Download it from the run
|
|
5
|
+
# summary. Runs on demand, and on pushes that touch CV material.
|
|
6
|
+
name: CV
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths: ['content/**', 'cv-tex/**']
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- uses: pnpm/action-setup@v6
|
|
20
|
+
- uses: actions/setup-node@v7
|
|
21
|
+
with:
|
|
22
|
+
node-version: 22
|
|
23
|
+
cache: pnpm
|
|
24
|
+
- run: pnpm install --frozen-lockfile
|
|
25
|
+
# Generate the .tex files here: the LaTeX action runs in its own container,
|
|
26
|
+
# without Node. cv-tex/latexmkrc lets it find the generated document class.
|
|
27
|
+
- run: pnpm pdf --tex-only
|
|
28
|
+
- uses: xu-cheng/latex-action@v4
|
|
29
|
+
with:
|
|
30
|
+
working_directory: cv-tex
|
|
31
|
+
root_file: cv.tex
|
|
32
|
+
latexmk_use_lualatex: false
|
|
33
|
+
- uses: actions/upload-artifact@v5
|
|
34
|
+
with:
|
|
35
|
+
name: cv
|
|
36
|
+
path: cv-tex/*.pdf
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Builds the site and publishes it to GitHub Pages.
|
|
2
|
+
#
|
|
3
|
+
# Setup: Settings -> Pages -> Source: "GitHub Actions".
|
|
4
|
+
#
|
|
5
|
+
# NUXT_APP_BASE_URL must match where the site is served from. For a project
|
|
6
|
+
# site at https://<user>.github.io/<repo>/ keep the line below; for a user site
|
|
7
|
+
# or a custom domain, delete it. A wrong value breaks every asset URL.
|
|
8
|
+
name: Deploy
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main]
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
pages: write
|
|
18
|
+
id-token: write
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: pages
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
build:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
env:
|
|
28
|
+
NUXT_APP_BASE_URL: /${{ github.event.repository.name }}/
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v7
|
|
31
|
+
# No `version:` here: the pnpm version comes from `packageManager` in
|
|
32
|
+
# package.json. Setting both fails with ERR_PNPM_BAD_PM_VERSION.
|
|
33
|
+
- uses: pnpm/action-setup@v6
|
|
34
|
+
- uses: actions/setup-node@v7
|
|
35
|
+
with:
|
|
36
|
+
node-version: 22 # keep in sync with engines.node
|
|
37
|
+
cache: pnpm
|
|
38
|
+
- run: pnpm install --frozen-lockfile
|
|
39
|
+
# typecheck + generate + assertions on the generated HTML
|
|
40
|
+
- run: pnpm check
|
|
41
|
+
- uses: actions/upload-pages-artifact@v5
|
|
42
|
+
with:
|
|
43
|
+
path: .output/public
|
|
44
|
+
|
|
45
|
+
deploy:
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment:
|
|
49
|
+
name: github-pages
|
|
50
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
51
|
+
steps:
|
|
52
|
+
- id: deployment
|
|
53
|
+
uses: actions/deploy-pages@v5
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Builds the site and deploys static assets to Cloudflare Workers (not Pages).
|
|
2
|
+
# wrangler.json points exclusively to .output/public. No Worker script or SSR.
|
|
3
|
+
# Setup: enable your account's workers.dev subdomain and choose an available
|
|
4
|
+
# Worker name in wrangler.json, or configure a custom domain there.
|
|
5
|
+
# Secrets: CLOUDFLARE_API_TOKEN (Workers Scripts edit permission),
|
|
6
|
+
# CLOUDFLARE_ACCOUNT_ID. The source repository can stay private.
|
|
7
|
+
name: Deploy (Cloudflare Workers)
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: cloudflare-workers
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
deploy:
|
|
23
|
+
if: ${{ github.ref == 'refs/heads/main' }}
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v7
|
|
27
|
+
- uses: pnpm/action-setup@v6
|
|
28
|
+
- uses: actions/setup-node@v7
|
|
29
|
+
with:
|
|
30
|
+
node-version: 22
|
|
31
|
+
cache: pnpm
|
|
32
|
+
- run: pnpm install --frozen-lockfile
|
|
33
|
+
- run: pnpm check
|
|
34
|
+
- uses: cloudflare/wrangler-action@v4
|
|
35
|
+
with:
|
|
36
|
+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
37
|
+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
38
|
+
wranglerVersion: '4'
|
|
39
|
+
command: deploy
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Design tokens: the first stop for restyling. Tailwind v4 reads these, so
|
|
4
|
+
`text-primary` and `font-serif` follow from here. */
|
|
5
|
+
@theme {
|
|
6
|
+
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
7
|
+
--font-serif: "Lora", ui-serif, Georgia, serif;
|
|
8
|
+
--color-primary: oklch(48% 0.13 250);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
@apply font-sans text-neutral-900 antialiased;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
a {
|
|
16
|
+
@apply text-primary underline underline-offset-2 hover:no-underline;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* --- vitakit components ------------------------------------------------ */
|
|
20
|
+
|
|
21
|
+
.vita-entry {
|
|
22
|
+
@apply grid gap-1 py-2 sm:grid-cols-[8rem_1fr] sm:gap-4;
|
|
23
|
+
}
|
|
24
|
+
.vita-entry__date {
|
|
25
|
+
@apply text-sm text-neutral-500 tabular-nums;
|
|
26
|
+
}
|
|
27
|
+
.vita-entry__title {
|
|
28
|
+
@apply font-medium;
|
|
29
|
+
}
|
|
30
|
+
.vita-entry__meta,
|
|
31
|
+
.vita-entry__note {
|
|
32
|
+
@apply text-sm text-neutral-600;
|
|
33
|
+
}
|
|
34
|
+
.vita-section {
|
|
35
|
+
@apply divide-y divide-neutral-100;
|
|
36
|
+
}
|
|
37
|
+
.vita-section-group {
|
|
38
|
+
@apply mt-10;
|
|
39
|
+
}
|
|
40
|
+
.vita-section-group__title {
|
|
41
|
+
@apply text-xl font-semibold;
|
|
42
|
+
}
|
|
43
|
+
.vita-section-group > .vita-section {
|
|
44
|
+
@apply mt-3;
|
|
45
|
+
}
|
|
46
|
+
.vita-section-group__subtitle {
|
|
47
|
+
@apply mt-6 text-sm font-semibold text-neutral-600;
|
|
48
|
+
}
|
|
49
|
+
.vita-links {
|
|
50
|
+
@apply flex flex-wrap gap-x-4 gap-y-1;
|
|
51
|
+
}
|
|
52
|
+
.vita-publications__group + .vita-publications__group {
|
|
53
|
+
@apply mt-8;
|
|
54
|
+
}
|
|
55
|
+
.vita-publications__heading {
|
|
56
|
+
@apply text-xl font-semibold;
|
|
57
|
+
}
|
|
58
|
+
.vita-bib {
|
|
59
|
+
@apply mt-3 list-decimal space-y-3 pl-6;
|
|
60
|
+
}
|
|
61
|
+
.vita-badge {
|
|
62
|
+
@apply ml-1 rounded bg-neutral-100 px-1.5 py-0.5 text-xs no-underline hover:bg-neutral-200;
|
|
63
|
+
}
|
|
64
|
+
.vita-issues {
|
|
65
|
+
@apply border-b border-red-300 bg-red-50 px-4 py-3 text-sm text-red-900;
|
|
66
|
+
}
|
|
67
|
+
.vita-issues__title {
|
|
68
|
+
@apply font-semibold;
|
|
69
|
+
}
|
|
70
|
+
.vita-issues pre {
|
|
71
|
+
@apply whitespace-pre-wrap font-sans;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* --- Markdown output --------------------------------------------------- */
|
|
75
|
+
|
|
76
|
+
.vita-prose {
|
|
77
|
+
@apply leading-relaxed;
|
|
78
|
+
}
|
|
79
|
+
.vita-prose :where(p, ul, ol, blockquote, pre, table) {
|
|
80
|
+
@apply my-4;
|
|
81
|
+
}
|
|
82
|
+
.vita-prose :where(h2) {
|
|
83
|
+
@apply mt-8 mb-2 text-xl font-semibold;
|
|
84
|
+
}
|
|
85
|
+
.vita-prose :where(h3) {
|
|
86
|
+
@apply mt-6 mb-2 text-lg font-semibold;
|
|
87
|
+
}
|
|
88
|
+
.vita-prose :where(ul) {
|
|
89
|
+
@apply list-disc pl-6;
|
|
90
|
+
}
|
|
91
|
+
.vita-prose :where(ol) {
|
|
92
|
+
@apply list-decimal pl-6;
|
|
93
|
+
}
|
|
94
|
+
.vita-prose :where(code) {
|
|
95
|
+
@apply rounded bg-neutral-100 px-1 py-0.5 text-sm;
|
|
96
|
+
}
|
|
97
|
+
.vita-prose :where(pre) {
|
|
98
|
+
@apply overflow-x-auto rounded bg-neutral-100 p-4 text-sm;
|
|
99
|
+
}
|
|
100
|
+
.vita-prose :where(blockquote) {
|
|
101
|
+
@apply border-l-4 border-neutral-200 pl-4 text-neutral-600;
|
|
102
|
+
}
|
|
103
|
+
.vita-prose :where(figure) {
|
|
104
|
+
@apply my-4;
|
|
105
|
+
}
|
|
106
|
+
.vita-prose :where(figcaption) {
|
|
107
|
+
@apply mt-1 text-xs text-neutral-500;
|
|
108
|
+
}
|
|
109
|
+
/* A figure beside the text on wide screens, above it on narrow ones. */
|
|
110
|
+
.vita-prose :where(figure.figure-right) {
|
|
111
|
+
@apply sm:float-right sm:ml-6 sm:mt-0 sm:w-56;
|
|
112
|
+
}
|
|
113
|
+
.vita-prose :where(figure.figure-right) img {
|
|
114
|
+
@apply w-full rounded border border-neutral-200 bg-white p-2;
|
|
115
|
+
}
|
|
116
|
+
.vita-prose :where(table) {
|
|
117
|
+
@apply w-full border-collapse text-left text-sm;
|
|
118
|
+
}
|
|
119
|
+
.vita-prose :where(th, td) {
|
|
120
|
+
@apply border-b border-neutral-200 py-2 pr-4 align-top;
|
|
121
|
+
}
|
|
122
|
+
.vita-prose :where(th) {
|
|
123
|
+
@apply font-semibold;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Wide display formulas must not blow up the layout on narrow screens. */
|
|
127
|
+
.katex-display {
|
|
128
|
+
@apply overflow-x-auto overflow-y-hidden py-1;
|
|
129
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const profile = useProfile()
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div class="min-h-screen flex flex-col">
|
|
7
|
+
<!-- Shows content problems while developing; a build fails on them instead. -->
|
|
8
|
+
<VitaIssues />
|
|
9
|
+
|
|
10
|
+
<header class="border-b border-neutral-200">
|
|
11
|
+
<div class="mx-auto flex max-w-3xl flex-wrap items-baseline gap-x-6 gap-y-2 px-4 py-6">
|
|
12
|
+
<NuxtLink to="/" class="text-lg font-semibold no-underline">
|
|
13
|
+
{{ profile.name }}
|
|
14
|
+
</NuxtLink>
|
|
15
|
+
<nav class="ml-auto flex gap-4 text-sm">
|
|
16
|
+
<NuxtLink
|
|
17
|
+
v-for="item in profile.nav"
|
|
18
|
+
:key="item.url"
|
|
19
|
+
:to="item.url"
|
|
20
|
+
class="no-underline hover:underline"
|
|
21
|
+
>
|
|
22
|
+
{{ item.label }}
|
|
23
|
+
</NuxtLink>
|
|
24
|
+
</nav>
|
|
25
|
+
</div>
|
|
26
|
+
</header>
|
|
27
|
+
|
|
28
|
+
<main class="mx-auto w-full max-w-3xl flex-1 px-4 py-10">
|
|
29
|
+
<slot />
|
|
30
|
+
</main>
|
|
31
|
+
|
|
32
|
+
<footer class="border-t border-neutral-200">
|
|
33
|
+
<div class="mx-auto flex max-w-3xl flex-wrap items-baseline gap-2 px-4 py-6 text-sm text-neutral-600">
|
|
34
|
+
<p>© {{ new Date().getFullYear() }} {{ profile.name }}</p>
|
|
35
|
+
<VitaMarkdown class="ml-auto text-xs text-neutral-400" :html="profile.footerHtml" />
|
|
36
|
+
</div>
|
|
37
|
+
</footer>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Renders every Markdown page in `content/pages/`.
|
|
4
|
+
*
|
|
5
|
+
* Adding a page means adding a file. When a page needs more than prose, create
|
|
6
|
+
* `app/pages/<name>.vue`: a concrete route always wins over this catch-all.
|
|
7
|
+
*/
|
|
8
|
+
const profile = useProfile()
|
|
9
|
+
const route = useRoute()
|
|
10
|
+
const page = usePage(route.path)
|
|
11
|
+
|
|
12
|
+
if (!page) {
|
|
13
|
+
throw createError({ statusCode: 404, statusMessage: `No page for ${route.path}`, fatal: true })
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
useHead({
|
|
17
|
+
title: page.route === '/' ? profile.name : `${page.title} – ${profile.name}`,
|
|
18
|
+
meta: [{ name: 'description', content: page.description ?? profile.summary }],
|
|
19
|
+
})
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<article>
|
|
24
|
+
<h1 class="text-3xl font-semibold" v-html="page!.titleHtml" />
|
|
25
|
+
<p v-if="page!.description" class="mt-2 text-neutral-600">
|
|
26
|
+
{{ page!.description }}
|
|
27
|
+
</p>
|
|
28
|
+
<VitaMarkdown class="mt-6" :html="page!.bodyHtml" />
|
|
29
|
+
</article>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The CV page: several sections composed in the order you want them.
|
|
4
|
+
*
|
|
5
|
+
* Section order, headings and which sections appear are decided here, not in
|
|
6
|
+
* the data — exactly as `cv-tex/cv.tex` decides them for the PDF. One line per
|
|
7
|
+
* section: move a line to move a section, delete it to leave the section out.
|
|
8
|
+
* A section without entries is not shown, heading included.
|
|
9
|
+
*/
|
|
10
|
+
const profile = useProfile()
|
|
11
|
+
const page = usePage('/cv/')
|
|
12
|
+
|
|
13
|
+
if (!page) {
|
|
14
|
+
throw createError({ statusCode: 404, statusMessage: 'No page for /cv/ (expected content/pages/cv.md)', fatal: true })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
useHead({
|
|
18
|
+
title: `${page.title} – ${profile.name}`,
|
|
19
|
+
meta: [{ name: 'description', content: page.description ?? profile.summary }],
|
|
20
|
+
})
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<article>
|
|
25
|
+
<h1 class="text-3xl font-semibold" v-html="page.titleHtml" />
|
|
26
|
+
<VitaMarkdown class="mt-6" :html="page.bodyHtml" />
|
|
27
|
+
|
|
28
|
+
<VitaSection id="employment" title="Employment" />
|
|
29
|
+
<VitaSection id="education" title="Education" />
|
|
30
|
+
<VitaSection id="teaching" title="Teaching" />
|
|
31
|
+
<VitaSection id="supervision" title="Supervised theses" />
|
|
32
|
+
<VitaSection id="talks" title="Talks" />
|
|
33
|
+
</article>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The landing page: who you are, then the prose from
|
|
4
|
+
* `content/pages/index.md`, then a few recent items.
|
|
5
|
+
*
|
|
6
|
+
* This file is yours — reorder it, delete parts, add your own markup.
|
|
7
|
+
*/
|
|
8
|
+
const profile = useProfile()
|
|
9
|
+
const page = usePage('/')
|
|
10
|
+
const talks = useSection('talks')
|
|
11
|
+
|
|
12
|
+
useHead({
|
|
13
|
+
title: profile.name,
|
|
14
|
+
meta: [{ name: 'description', content: profile.summary }],
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div>
|
|
20
|
+
<header class="flex flex-wrap items-start gap-6 sm:flex-nowrap">
|
|
21
|
+
<img
|
|
22
|
+
v-if="profile.avatar"
|
|
23
|
+
:src="profile.avatar"
|
|
24
|
+
alt=""
|
|
25
|
+
width="128"
|
|
26
|
+
height="128"
|
|
27
|
+
class="size-32 shrink-0 rounded-full object-cover ring-1 ring-neutral-200"
|
|
28
|
+
>
|
|
29
|
+
<div>
|
|
30
|
+
<h1 class="text-3xl font-semibold">
|
|
31
|
+
{{ profile.name }}
|
|
32
|
+
</h1>
|
|
33
|
+
<p v-if="profile.title || profile.affiliation" class="text-neutral-600">
|
|
34
|
+
{{ profile.title }}
|
|
35
|
+
<template v-if="profile.title && profile.affiliation"> · </template>
|
|
36
|
+
<template v-if="profile.affiliation">
|
|
37
|
+
<a v-if="profile.affiliation.url" :href="profile.affiliation.url">{{ profile.affiliation.label }}</a>
|
|
38
|
+
<template v-else>{{ profile.affiliation.label }}</template>
|
|
39
|
+
</template>
|
|
40
|
+
</p>
|
|
41
|
+
<p v-if="profile.email" class="mt-1 text-sm">
|
|
42
|
+
<a :href="`mailto:${profile.email}`">{{ profile.email }}</a>
|
|
43
|
+
</p>
|
|
44
|
+
<VitaLinks :links="profile.links" class="mt-2 text-sm" />
|
|
45
|
+
</div>
|
|
46
|
+
</header>
|
|
47
|
+
|
|
48
|
+
<VitaMarkdown v-if="page" class="mt-8" :html="page.bodyHtml" />
|
|
49
|
+
|
|
50
|
+
<section v-if="talks.length" class="mt-10">
|
|
51
|
+
<h2 class="text-xl font-semibold">
|
|
52
|
+
Recent talks
|
|
53
|
+
</h2>
|
|
54
|
+
<VitaSection :entries="talks" :limit="3" class="mt-3" />
|
|
55
|
+
<p class="mt-3 text-sm">
|
|
56
|
+
<NuxtLink to="/cv/#talks">
|
|
57
|
+
All talks →
|
|
58
|
+
</NuxtLink>
|
|
59
|
+
</p>
|
|
60
|
+
</section>
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Prose from `content/pages/publications.md`, then the generated list.
|
|
4
|
+
*
|
|
5
|
+
* This page shadows the Markdown catch-all for `/publications/` — the general
|
|
6
|
+
* escape hatch when a page needs prose *and* components.
|
|
7
|
+
*/
|
|
8
|
+
const profile = useProfile()
|
|
9
|
+
const page = usePage('/publications/')
|
|
10
|
+
|
|
11
|
+
if (!page) {
|
|
12
|
+
throw createError({ statusCode: 404, statusMessage: 'No page for /publications/ (expected content/pages/publications.md)', fatal: true })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
useHead({
|
|
16
|
+
title: `${page.title} – ${profile.name}`,
|
|
17
|
+
meta: [{ name: 'description', content: page.description ?? profile.summary }],
|
|
18
|
+
})
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<article>
|
|
23
|
+
<h1 class="text-3xl font-semibold" v-html="page.titleHtml" />
|
|
24
|
+
<VitaMarkdown class="mt-6" :html="page.bodyHtml" />
|
|
25
|
+
<VitaPublications class="mt-8" />
|
|
26
|
+
</article>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
- date: { from: 2016, to: 2020 }
|
|
2
|
+
degree: PhD in Mathematics
|
|
3
|
+
institution: { name: University of Klagenfurt, url: https://www.aau.at }
|
|
4
|
+
thesis:
|
|
5
|
+
title: Cutting down random trees
|
|
6
|
+
type: Doctoral thesis
|
|
7
|
+
supervisor: { label: A. Supervisor, url: https://example.org/supervisor }
|
|
8
|
+
|
|
9
|
+
- date: { from: 2014, to: 2016 }
|
|
10
|
+
degree: MSc in Mathematics (with distinction)
|
|
11
|
+
institution: University of Klagenfurt
|
|
12
|
+
thesis:
|
|
13
|
+
title: Ascent sequences and their asymptotics
|
|
14
|
+
type: Master's thesis
|
|
15
|
+
|
|
16
|
+
- date: { from: 2011, to: 2014 }
|
|
17
|
+
degree: BSc in Technical Mathematics
|
|
18
|
+
institution: University of Klagenfurt
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
- date: { from: 2023, to: present }
|
|
2
|
+
position: Postdoctoral Researcher
|
|
3
|
+
institution: { name: University of Graz, url: https://www.uni-graz.at }
|
|
4
|
+
project:
|
|
5
|
+
title: Asymptotics of random discrete structures
|
|
6
|
+
funder: FWF
|
|
7
|
+
grant: P 12345
|
|
8
|
+
url: https://www.fwf.ac.at
|
|
9
|
+
|
|
10
|
+
- date: { from: 2020, to: 2023 }
|
|
11
|
+
position: University Assistant
|
|
12
|
+
institution: University of Klagenfurt
|
|
13
|
+
|
|
14
|
+
- date: { from: 2019, to: 2019 }
|
|
15
|
+
position: Visiting Researcher
|
|
16
|
+
institution: Uppsala University
|
|
17
|
+
note: Three-month research stay with the combinatorics group.
|
|
18
|
+
visibility: cv
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Curriculum Vitae
|
|
3
|
+
description: The same data that produces the PDF.
|
|
4
|
+
order: 30
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Build the PDF version with `pnpm pdf`. The sections below come from the
|
|
8
|
+
YAML files in `content/`; their order is decided in `app/pages/cv.vue`, and the
|
|
9
|
+
order in the PDF in `cv-tex/cv.tex`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: __YAML_NAME__
|
|
3
|
+
order: 0
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Replace this page with a few sentences about yourself: it lives in
|
|
7
|
+
`content/pages/index.md`, and the heading above comes from its front matter.
|
|
8
|
+
|
|
9
|
+
Everything on this site comes from the files in `content/`, and the same data
|
|
10
|
+
produces `cv-tex/cv.pdf`. Add a page by adding a Markdown file; add a CV
|
|
11
|
+
section by adding a YAML file — `pnpm vitakit add section outreach` sets one up.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Research
|
|
3
|
+
description: Analytic combinatorics and random discrete structures.
|
|
4
|
+
order: 10
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<figure class="figure-right">
|
|
8
|
+
<img src="/img/tree.svg" alt="A simulated random tree" width="240" height="140">
|
|
9
|
+
<figcaption>A random tree on eight nodes.</figcaption>
|
|
10
|
+
</figure>
|
|
11
|
+
|
|
12
|
+
My work concerns the asymptotic behaviour of large random trees. A simple
|
|
13
|
+
family is described by the equation $T(z) = z\,\phi(T(z))$, whose singular
|
|
14
|
+
expansion determines almost everything about the limit shape:
|
|
15
|
+
|
|
16
|
+
$$
|
|
17
|
+
T(z) = \tau - \gamma \sqrt{1 - z/\rho} + O(1 - z/\rho).
|
|
18
|
+
$$
|
|
19
|
+
|
|
20
|
+
From this, the expected height of a random tree with $n$ nodes satisfies
|
|
21
|
+
|
|
22
|
+
$$
|
|
23
|
+
\mathbb{E}[H_n] \sim c \sqrt{n}, \qquad n \to \infty.
|
|
24
|
+
$$
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
| Technique | Used for |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| Singularity analysis | asymptotics of coefficients |
|
|
31
|
+
| Analytic combinatorics in several variables | multivariate limit laws |
|
|
32
|
+
| Simulation | checking conjectures before proving them |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# You, and the shape of your site. The only file that is not a CV section.
|
|
2
|
+
name: __YAML_NAME__
|
|
3
|
+
title: __YAML_TITLE__
|
|
4
|
+
affiliation:
|
|
5
|
+
name: __YAML_AFFILIATION__
|
|
6
|
+
email: __YAML_EMAIL__
|
|
7
|
+
|
|
8
|
+
# Where the site is published. Only the PDF needs it, to link files on the
|
|
9
|
+
# site such as /slides/talk.pdf; delete the # once you know the address.
|
|
10
|
+
# url: https://yourname.github.io/
|
|
11
|
+
|
|
12
|
+
# Portrait, from public/. Delete the line if you would rather not have one.
|
|
13
|
+
avatar: /img/portrait.svg
|
|
14
|
+
|
|
15
|
+
links:
|
|
16
|
+
- { label: ORCID, url: https://orcid.org/0000-0002-1825-0097 }
|
|
17
|
+
# - { label: GitHub, url: https://github.com/yourname }
|
|
18
|
+
# - { label: arXiv, url: https://arxiv.org/a/yourname }
|
|
19
|
+
|
|
20
|
+
# One or two sentences for search engines and link previews. What visitors
|
|
21
|
+
# read is content/pages/index.md, not this.
|
|
22
|
+
summary: __YAML_SUMMARY__
|
|
23
|
+
|
|
24
|
+
# Navigation, in the order it should appear. Adding a page does not change
|
|
25
|
+
# this list: the wording and the order are yours.
|
|
26
|
+
nav:
|
|
27
|
+
- { label: About, to: / }
|
|
28
|
+
- { label: Research, to: /research/ }
|
|
29
|
+
- { label: Publications, to: /publications/ }
|
|
30
|
+
- { label: CV, to: /cv/ }
|
|
31
|
+
|
|
32
|
+
# Inline Markdown, shown quietly at the bottom of every page.
|
|
33
|
+
footer: Built with [vitakit](https://github.com/anja-codes/vitakit).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
% Your publication list. Export it from Zotero, JabRef or arXiv and replace the
|
|
2
|
+
% examples below.
|
|
3
|
+
%
|
|
4
|
+
% The non-standard `status` field decides the grouping on /publications/ and in
|
|
5
|
+
% the PDF: published, accepted, preprint, software or other; without it, an
|
|
6
|
+
% entry is published. To change the groups:
|
|
7
|
+
% pnpm vitakit customize publications # -> schemas/publications.ts
|
|
8
|
+
%
|
|
9
|
+
% `doi`, `arxiv`, `mrnumber` and `zbl` become links; `eprint` with
|
|
10
|
+
% `eprinttype = {arxiv}` (or `archivePrefix`) works as `arxiv` does, so exports
|
|
11
|
+
% from Zotero, JabRef or arXiv need no editing. Mathematics in titles works:
|
|
12
|
+
% write $...$ as usual.
|
|
13
|
+
%
|
|
14
|
+
% The website formats this list with a CSL style. To change it:
|
|
15
|
+
% pnpm vitakit eject publications.csl # -> content/publications.csl
|
|
16
|
+
% or save any CSL style under that name.
|
|
17
|
+
|
|
18
|
+
@article{example-published,
|
|
19
|
+
author = {Doe, Jane and Roe, Richard},
|
|
20
|
+
title = {The shape of large random $k$-ary trees},
|
|
21
|
+
journal = {Random Structures \& Algorithms},
|
|
22
|
+
volume = {64},
|
|
23
|
+
pages = {201--240},
|
|
24
|
+
year = {2024},
|
|
25
|
+
doi = {10.5555/12345678},
|
|
26
|
+
status = {published},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@misc{example-preprint,
|
|
30
|
+
author = {Doe, Jane},
|
|
31
|
+
title = {Sharp bounds for ascent sequences of height $h$},
|
|
32
|
+
year = {2025},
|
|
33
|
+
arxiv = {2501.01234},
|
|
34
|
+
status = {preprint},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@software{example-software,
|
|
38
|
+
author = {Doe, Jane},
|
|
39
|
+
title = {treetools: utilities for random tree simulation},
|
|
40
|
+
url = {https://github.com/yourname/treetools},
|
|
41
|
+
year = {2025},
|
|
42
|
+
status = {software},
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
- date: 2025
|
|
2
|
+
student: A. Student
|
|
3
|
+
ongoing: true # still in progress
|
|
4
|
+
title: Simulating random trees with $n$ nodes
|
|
5
|
+
degree: Master's thesis
|
|
6
|
+
institution: University of Graz
|
|
7
|
+
|
|
8
|
+
- date: 2024
|
|
9
|
+
student: B. Student
|
|
10
|
+
title: Ascent sequences in combinatorics
|
|
11
|
+
degree: Bachelor's thesis
|
|
12
|
+
institution: University of Graz
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
- date: 2025-06-16
|
|
2
|
+
title: The shape of large random $k$-ary trees
|
|
3
|
+
event: AofA 2025
|
|
4
|
+
location: Bath, UK
|
|
5
|
+
kind: invited
|
|
6
|
+
|
|
7
|
+
- date: 2024-09-03
|
|
8
|
+
title: Cutting down trees, one leaf at a time
|
|
9
|
+
event: Austrian Mathematical Society Meeting
|
|
10
|
+
location: Graz, Austria
|
|
11
|
+
kind: contributed
|
|
12
|
+
|
|
13
|
+
- date: 2024-03-12
|
|
14
|
+
title: What is a random tree?
|
|
15
|
+
event: Mathematics for schools
|
|
16
|
+
location: Klagenfurt, Austria
|
|
17
|
+
kind: outreach
|