WIP
This commit is contained in:
parent
0ed88f38a4
commit
44b7768d6f
31 changed files with 1146 additions and 141 deletions
|
|
@ -1,4 +1,8 @@
|
||||||
import { defineConfig, DefaultTheme } from "vitepress";
|
import { defineConfig, DefaultTheme } from "vitepress";
|
||||||
|
import {
|
||||||
|
groupIconMdPlugin,
|
||||||
|
groupIconVitePlugin,
|
||||||
|
} from "vitepress-plugin-group-icons";
|
||||||
|
|
||||||
interface CustomThemeConfig extends DefaultTheme.Config {
|
interface CustomThemeConfig extends DefaultTheme.Config {
|
||||||
socialLinks?: Array<{
|
socialLinks?: Array<{
|
||||||
|
|
@ -6,14 +10,27 @@ interface CustomThemeConfig extends DefaultTheme.Config {
|
||||||
link: string;
|
link: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
}>;
|
}>;
|
||||||
|
nav?: Array<{
|
||||||
|
text: string;
|
||||||
|
link: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://vitepress.dev/reference/site-config
|
|
||||||
export default defineConfig<CustomThemeConfig>({
|
export default defineConfig<CustomThemeConfig>({
|
||||||
title: "Simon Einzinger",
|
title: "Simon Einzinger",
|
||||||
description: "Cybersecurity Student",
|
description: "Cybersecurity Student",
|
||||||
markdown: {
|
markdown: {
|
||||||
theme: "github-light",
|
theme: {
|
||||||
|
light: "github-light",
|
||||||
|
dark: "github-dark",
|
||||||
|
},
|
||||||
|
// lineNumbers: true,
|
||||||
|
config(md: any) {
|
||||||
|
md.use(groupIconMdPlugin);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vite: {
|
||||||
|
plugins: [groupIconVitePlugin()],
|
||||||
},
|
},
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
socialLinks: [
|
socialLinks: [
|
||||||
|
|
@ -33,5 +50,10 @@ export default defineConfig<CustomThemeConfig>({
|
||||||
link: "mailto:info@simon-einzinger.de",
|
link: "mailto:info@simon-einzinger.de",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
nav: [
|
||||||
|
{ text: "Home", link: "/" },
|
||||||
|
{ text: "Blog", link: "/blog/" },
|
||||||
|
{ text: "CV", link: "/cv/" },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
} satisfies { themeConfig: CustomThemeConfig });
|
} satisfies { themeConfig: CustomThemeConfig });
|
||||||
|
|
|
||||||
101
docs/.vitepress/theme/components/CVIndex.vue
Normal file
101
docs/.vitepress/theme/components/CVIndex.vue
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { data as cvItems } from "../composables/cv.data";
|
||||||
|
|
||||||
|
import CVTimelineItem from "../layout/CVTimelineItem.vue";
|
||||||
|
import CVProjectCard from "../layout/CVProjectCard.vue";
|
||||||
|
|
||||||
|
function sortByDateDesc(a, b) {
|
||||||
|
return b.startValue - a.startValue || (b.endValue || 0) - (a.endValue || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const educationItems = computed(() =>
|
||||||
|
cvItems.filter((i) => i.section === "education").sort(sortByDateDesc),
|
||||||
|
);
|
||||||
|
|
||||||
|
const workItems = computed(() =>
|
||||||
|
cvItems.filter((i) => i.section === "work-experience").sort(sortByDateDesc),
|
||||||
|
);
|
||||||
|
|
||||||
|
const projectItems = computed(() =>
|
||||||
|
cvItems.filter((i) => i.section === "projects").sort(sortByDateDesc),
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="cv-index">
|
||||||
|
<section v-if="educationItems.length" class="cv-section">
|
||||||
|
<h1>Education</h1>
|
||||||
|
<div class="cv-timeline">
|
||||||
|
<CVTimelineItem
|
||||||
|
v-for="(item, idx) in educationItems"
|
||||||
|
:key="item.url + idx"
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="workItems.length" class="cv-section">
|
||||||
|
<h1>Work Experience</h1>
|
||||||
|
<div class="cv-timeline">
|
||||||
|
<CVTimelineItem
|
||||||
|
v-for="(item, idx) in workItems"
|
||||||
|
:key="item.url + idx"
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="projectItems.length" class="cv-section">
|
||||||
|
<h1>Projects</h1>
|
||||||
|
<div class="cv-project-list">
|
||||||
|
<CVProjectCard
|
||||||
|
v-for="(item, idx) in projectItems"
|
||||||
|
:key="item.url + idx"
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cv-index {
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-section {
|
||||||
|
margin-bottom: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-section h1 {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
font-size: 1.8em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-timeline {
|
||||||
|
position: relative;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-timeline::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 1rem;
|
||||||
|
width: 3px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--highlight-color) 0%,
|
||||||
|
var(--primary-color) 100%
|
||||||
|
);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-project-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
70
docs/.vitepress/theme/composables/cv.data.ts
Normal file
70
docs/.vitepress/theme/composables/cv.data.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { createContentLoader } from "vitepress";
|
||||||
|
|
||||||
|
interface ProjectLink {
|
||||||
|
label: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CVItemData {
|
||||||
|
section: "education" | "work-experience" | "projects";
|
||||||
|
institution?: string;
|
||||||
|
degree?: string;
|
||||||
|
company?: string;
|
||||||
|
position?: string;
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
links?: ProjectLink[];
|
||||||
|
technologies?: string[];
|
||||||
|
|
||||||
|
start: string;
|
||||||
|
end?: string;
|
||||||
|
startValue: number;
|
||||||
|
endValue?: number;
|
||||||
|
excerpt?: string;
|
||||||
|
url: string;
|
||||||
|
body?: string;
|
||||||
|
}
|
||||||
|
declare const data: CVItemData[];
|
||||||
|
export { data };
|
||||||
|
|
||||||
|
export default createContentLoader("cv/*.md", {
|
||||||
|
excerpt: true,
|
||||||
|
transform(raw) {
|
||||||
|
return raw.map(({ frontmatter, url, excerpt: autoExcerpt }) => {
|
||||||
|
const section = frontmatter.section as CVItemData["section"];
|
||||||
|
const startRaw = frontmatter.start as string;
|
||||||
|
const endRaw = (frontmatter.end as string) || "";
|
||||||
|
|
||||||
|
const startValue = parseMonthYear(startRaw);
|
||||||
|
const endValue =
|
||||||
|
endRaw.toLowerCase() === "present" ? Infinity : parseMonthYear(endRaw);
|
||||||
|
|
||||||
|
const finalExcerpt = frontmatter.excerpt || autoExcerpt || "";
|
||||||
|
|
||||||
|
const links = frontmatter.links ?? [];
|
||||||
|
const technologies = frontmatter.technologies ?? [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...frontmatter,
|
||||||
|
section,
|
||||||
|
url,
|
||||||
|
excerpt: finalExcerpt,
|
||||||
|
start: startRaw,
|
||||||
|
end: endRaw,
|
||||||
|
startValue,
|
||||||
|
endValue,
|
||||||
|
links,
|
||||||
|
technologies,
|
||||||
|
};
|
||||||
|
}) as CVItemData[];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function parseMonthYear(str: string): number {
|
||||||
|
if (!str) return 0;
|
||||||
|
const [mm, yyyy] = str.split("/");
|
||||||
|
const month = parseInt(mm, 10);
|
||||||
|
const year = parseInt(yyyy, 10);
|
||||||
|
if (isNaN(month) || isNaN(year)) return 0;
|
||||||
|
return year * 100 + month;
|
||||||
|
}
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { createContentLoader } from "vitepress";
|
|
||||||
|
|
||||||
interface Index {
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const data: Index[];
|
|
||||||
|
|
||||||
export { data };
|
|
||||||
|
|
||||||
export default createContentLoader("*.md", {
|
|
||||||
transform(raw): Index[] {
|
|
||||||
return raw
|
|
||||||
.map(({ url, frontmatter, excerpt }) => ({
|
|
||||||
title: frontmatter.title,
|
|
||||||
url,
|
|
||||||
}))
|
|
||||||
.sort((a, b) => a.title.localeCompare(b.title));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
// https://vitepress.dev/guide/custom-theme
|
// https://vitepress.dev/guide/custom-theme
|
||||||
import { Theme } from "vitepress";
|
|
||||||
import DefaultLayout from "./layout/Layout.vue";
|
|
||||||
import BlogLayout from "./layout/BlogLayout.vue";
|
|
||||||
import type { Theme } from "vitepress";
|
import type { Theme } from "vitepress";
|
||||||
|
import DefaultLayout from "./layout/Layout.vue";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
import "./styles/cards.css";
|
||||||
|
import "./styles/blogpost.css";
|
||||||
|
import "virtual:group-icons.css";
|
||||||
|
import "./styles/code.css";
|
||||||
import BlogIndex from "./components/BlogIndex.vue";
|
import BlogIndex from "./components/BlogIndex.vue";
|
||||||
|
import CVIndex from "./components/CVIndex.vue";
|
||||||
// @ts-ignore
|
|
||||||
const components = [BlogIndex];
|
|
||||||
|
|
||||||
const theme: Theme = {
|
const theme: Theme = {
|
||||||
Layout: DefaultLayout,
|
Layout: DefaultLayout,
|
||||||
enhanceApp({ app, router, siteData }) {
|
enhanceApp({ app }) {
|
||||||
app.component("BlogIndex", BlogIndex);
|
app.component("BlogIndex", BlogIndex);
|
||||||
},
|
app.component("CVPage", CVIndex);
|
||||||
layouts: {
|
|
||||||
blog: BlogLayout,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,91 +10,19 @@ const props = defineProps<BlogItemProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="blog-card">
|
<div class="card card-lift card-gradient-border">
|
||||||
<div class="blog-header">
|
<div class="card-content">
|
||||||
<h2 class="blog-title">
|
<div class="card-header">
|
||||||
<a :href="props.url">
|
<h2 class="card-title">
|
||||||
{{ props.title }}
|
<a :href="props.url">
|
||||||
</a>
|
{{ props.title }}
|
||||||
</h2>
|
</a>
|
||||||
<span class="blog-date">{{ props.date }}</span>
|
</h2>
|
||||||
|
<span class="card-meta">{{ props.date }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="props.excerpt" v-html="props.excerpt"></div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="props.excerpt" v-html="props.excerpt"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.blog-card {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 1.5em;
|
|
||||||
padding: 1.5em;
|
|
||||||
border: 1px solid var(--outline-color);
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: transparent;
|
|
||||||
transition:
|
|
||||||
transform 0.3s,
|
|
||||||
box-shadow 0.3s,
|
|
||||||
opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-card::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: linear-gradient(
|
|
||||||
45deg,
|
|
||||||
var(--primary-color),
|
|
||||||
var(--highlight-color)
|
|
||||||
);
|
|
||||||
-webkit-mask:
|
|
||||||
linear-gradient(#fff 0 0) content-box,
|
|
||||||
linear-gradient(#fff 0 0);
|
|
||||||
-webkit-mask-composite: xor;
|
|
||||||
mask-composite: exclude;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-card:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-card:hover::before {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.2em;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-title a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit; /* Inherit the .blog-title color */
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-date {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-excerpt {
|
|
||||||
margin: 0;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
color: var(--text-color);
|
|
||||||
font-weight: var(--font-weight-regular);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ const prevPost = computed(() => {
|
||||||
<div class="blog-layout">
|
<div class="blog-layout">
|
||||||
<TopBar />
|
<TopBar />
|
||||||
|
|
||||||
<!-- The main post content: the markdown for this page -->
|
|
||||||
<article class="blog-post">
|
<article class="blog-post">
|
||||||
<Content />
|
<Content />
|
||||||
</article>
|
</article>
|
||||||
|
|
@ -42,7 +41,6 @@ const prevPost = computed(() => {
|
||||||
<div v-if="prevPost" class="prev-post">
|
<div v-if="prevPost" class="prev-post">
|
||||||
<a :href="prevPost.url">← {{ prevPost.title }}</a>
|
<a :href="prevPost.url">← {{ prevPost.title }}</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Next post link -->
|
|
||||||
<div v-if="nextPost" class="next-post">
|
<div v-if="nextPost" class="next-post">
|
||||||
<a :href="nextPost.url">{{ nextPost.title }} →</a>
|
<a :href="nextPost.url">{{ nextPost.title }} →</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -52,7 +50,6 @@ const prevPost = computed(() => {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.blog-layout {
|
.blog-layout {
|
||||||
/* your layout styling */
|
|
||||||
}
|
}
|
||||||
.blog-post {
|
.blog-post {
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
|
|
|
||||||
91
docs/.vitepress/theme/layout/CVProjectCard.vue
Normal file
91
docs/.vitepress/theme/layout/CVProjectCard.vue
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface ProjectLink {
|
||||||
|
label: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProjectItemData {
|
||||||
|
title?: string;
|
||||||
|
excerpt?: string;
|
||||||
|
links?: ProjectLink[];
|
||||||
|
technologies?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{ item: ProjectItemData }>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="card card-lift card-gradient-border">
|
||||||
|
<div class="card-content">
|
||||||
|
<!-- Header row: Title on left, Links on right -->
|
||||||
|
<div class="card-header project-header">
|
||||||
|
<h3 class="card-title">
|
||||||
|
{{ props.item.title || "Untitled Project" }}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="project-links"
|
||||||
|
v-if="props.item.links && props.item.links.length"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
v-for="link in props.item.links"
|
||||||
|
:key="link.url"
|
||||||
|
:href="link.url"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
{{ link.label }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="props.item.excerpt"
|
||||||
|
class="card-excerpt project-excerpt"
|
||||||
|
v-html="props.item.excerpt"
|
||||||
|
></p>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="project-technologies"
|
||||||
|
v-if="props.item.technologies && props.item.technologies.length"
|
||||||
|
>
|
||||||
|
{{ props.item.technologies.join(" · ") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.project-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-links {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-links a {
|
||||||
|
color: var(--highlight-color);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-links a:hover {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-excerpt {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-technologies {
|
||||||
|
margin-top: 1em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
108
docs/.vitepress/theme/layout/CVTimelineItem.vue
Normal file
108
docs/.vitepress/theme/layout/CVTimelineItem.vue
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
interface TimelineItemData {
|
||||||
|
section: "education" | "work-experience" | "projects";
|
||||||
|
institution?: string;
|
||||||
|
degree?: string;
|
||||||
|
company?: string;
|
||||||
|
position?: string;
|
||||||
|
start: string;
|
||||||
|
end?: string;
|
||||||
|
excerpt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{ item: TimelineItemData }>();
|
||||||
|
|
||||||
|
const roleTitle = computed(() => {
|
||||||
|
if (props.item.section === "education") {
|
||||||
|
return props.item.degree || "No Title";
|
||||||
|
} else if (props.item.section === "work-experience") {
|
||||||
|
return props.item.position || "No Position";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const placeTitle = computed(() => {
|
||||||
|
if (props.item.section === "education") {
|
||||||
|
return props.item.institution || "";
|
||||||
|
} else if (props.item.section === "work-experience") {
|
||||||
|
return props.item.company || "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateRange = computed(() => {
|
||||||
|
const { start, end } = props.item;
|
||||||
|
if (!end || end.toLowerCase() === "present") {
|
||||||
|
return `${start} - Present`;
|
||||||
|
}
|
||||||
|
return `${start} - ${end}`;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="timeline-dot"></div>
|
||||||
|
|
||||||
|
<div class="card card-lift card-gradient-border">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="card-header timeline-header">
|
||||||
|
<h3 class="card-title timeline-role">{{ roleTitle }}</h3>
|
||||||
|
<span class="card-meta">{{ dateRange }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timeline-place" v-if="placeTitle">
|
||||||
|
{{ placeTitle }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="item.excerpt"
|
||||||
|
class="card-excerpt timeline-excerpt"
|
||||||
|
v-html="item.excerpt"
|
||||||
|
></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.timeline-item {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 3em;
|
||||||
|
margin-left: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-dot {
|
||||||
|
position: absolute;
|
||||||
|
left: -2rem;
|
||||||
|
top: 1.25rem;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: 2px solid var(--outline-color);
|
||||||
|
transition:
|
||||||
|
background-color 0.3s,
|
||||||
|
border-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-role {
|
||||||
|
margin: 0.2em 0 0.25em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-place {
|
||||||
|
font-size: 1em;
|
||||||
|
color: var(--text-color);
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
28
docs/.vitepress/theme/layout/Footer.vue
Normal file
28
docs/.vitepress/theme/layout/Footer.vue
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useData } from "vitepress";
|
||||||
|
const { site } = useData();
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<footer class="site-footer">
|
||||||
|
<p>
|
||||||
|
CC {{ currentYear }} - {{ site.title }} |
|
||||||
|
<a href="/legals" class="footer-link">Data Protection & Privacy</a>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.site-footer {
|
||||||
|
margin-top: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid var(--outline-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.footer-link {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -4,14 +4,36 @@ import { useData } from "vitepress";
|
||||||
import TopBar from "./TopBar.vue";
|
import TopBar from "./TopBar.vue";
|
||||||
import Home from "./Home.vue";
|
import Home from "./Home.vue";
|
||||||
import NotFound from "./NotFound.vue";
|
import NotFound from "./NotFound.vue";
|
||||||
|
import Footer from "./Footer.vue";
|
||||||
|
|
||||||
// https://vitepress.dev/reference/runtime-api#usedata
|
// https://vitepress.dev/reference/runtime-api#usedata
|
||||||
const { frontmatter, page } = useData();
|
const { frontmatter, page } = useData();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TopBar />
|
<div class="custom-layout">
|
||||||
<Home v-if="frontmatter.home" />
|
<TopBar />
|
||||||
<NotFound v-else-if="page.isNotFound" />
|
<div class="content-container" v-if="frontmatter.home">
|
||||||
<Content v-else />
|
<Home />
|
||||||
|
</div>
|
||||||
|
<NotFound v-else-if="page.isNotFound" />
|
||||||
|
<div class="content-container" v-else>
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.custom-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.content-container {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 1200px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
import { useData } from "vitepress";
|
import { useData } from "vitepress";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { data as index } from "../composables/index.data.js";
|
|
||||||
|
|
||||||
import ThemeToggle from "./ThemeToggle.vue";
|
import ThemeToggle from "./ThemeToggle.vue";
|
||||||
|
|
||||||
const { site, theme } = useData();
|
const { site, theme } = useData();
|
||||||
|
|
@ -13,14 +11,14 @@ const socialLinks = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const indexList = computed(() => {
|
const indexList = computed(() => {
|
||||||
return index;
|
return theme.value.nav ?? [];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="TopBar">
|
<div class="TopBar">
|
||||||
<div class="ProfileImageContainer">
|
<div class="ProfileImageContainer">
|
||||||
<img src="/images/me.jpeg" alt="Simon Einzinger" class="ProfileImage" />
|
<img src="/images/me.jpeg" alt="{{ site.title }}" class="ProfileImage" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="title">{{ site.title }}</h1>
|
<h1 class="title">{{ site.title }}</h1>
|
||||||
|
|
@ -47,8 +45,8 @@ const indexList = computed(() => {
|
||||||
|
|
||||||
<div class="Separator"></div>
|
<div class="Separator"></div>
|
||||||
<ul class="IndexList">
|
<ul class="IndexList">
|
||||||
<li v-for="{ title, url } of indexList" :key="title">
|
<li v-for="{ text, link } of indexList" :key="title">
|
||||||
<a :href="url">#{{ title }}</a>
|
<a :href="link">#{{ text }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -131,15 +129,16 @@ const indexList = computed(() => {
|
||||||
.IndexList {
|
.IndexList {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
|
margin-bottom: 2em;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1.5em;
|
gap: 2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.IndexList li a {
|
.IndexList li a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
padding: 0 0.75em;
|
padding: 0 0.5em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
104
docs/.vitepress/theme/styles/blogpost.css
Normal file
104
docs/.vitepress/theme/styles/blogpost.css
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
.table-of-contents {
|
||||||
|
margin: 2em 0;
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid var(--outline-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-of-contents::before {
|
||||||
|
content: "Table of Contents";
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-of-contents ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-of-contents li {
|
||||||
|
position: relative;
|
||||||
|
margin: 0.4em 0;
|
||||||
|
padding-left: 1.2em;
|
||||||
|
}
|
||||||
|
.table-of-contents li::before {
|
||||||
|
content: "•";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-of-contents a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-block {
|
||||||
|
position: relative;
|
||||||
|
margin: 1.5em 0;
|
||||||
|
padding: 1em 1.25em;
|
||||||
|
border-left: 4px solid var(--outline-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-block .custom-block-title {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note.custom-block {
|
||||||
|
border-color: #2196f3;
|
||||||
|
}
|
||||||
|
.note .custom-block-title {
|
||||||
|
color: #2196f3;
|
||||||
|
}
|
||||||
|
.note .custom-block-title::before {
|
||||||
|
content: "📝 ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip.custom-block {
|
||||||
|
border-color: #4caf50;
|
||||||
|
}
|
||||||
|
.tip .custom-block-title::before {
|
||||||
|
content: "💡 ";
|
||||||
|
}
|
||||||
|
.tip .custom-block-title {
|
||||||
|
color: #4caf50;
|
||||||
|
|
||||||
|
.important.custom-block {
|
||||||
|
border-color: #e91e63;
|
||||||
|
}
|
||||||
|
.important .custom-block-title::before {
|
||||||
|
content: "❗️ ";
|
||||||
|
}
|
||||||
|
.important .custom-block-title {
|
||||||
|
color: #e91e63;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning.custom-block {
|
||||||
|
border-color: #ff9800;
|
||||||
|
}
|
||||||
|
.warning .custom-block-title::before {
|
||||||
|
content: "⚠️ ";
|
||||||
|
}
|
||||||
|
.warning .custom-block-title {
|
||||||
|
color: #ff9800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caution.custom-block {
|
||||||
|
border-color: #ff5722;
|
||||||
|
}
|
||||||
|
.caution .custom-block-title::before {
|
||||||
|
content: "🔥 ";
|
||||||
|
}
|
||||||
|
.caution .custom-block-title {
|
||||||
|
color: #ff5722;
|
||||||
|
}
|
||||||
78
docs/.vitepress/theme/styles/cards.css
Normal file
78
docs/.vitepress/theme/styles/cards.css
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
border: 1px solid var(--outline-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-lift {
|
||||||
|
transition:
|
||||||
|
transform 0.3s,
|
||||||
|
box-shadow 0.3s;
|
||||||
|
}
|
||||||
|
.card-lift:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-gradient-border {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-gradient-border::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
padding: 1px;
|
||||||
|
background: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
var(--primary-color),
|
||||||
|
var(--highlight-color)
|
||||||
|
);
|
||||||
|
-webkit-mask:
|
||||||
|
linear-gradient(#fff 0 0) content-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: xor;
|
||||||
|
mask-composite: exclude;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-gradient-border:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
padding: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta,
|
||||||
|
.card-dates {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-excerpt {
|
||||||
|
margin: 0.5em 0 0;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
164
docs/.vitepress/theme/styles/code.css
Normal file
164
docs/.vitepress/theme/styles/code.css
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
[data-theme="light"] .shiki .line [style*="--shiki-light:"] {
|
||||||
|
color: var(--shiki-light) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .shiki .line [style*="--shiki-dark:"] {
|
||||||
|
color: var(--shiki-dark) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vp-code-group.vp-adaptive-theme,
|
||||||
|
.vp-code-block-title {
|
||||||
|
margin: 1.5em 0;
|
||||||
|
border: 1px solid var(--outline-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vp-code-block-title-bar {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vp-code-group.vp-adaptive-theme .tabs {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid var(--outline-color);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vp-code-group.vp-adaptive-theme .tabs input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each label acts like a tab */
|
||||||
|
.vp-code-group.vp-adaptive-theme .tabs label {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.6em 1em;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
border-right: 1px solid var(--outline-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
transition:
|
||||||
|
background-color 0.2s,
|
||||||
|
color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effect for a tab */
|
||||||
|
.vp-code-group.vp-adaptive-theme .tabs label:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "checked" tab => active style */
|
||||||
|
.vp-code-group.vp-adaptive-theme .tabs input:checked + label {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
border-right-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The container for each code block */
|
||||||
|
.vp-code-group.vp-adaptive-theme .blocks {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide all code blocks except the one with .active */
|
||||||
|
.vp-code-group.vp-adaptive-theme .blocks > div:not(.active) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* Show the active one */
|
||||||
|
.vp-code-group.vp-adaptive-theme .blocks > .active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
[class^="language-"] {
|
||||||
|
border: 1px solid var(--outline-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.vp-code-group [class^="language-"],
|
||||||
|
.vp-code-block-title [class^="language-"] {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical line above language- in .vp-code-block-title */
|
||||||
|
.vp-code-block-title [class^="language-"] {
|
||||||
|
border-top: 1px solid var(--outline-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="language-"].vp-adaptive-theme {
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shiki.vp-code {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1em;
|
||||||
|
font-family: "Fira Code", monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 0.75;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shiki .line {
|
||||||
|
display: block;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language label (e.g. “sh”, “py”), top-right by default */
|
||||||
|
[class^="language-"].vp-adaptive-theme .lang {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.4em;
|
||||||
|
right: 0.6em;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy button.
|
||||||
|
Note that after copying, VitePress might change the class to “copied code”.
|
||||||
|
So let’s target BOTH .copy and .copied.code. */
|
||||||
|
[class^="language-"].vp-adaptive-theme .copy,
|
||||||
|
[class^="language-"].vp-adaptive-theme .copied {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.4em;
|
||||||
|
right: 0.6em;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
transition:
|
||||||
|
opacity 0.2s,
|
||||||
|
background-color 0.2s;
|
||||||
|
}
|
||||||
|
[class^="language-"].vp-adaptive-theme .copy:after {
|
||||||
|
content: "Copy";
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="language-"].vp-adaptive-theme .copied:after {
|
||||||
|
content: "Copied";
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="language-"].vp-adaptive-theme:hover .lang {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="language-"].vp-adaptive-theme:hover .copy,
|
||||||
|
[class^="language-"].vp-adaptive-theme:hover .copied.code {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effect on the button */
|
||||||
|
[class^="language-"].vp-adaptive-theme .copy:hover,
|
||||||
|
[class^="language-"].vp-adaptive-theme .copied.code:hover {
|
||||||
|
background-color: var(--outline-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
---
|
---
|
||||||
title: CV
|
title: CV
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<CVPage />
|
||||||
|
|
|
||||||
8
docs/cv/education-1.md
Normal file
8
docs/cv/education-1.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "education"
|
||||||
|
institution: "Gymnasium Stein"
|
||||||
|
degree: "Abitur"
|
||||||
|
start: "09/2013"
|
||||||
|
end: "07/2021"
|
||||||
|
excerpt: "Final Grade: 1.6"
|
||||||
|
---
|
||||||
7
docs/cv/education-2.md
Normal file
7
docs/cv/education-2.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
section: "education"
|
||||||
|
institution: "Saarland University"
|
||||||
|
degree: "Bachelor of Science (Cybersecurity)"
|
||||||
|
start: "10/2021"
|
||||||
|
end: "present"
|
||||||
|
---
|
||||||
14
docs/cv/project-1.md
Normal file
14
docs/cv/project-1.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
section: "projects"
|
||||||
|
title: "Personal Webpage"
|
||||||
|
excerpt: "My personal website including a blog and my CV"
|
||||||
|
links:
|
||||||
|
- label: "Code"
|
||||||
|
url: "https://git.simon-einzinger.de/einSimon/webpage"
|
||||||
|
- label: "Deployment"
|
||||||
|
url: "https://simon-einzinger.de"
|
||||||
|
technologies:
|
||||||
|
- "Vue 3"
|
||||||
|
- "TypeScript"
|
||||||
|
- "VitePress"
|
||||||
|
---
|
||||||
10
docs/cv/project-2.md
Normal file
10
docs/cv/project-2.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
section: "projects"
|
||||||
|
title: "BrainFucK-me"
|
||||||
|
excerpt: "A simple, yet overengineered Brainfuck interpreter/debugger written in Kotlin"
|
||||||
|
links:
|
||||||
|
- label: "Code"
|
||||||
|
url: "https://github.com/einCyberSimon/BrainFucK-me"
|
||||||
|
technologies:
|
||||||
|
- "Kotlin"
|
||||||
|
---
|
||||||
8
docs/cv/work-1.md
Normal file
8
docs/cv/work-1.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "CISPA Helmholtz Center for Information Security"
|
||||||
|
position: "Undergraduate Research Assistant"
|
||||||
|
start: "05/2022"
|
||||||
|
end: "09/2022"
|
||||||
|
excerpt: "Conducted research investigations on Cross-Site Request Forgery (CSRF) Headers exploring inconsistencies between headers in the <a href='https://swag.cispa.saarland/'>Secure Web Applications Group</a> lead by Dr.-Ing. Ben Stock."
|
||||||
|
---
|
||||||
8
docs/cv/work-2.md
Normal file
8
docs/cv/work-2.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "CISPA Helmholtz Center for Information Security"
|
||||||
|
position: "Student Assistant - Scientific Outreach Team"
|
||||||
|
start: "08/2022"
|
||||||
|
end: "09/2022"
|
||||||
|
excerpt: "Assisted in organizing <em>How to Capture-The-Flag(CTF)</em> workshops for highschool students"
|
||||||
|
---
|
||||||
8
docs/cv/work-3.md
Normal file
8
docs/cv/work-3.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "Saarland University"
|
||||||
|
position: "Tutor - Foundations of Cybersecurity 1"
|
||||||
|
start: "11/2022"
|
||||||
|
end: "04/2023"
|
||||||
|
excerpt: "Tutoring the <a href='https://cms.cispa.saarland/cysec1_2223/'>Foundations of Cybersecurity 1</a> lecture held by Dr.-Ing. Ben Stock"
|
||||||
|
---
|
||||||
8
docs/cv/work-4.md
Normal file
8
docs/cv/work-4.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "Saarland University"
|
||||||
|
position: "Tutor - Foundations of Cybersecurity 2"
|
||||||
|
start: "04/2023"
|
||||||
|
end: "09/2023"
|
||||||
|
excerpt: "Tutoring the <a href='https://cms.cispa.saarland/cysecii2023/'>Foundations of Cybersecurity 2</a> lecture held by Dr. Michael Schwarz"
|
||||||
|
---
|
||||||
8
docs/cv/work-5.md
Normal file
8
docs/cv/work-5.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "Saarland University"
|
||||||
|
position: "Teaching Assistant - Foundations of Cybersecurity 1"
|
||||||
|
start: "10/2023"
|
||||||
|
end: "03/2024"
|
||||||
|
excerpt: "Administrative work as Teaching Assistant for the <a href='https://cms.cispa.saarland/cysec1_2324/'>Foundation of Cybersecurity 1</a> lecture held by Dr.-Ing. Ben Stock."
|
||||||
|
---
|
||||||
8
docs/cv/work-6.md
Normal file
8
docs/cv/work-6.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
section: "work-experience"
|
||||||
|
company: "CISPA Helmholtz Center for Information Security"
|
||||||
|
position: "Undergraduate Research Assistant"
|
||||||
|
start: "04/2024"
|
||||||
|
end: "present"
|
||||||
|
excerpt: "Currently working at the <a href='https://roots.ec'>ROOTSEC</a> research group led by Dr. Michael Schwarz focusing on microarchitectural attacks and CPU security."
|
||||||
|
---
|
||||||
|
|
@ -4,6 +4,6 @@ title: About
|
||||||
---
|
---
|
||||||
|
|
||||||
Hello there, I am Simon, a 23 year-old cybersecurity student at Saarland University.
|
Hello there, I am Simon, a 23 year-old cybersecurity student at Saarland University.
|
||||||
Currently, I am in my last bachelor semester writing my thesis on [Side-channel attacks](https://en.wikipedia.org/wiki/Side-channel_attack).
|
Currently, I am in my last™ bachelor semester writing my thesis on [Side-channel attacks](https://en.wikipedia.org/wiki/Side-channel_attack).
|
||||||
Parts of my freetime are dedicated to playing Capture-The-Flag competitions (usually with my team [saarsec](https://saarsec.rocks)).
|
Parts of my freetime are dedicated to playing Capture-The-Flag competitions (usually with my local team [saarsec](https://saarsec.rocks)).
|
||||||
Thus, I will be looking forward to showing some cool challenge solutions in the [Blogs](/blog) section.
|
Thus, I will be looking forward to showing some cool challenge solutions in the [Blogs](/blog) section.
|
||||||
|
|
|
||||||
13
docs/legals.md
Normal file
13
docs/legals.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Impressum
|
||||||
|
|
||||||
|
## Kontakt
|
||||||
|
|
||||||
|
Name: Simon Einzinger
|
||||||
|
|
||||||
|
E-Mail: [info(at)simon-einzinger.de](mailto:info@simon-einzinger.de)
|
||||||
|
|
||||||
|
## Haftung für und Überprüfung von Inhalten:
|
||||||
|
|
||||||
|
Durch die Vorgaben in § 7 Absatz 1 TMG bin ich als Webmaster für die Inhalte meines Blogs verantwortlich.
|
||||||
|
Gleichzeitig befreien mich §§ 8 bis einschließlich § 10 TMG von der Verantwortung, übermittelte oder gespeicherte fremde Inhalte zu überwachen.
|
||||||
|
Trotzdem bin ich mir meiner Pflicht bewusst, der Sperrung und Entfernung von Informationen nachzukommen, wie es geltende Gesetze vorgeben.
|
||||||
|
|
@ -13,18 +13,42 @@ Some excerpt for the blog post teasing what it is _about_
|
||||||
|
|
||||||
with some lorem ipsum text
|
with some lorem ipsum text
|
||||||
|
|
||||||
```python
|
```python [test.py]
|
||||||
def hello_world() -> str:
|
def hello_world() -> str:
|
||||||
return "Hello, World!"
|
return "Hello, World!"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
string = hello_world()
|
string = hello_world()
|
||||||
print(string)
|
print(string)
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!NOTE]
|
::: code-group
|
||||||
|
|
||||||
|
```sh [npm]
|
||||||
|
npm install vitepress-plugin-group-icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [yarn]
|
||||||
|
yarn add vitepress-plugin-group-icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [pnpm]
|
||||||
|
pnpm add vitepress-plugin-group-icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [bun]
|
||||||
|
bun add vitepress-plugin-group-icons
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
> Highlights information that users should take into account, even when skimming.
|
> Highlights information that users should take into account, even when skimming.
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
Some nice tip here
|
||||||
|
:::
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default {
|
export default {
|
||||||
name: "MyComponent",
|
name: "MyComponent",
|
||||||
|
|
|
||||||
190
package-lock.json
generated
190
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
||||||
"@types/markdown-it": "^12.2.3",
|
"@types/markdown-it": "^12.2.3",
|
||||||
"@types/node": "^20.11.27",
|
"@types/node": "^20.11.27",
|
||||||
"vitepress": "^1.5.0",
|
"vitepress": "^1.5.0",
|
||||||
|
"vitepress-plugin-group-icons": "^1.3.5",
|
||||||
"vue": "^3.5.0-beta.3"
|
"vue": "^3.5.0-beta.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -256,6 +257,28 @@
|
||||||
"node": ">= 14.0.0"
|
"node": ">= 14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@antfu/install-pkg": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"package-manager-detector": "^0.2.0",
|
||||||
|
"tinyexec": "^0.3.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@antfu/utils": {
|
||||||
|
"version": "0.7.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
|
||||||
|
"integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.25.9",
|
"version": "7.25.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
||||||
|
|
@ -748,6 +771,15 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify-json/logos": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/logos/-/logos-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-XC4If5D/hbaZvUkTV8iaZuGlQCyG6CNOlaAaJaGa13V5QMYwYjgtKk3vPP8wz3wtTVNVEVk3LRx1fOJz+YnSMw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@iconify-json/simple-icons": {
|
"node_modules/@iconify-json/simple-icons": {
|
||||||
"version": "1.2.18",
|
"version": "1.2.18",
|
||||||
"resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.18.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.18.tgz",
|
||||||
|
|
@ -758,6 +790,15 @@
|
||||||
"@iconify/types": "*"
|
"@iconify/types": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify-json/vscode-icons": {
|
||||||
|
"version": "1.2.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/vscode-icons/-/vscode-icons-1.2.10.tgz",
|
||||||
|
"integrity": "sha512-qjp/j2RcHEZkesuAT6RP8BfcuHa+oERr7K1twfsulrIHrKZlpxxBeEyFm+3evZSAOgD+sjgU5CuTYS3RfCL+Pg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@iconify/types": {
|
"node_modules/@iconify/types": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
||||||
|
|
@ -765,6 +806,22 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify/utils": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@antfu/install-pkg": "^0.4.1",
|
||||||
|
"@antfu/utils": "^0.7.10",
|
||||||
|
"@iconify/types": "^2.0.0",
|
||||||
|
"debug": "^4.4.0",
|
||||||
|
"globals": "^15.13.0",
|
||||||
|
"kolorist": "^1.8.0",
|
||||||
|
"local-pkg": "^0.5.1",
|
||||||
|
"mlly": "^1.7.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
|
|
@ -1553,6 +1610,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/acorn": {
|
||||||
|
"version": "8.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||||
|
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/algoliasearch": {
|
"node_modules/algoliasearch": {
|
||||||
"version": "5.19.0",
|
"version": "5.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.19.0.tgz",
|
||||||
|
|
@ -1632,6 +1701,12 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/confbox": {
|
||||||
|
"version": "0.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
|
||||||
|
"integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/copy-anything": {
|
"node_modules/copy-anything": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
|
||||||
|
|
@ -1655,6 +1730,23 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dequal": {
|
"node_modules/dequal": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
|
|
@ -1770,6 +1862,18 @@
|
||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/globals": {
|
||||||
|
"version": "15.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz",
|
||||||
|
"integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hast-util-to-html": {
|
"node_modules/hast-util-to-html": {
|
||||||
"version": "9.0.4",
|
"version": "9.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.4.tgz",
|
||||||
|
|
@ -1839,6 +1943,28 @@
|
||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/kolorist": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/local-pkg": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz",
|
||||||
|
"integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mlly": "^1.7.3",
|
||||||
|
"pkg-types": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.17",
|
"version": "0.30.17",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||||
|
|
@ -1986,6 +2112,24 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/mlly": {
|
||||||
|
"version": "1.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz",
|
||||||
|
"integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.14.0",
|
||||||
|
"pathe": "^2.0.1",
|
||||||
|
"pkg-types": "^1.3.0",
|
||||||
|
"ufo": "^1.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||||
|
|
@ -2017,6 +2161,18 @@
|
||||||
"regex-recursion": "^5.1.1"
|
"regex-recursion": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/package-manager-detector": {
|
||||||
|
"version": "0.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.8.tgz",
|
||||||
|
"integrity": "sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/pathe": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/perfect-debounce": {
|
"node_modules/perfect-debounce": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
||||||
|
|
@ -2031,6 +2187,17 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/pkg-types": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"confbox": "^0.1.8",
|
||||||
|
"mlly": "^1.7.4",
|
||||||
|
"pathe": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.49",
|
"version": "8.4.49",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||||
|
|
@ -2257,6 +2424,12 @@
|
||||||
"url": "https://github.com/sponsors/alfiejones"
|
"url": "https://github.com/sponsors/alfiejones"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tinyexec": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/trim-lines": {
|
"node_modules/trim-lines": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
|
||||||
|
|
@ -2268,6 +2441,12 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ufo": {
|
||||||
|
"version": "1.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
|
||||||
|
"integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "6.19.8",
|
"version": "6.19.8",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||||
|
|
@ -2480,6 +2659,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vitepress-plugin-group-icons": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vitepress-plugin-group-icons/-/vitepress-plugin-group-icons-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-1f1NP7osRYlNTR0yS5CAqcaasKHRSAzFKpeCUOfCPwYLAFxhCxsEbRtPBm0U1CfrDVa303MsjX18ngGpFGxIMA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify-json/logos": "^1.2.4",
|
||||||
|
"@iconify-json/vscode-icons": "^1.2.10",
|
||||||
|
"@iconify/utils": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vitepress/node_modules/@types/markdown-it": {
|
"node_modules/vitepress/node_modules/@types/markdown-it": {
|
||||||
"version": "14.1.2",
|
"version": "14.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vitepress": "^1.5.0",
|
|
||||||
"@types/markdown-it": "^12.2.3",
|
"@types/markdown-it": "^12.2.3",
|
||||||
"@types/node": "^20.11.27",
|
"@types/node": "^20.11.27",
|
||||||
|
"vitepress": "^1.5.0",
|
||||||
|
"vitepress-plugin-group-icons": "^1.3.5",
|
||||||
"vue": "^3.5.0-beta.3"
|
"vue": "^3.5.0-beta.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue