Migration to Nuxt3
8
.github/workflows/deploy.yml
vendored
@ -23,13 +23,13 @@ jobs:
|
|||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: npm run generate
|
||||||
|
|
||||||
- name: Upload production-ready build files
|
- name: Upload production-ready build files
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: production-files
|
name: production-files
|
||||||
path: ./dist
|
path: ./.output/public
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy
|
name: Deploy
|
||||||
@ -42,10 +42,10 @@ jobs:
|
|||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: production-files
|
name: production-files
|
||||||
path: ./dist
|
path: ./.output/public
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./dist
|
publish_dir: ./.output/public
|
||||||
33
.gitignore
vendored
@ -1,28 +1,9 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
*.log*
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
.output
|
||||||
|
.env
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
.DS_Store
|
||||||
coverage
|
|
||||||
*.local
|
|
||||||
|
|
||||||
/cypress/videos/
|
|
||||||
/cypress/screenshots/
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
.vscode
|
|
||||||
.idea
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|||||||
43
app.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div v-if="init"
|
||||||
|
class="bg-gray-100 text-gray-900 min-h-screen h-full
|
||||||
|
dark:bg-gray-900 dark:text-slate-50"
|
||||||
|
style="font-family: 'Comfortaa'; overflow-x: hidden; ">
|
||||||
|
|
||||||
|
<!-- Prevents scrollbar shift -->
|
||||||
|
<div style="margin-right: calc(-1 * (100vw - 100%));">
|
||||||
|
<div class="container mx-auto pb-8 px-3 md:px-8 min-h-screen w-screen flex flex-col">
|
||||||
|
<NuxtLayout>
|
||||||
|
<NuxtPage/>
|
||||||
|
</NuxtLayout>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Cookie />
|
||||||
|
<EastereggBanner ref="easteregg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { locale } = useI18n();
|
||||||
|
const easteregg = ref();
|
||||||
|
const init = ref(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
applyTheme();
|
||||||
|
|
||||||
|
document.addEventListener("easteregg", (e) => {
|
||||||
|
// @ts-ignore
|
||||||
|
easteregg.value.show(e.detail);
|
||||||
|
});
|
||||||
|
|
||||||
|
init.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
useHead({ htmlAttrs: { lang: locale.value } });
|
||||||
|
watch(locale, (new_locale) => {
|
||||||
|
useHead({ htmlAttrs: { lang: new_locale } });
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 772 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 634 B After Width: | Height: | Size: 634 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 553 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 963 B After Width: | Height: | Size: 963 B |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 687 B After Width: | Height: | Size: 687 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 501 B After Width: | Height: | Size: 501 B |
|
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 592 B |
|
Before Width: | Height: | Size: 548 B After Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 845 B After Width: | Height: | Size: 845 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
1
assets/images/icons/nuxt.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 298"><g fill="none" fill-rule="nonzero"><path fill="#00C58E" d="M227.92099 82.07407l-13.6889 23.7037-46.8148-81.08641L23.7037 273.58025h97.3037c0 13.0912 10.61252 23.7037 23.70371 23.7037H23.70371c-8.46771 0-16.29145-4.52017-20.5246-11.85382-4.23315-7.33366-4.23272-16.36849.00114-23.70174L146.89383 12.83951c4.23415-7.33433 12.0596-11.85252 20.5284-11.85252 8.46878 0 16.29423 4.51819 20.52839 11.85252l39.97037 69.23456z"/><path fill="#2F495E" d="M331.6642 261.7284l-90.05432-155.95062-13.6889-23.7037-13.68888 23.7037-90.04445 155.95061c-4.23385 7.33325-4.23428 16.36808-.00113 23.70174 4.23314 7.33365 12.05689 11.85382 20.5246 11.85382h166.4c8.46946 0 16.29644-4.51525 20.532-11.84955 4.23555-7.3343 4.23606-16.37123.00132-23.706h.01976zM144.7111 273.58024L227.921 129.48148l83.19012 144.09877h-166.4z"/><path fill="#108775" d="M396.04938 285.4321c-4.23344 7.33254-12.05656 11.85185-20.52345 11.85185H311.1111c13.0912 0 23.7037-10.6125 23.7037-23.7037h40.66173L260.09877 73.74815l-18.4889 32.02963-13.68888-23.7037L239.5753 61.8963c4.23416-7.33433 12.0596-11.85252 20.5284-11.85252 8.46879 0 16.29423 4.51819 20.52839 11.85252l115.41728 199.8321c4.23426 7.33395 4.23426 16.36975 0 23.7037z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 365 B |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 745 B After Width: | Height: | Size: 745 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 466 B |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
BIN
assets/images/no-turn-street.png
Normal file
|
After Width: | Height: | Size: 458 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 309 KiB After Width: | Height: | Size: 309 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<p class="my-4 text-left md:text-center">
|
<div class="my-4 text-left md:text-center">
|
||||||
<a :href="props.url">
|
<a :href="props.url">
|
||||||
<div class="inline-flex items-center">
|
<div class="inline-flex items-center">
|
||||||
<img :src="props.icon" alt="Github" class="h-7 mr-2 select-none dark:invert" />
|
<img :src="props.icon" alt="Github" class="h-7 mr-2 select-none dark:invert" />
|
||||||
<span class="text-xl text-left">{{ props.label }}</span>
|
<span class="text-xl text-left">{{ props.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<ClientOnly>
|
||||||
<div v-if="show_banner" class="w-full h-full">
|
<div v-if="show_banner" class="w-full h-full">
|
||||||
|
|
||||||
<div ref="container_cookie" class="absolute top-0 left-0 h-full w-full pointer-events-none z-40">
|
<div ref="container_cookie" class="absolute top-0 left-0 h-full w-full pointer-events-none z-40">
|
||||||
@ -7,44 +8,42 @@
|
|||||||
|
|
||||||
<div ref="banner" class="fixed bottom-0 left-0 z-50 bg-slate-200/90 border-slate-700 dark:bg-slate-800/90 dark:border-slate-400
|
<div ref="banner" class="fixed bottom-0 left-0 z-50 bg-slate-200/90 border-slate-700 dark:bg-slate-800/90 dark:border-slate-400
|
||||||
border rounded w-fit lg:w-1/2 p-3 px-5 m-5">
|
border rounded w-fit lg:w-1/2 p-3 px-5 m-5">
|
||||||
<p class="text-sm">{{ t("cookie policy title") }}</p>
|
<p class="text-sm">{{ $t("cookie policy title") }}</p>
|
||||||
<div class="text-xs">
|
<div class="text-xs">
|
||||||
<span>{{ t("cookie policy") }} <button :onclick="throwCookie" class="underline">{{ t("cookie policy link") }}</button></span>
|
<span>{{ $t("cookie policy") }} <button @click="throwCookie" class="underline">{{ $t("cookie policy link") }}</button></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-2 text-sm">
|
<div class="flex justify-end mt-2 text-sm">
|
||||||
<button :onclick="refuseCookieBanner" class="mx-1 hover:text-slate-500 dark:hover:text-slate-300">{{ t("reject") }}</button>
|
<button @click="refuseCookieBanner" class="mx-1 hover:text-slate-500 dark:hover:text-slate-300">{{ $t("reject") }}</button>
|
||||||
<button :onclick="acceptCookieBanner" class="rounded p-2 mx-1 bg-slate-300 hover:bg-slate-400 dark:bg-slate-700 dark:hover:bg-slate-600">{{ t("accept") }}</button>
|
<button @click="acceptCookieBanner" class="rounded p-2 mx-1 bg-slate-300 hover:bg-slate-400 dark:bg-slate-700 dark:hover:bg-slate-600">{{ $t("accept") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</ClientOnly>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { Engine, Render, Bodies, Composite, Body, Runner } from "matter-js";
|
import { Engine, Render, Bodies, Composite, Body, Runner } from "matter-js";
|
||||||
import cookie_image from "@/assets/images/cookie.png";
|
import cookie_image from "@/assets/images/cookie.png";
|
||||||
import { randomInt, random } from "@/utilities/random";
|
|
||||||
import { shouldShowCookie, acceptCookie, refuseCookie } from "@/utilities/cookie_handler";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { addFoundEasterEgg } from "@/utilities/easteregg_handler";
|
|
||||||
import locale from "@/locales/cookie";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
const container_cookie = ref(null);
|
||||||
|
const canvas_cookie = ref(null);
|
||||||
|
|
||||||
const container_cookie = ref();
|
const show_banner = ref(true);
|
||||||
const canvas_cookie = ref();
|
const canvas_width = ref(0);
|
||||||
|
const canvas_height = ref(0);
|
||||||
const show_banner = ref(shouldShowCookie());
|
|
||||||
const canvas_width = ref(getWidth());
|
|
||||||
const canvas_height = ref(getHeight());
|
|
||||||
|
|
||||||
let engine:any = null;
|
let engine:any = null;
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
show_banner.value = shouldShowCookie()
|
||||||
|
canvas_width.value = getWidth();
|
||||||
|
canvas_height.value = getHeight();
|
||||||
|
|
||||||
if (shouldShowCookie()) {
|
if (shouldShowCookie()) {
|
||||||
|
await nextTick()
|
||||||
initCanvas();
|
initCanvas();
|
||||||
|
|
||||||
new ResizeObserver(() => {
|
new ResizeObserver(() => {
|
||||||
@ -9,8 +9,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from "vue";
|
|
||||||
|
|
||||||
const is_loading = ref(true);
|
const is_loading = ref(true);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
33
components/LanguageSelector.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<button id="button-dropdown-locales" data-dropdown-toggle="dropdown-locales" type="button"
|
||||||
|
class="rounded-full p-1 hover:bg-slate-200 dark:hover:bg-slate-700">
|
||||||
|
<div class="w-5 h-5 flex items-center justify-center">
|
||||||
|
<img src="~/assets/images/icons/globe.svg" alt="Language" class="h-full w-full dark:invert" />
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div id="dropdown-locales" class="z-10 hidden bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600">
|
||||||
|
<ul class="p-3 space-y-1 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="button-dropdown-locales">
|
||||||
|
|
||||||
|
<li v-for="locale in $i18n.locales" :key="`locale-${locale.code}`">
|
||||||
|
<NuxtLink :to="switchLocalePath(locale.code)" class="text-sm font-medium uppercase text-gray-900 rounded dark:text-gray-300">
|
||||||
|
<span class="flex items-center p-2 px-5 rounded hover:bg-gray-100 dark:hover:bg-gray-600">
|
||||||
|
{{ locale.code }}
|
||||||
|
</span>
|
||||||
|
</NuxtLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { initDropdowns } from "flowbite";
|
||||||
|
const switchLocalePath = useSwitchLocalePath()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initDropdowns();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
79
components/ProfilePicture.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<div class="flex items-center h-60 w-60">
|
||||||
|
<img v-show="picture === 'dark'" src="~/assets/images/profile/picture-dark.png" alt="" class="max-h-full max-w-full">
|
||||||
|
<img v-show="picture === 'light'" src="~/assets/images/profile/picture-light.png" alt="" class="max-h-full max-w-full">
|
||||||
|
<img v-show="picture === 'bright'" src="~/assets/images/profile/picture-bright.png" alt="" class="max-h-full max-w-full">
|
||||||
|
<img v-show="picture === 'no light'" src="~/assets/images/profile/picture-nolight.png" alt="" class="max-h-full max-w-full">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="message" class="absolute bottom-0 left-0 w-full">
|
||||||
|
<p class="w-fit mx-auto px-2 pt-1 mb-1 bg-gray-200 dark:bg-gray-700">{{ message }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const picture = ref(getTheme());
|
||||||
|
const message = ref("");
|
||||||
|
|
||||||
|
|
||||||
|
// Finite-state automata to handle theme changes
|
||||||
|
interface State {
|
||||||
|
image: string; // Image to display
|
||||||
|
message: string; // Message to display (string to parse with i18n)
|
||||||
|
expect: string; // Expected active theme when this state is applied
|
||||||
|
next: string; // Next state
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let current_state = document.querySelector("html")?.classList.contains("dark") ? "dark1" : "light1";
|
||||||
|
let states:Record<string, State> = {
|
||||||
|
"dark1": { image: "dark", message: "", expect: "dark", next: "bright" },
|
||||||
|
"bright": { image: "bright", message: "that's bright", expect: "light", next: "dark2" },
|
||||||
|
"dark2": { image: "dark", message: "better", expect: "dark", next: "light_final" },
|
||||||
|
|
||||||
|
"light1": { image: "light", message: "", expect: "light", next: "nolights" },
|
||||||
|
"nolights": { image: "no light", message: "where lights", expect: "dark", next: "light2" },
|
||||||
|
"light2": { image: "light", message: "here lights", expect: "light", next: "dark_final" },
|
||||||
|
|
||||||
|
"dark_final": { image: "dark", message: "", expect: "dark", next: "light_final" },
|
||||||
|
"light_final": { image: "light", message: "", expect: "light", next: "dark_final" },
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyState() {
|
||||||
|
picture.value = states[current_state]?.image;
|
||||||
|
message.value = states[current_state]?.message !== "" ? t(states[current_state]?.message) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextState() {
|
||||||
|
current_state = states[current_state]?.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyState();
|
||||||
|
|
||||||
|
let observer = new MutationObserver(function(mutations) {
|
||||||
|
if (!useRoute().name?.toString().startsWith("about")) { observer.disconnect(); return; }
|
||||||
|
|
||||||
|
const is_dark_theme = document.querySelector("html")?.classList.contains("dark");
|
||||||
|
|
||||||
|
if ( states[states[current_state].next].expect === (is_dark_theme ? "dark" : "light") ) {
|
||||||
|
nextState();
|
||||||
|
applyState();
|
||||||
|
|
||||||
|
if (current_state === "bright") { addFoundEasterEgg("picture-bright"); }
|
||||||
|
else if (current_state === "nolights") { addFoundEasterEgg("picture-nolights"); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Observes for theme changes
|
||||||
|
observer.observe((document.querySelector("html") as Node), { attributes: true, attributeFilter: ['class'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -1,23 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-52">
|
<div v-if="current_name !== ''" class="w-52">
|
||||||
<img :src="current_image" alt="" class="h-40 max-w-xs max-w- mx-auto" :onclick="userChangeThing">
|
<img :src="current_image" alt="" class="h-40 max-w-xs max-w- mx-auto" @click="userChangeThing">
|
||||||
<p class="text-center text-sm mt-2 select-none">{{ t(current_name) }}</p>
|
<p class="text-center text-sm mt-2 select-none">{{ $t(current_name) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { randomOfArray } from "@/utilities/random";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { addFoundEasterEgg } from "@/utilities/easteregg_handler";
|
|
||||||
import penguin_image from "@/assets/images/penguin.png";
|
import penguin_image from "@/assets/images/penguin.png";
|
||||||
import llama_image from "@/assets/images/llama.png";
|
import llama_image from "@/assets/images/llama.png";
|
||||||
import rock_image from "@/assets/images/rock.png";
|
import rock_image from "@/assets/images/rock.png";
|
||||||
import coconut_image from "@/assets/images/coconut.png";
|
import coconut_image from "@/assets/images/coconut.png";
|
||||||
import red_panda_image from "@/assets/images/red-panda.png";
|
import red_panda_image from "@/assets/images/red-panda.png";
|
||||||
import locale from "@/locales/something";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
|
|
||||||
const things = [
|
const things = [
|
||||||
{ name: "penguin", image: penguin_image },
|
{ name: "penguin", image: penguin_image },
|
||||||
@ -30,8 +24,6 @@
|
|||||||
const current_name = ref("");
|
const current_name = ref("");
|
||||||
const current_image = ref("");
|
const current_image = ref("");
|
||||||
|
|
||||||
changeThing();
|
|
||||||
|
|
||||||
|
|
||||||
function changeThing() {
|
function changeThing() {
|
||||||
const to_show_thing = randomOfArray(things.filter((thing) => thing.name !== current_name.value));
|
const to_show_thing = randomOfArray(things.filter((thing) => thing.name !== current_name.value));
|
||||||
@ -44,4 +36,9 @@
|
|||||||
addFoundEasterEgg("change-something");
|
addFoundEasterEgg("change-something");
|
||||||
changeThing();
|
changeThing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
changeThing();
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -1,25 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="rounded-full p-1 hover:bg-slate-200 dark:hover:bg-slate-700" :onclick="changeTheme">
|
<button class="rounded-full p-1 hover:bg-slate-200 dark:hover:bg-slate-700" @click="changeTheme">
|
||||||
<div class="w-5 h-5 flex items-center justify-center">
|
<div class="w-5 h-5 flex items-center justify-center">
|
||||||
<div v-if="current_theme === 'light'">
|
<div v-if="current_theme === 'light'">
|
||||||
<img :src="moon_icon" alt="Dark theme" class="h-full w-full" />
|
<img src="~/assets/images/icons/moon.svg" alt="Dark theme" class="h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="current_theme === 'dark'">
|
<div v-if="current_theme === 'dark'">
|
||||||
<img :src="sun_icon" alt="Light theme" class="invert h-full w-full" />
|
<img src="~/assets/images/icons/sun.svg" alt="Light theme" class="invert h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getTheme, flipTheme, applyTheme } from "@/utilities/theme_handler";
|
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
import moon_icon from "@/assets/images/icons/moon.svg";
|
const current_theme = ref("");
|
||||||
import sun_icon from "@/assets/images/icons/sun.svg";
|
|
||||||
|
|
||||||
const current_theme = ref(getTheme());
|
onMounted(() => {
|
||||||
|
current_theme.value = getTheme();
|
||||||
|
})
|
||||||
|
|
||||||
function changeTheme() {
|
function changeTheme() {
|
||||||
flipTheme();
|
flipTheme();
|
||||||
@ -1,4 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div v-if="loading" class="flex w-full justify-center">
|
||||||
|
<span class="animate-ping absolute inline-flex h-5 w-5 rounded-full bg-slate-800 dark:bg-slate-200 opacity-75"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="w-full h-full" ref="container_timeline">
|
<div class="w-full h-full" ref="container_timeline">
|
||||||
<div class="flex justify-center w-full h-full" v-if="month_offset > 0 && min_date && max_date">
|
<div class="flex justify-center w-full h-full" v-if="month_offset > 0 && min_date && max_date">
|
||||||
|
|
||||||
@ -54,16 +58,15 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
|
||||||
import type { PropType, Ref } from "vue";
|
|
||||||
|
|
||||||
interface Event {
|
interface Event {
|
||||||
title: string, description: string, time_label: string,
|
title: string, description: string, time_label: string,
|
||||||
start: Date, end: Date, current?: boolean
|
start: Date, end: Date, current?: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
right: {
|
right: {
|
||||||
type: Object as PropType<Event[]>,
|
type: Object as PropType<Event[]>,
|
||||||
@ -75,7 +78,7 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const loading = ref(true);
|
||||||
const container_timeline = ref();
|
const container_timeline = ref();
|
||||||
const month_offset = ref(-1);
|
const month_offset = ref(-1);
|
||||||
const right_events:Ref<{ index: number, offset: number }[]> = ref([]);
|
const right_events:Ref<{ index: number, offset: number }[]> = ref([]);
|
||||||
@ -106,6 +109,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
loading.value = false;
|
||||||
updateTimelineSize();
|
updateTimelineSize();
|
||||||
|
|
||||||
// Computes the offset w.r.t. the end of the time interval
|
// Computes the offset w.r.t. the end of the time interval
|
||||||
@ -118,6 +122,6 @@
|
|||||||
index: index
|
index: index
|
||||||
}));
|
}));
|
||||||
|
|
||||||
new ResizeObserver(updateTimelineSize).observe(document.querySelector("#app") as Element)
|
new ResizeObserver(updateTimelineSize).observe(document.querySelector("html") as Element)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<ClientOnly>
|
||||||
<div v-if="show_banner" class="fixed top-0 left-0 w-full pointer-events-none z-50">
|
<div v-if="show_banner" class="fixed top-0 left-0 w-full pointer-events-none z-50">
|
||||||
|
|
||||||
<div :class="`border rounded-sm mx-auto w-fit max-w-xs md:max-w-md pointer-events-auto
|
<div :class="`border rounded-sm mx-auto w-fit max-w-xs md:max-w-md pointer-events-auto
|
||||||
@ -15,8 +16,8 @@
|
|||||||
<PictureNoLightEgg v-if="easteregg === 'picture-nolights'" />
|
<PictureNoLightEgg v-if="easteregg === 'picture-nolights'" />
|
||||||
|
|
||||||
<div class="mt-1 text-center">
|
<div class="mt-1 text-center">
|
||||||
<p v-if="found_eastereggs != total_eastereggs">{{ found_eastereggs }}/{{ total_eastereggs }} {{ t("easter eggs found") }}</p>
|
<p v-if="found_eastereggs != total_eastereggs">{{ found_eastereggs }}/{{ total_eastereggs }} {{ $t("easter eggs found") }}</p>
|
||||||
<p v-if="found_eastereggs === total_eastereggs">{{ t("all easter eggs found") }}</p>
|
<p v-if="found_eastereggs === total_eastereggs">{{ $t("all easter eggs found") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -24,29 +25,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</ClientOnly>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { getFoundEasterEggsCount, getTotalEasterEggsCount } from "@/utilities/easteregg_handler";
|
|
||||||
import CookieEgg from "./eggs/Cookie.vue";
|
|
||||||
import FutureEgg from "./eggs/Future.vue";
|
|
||||||
import SomethingEgg from "./eggs/Something.vue";
|
|
||||||
import PictureBrightEgg from "./eggs/PictureBright.vue";
|
|
||||||
import PictureNoLightEgg from "./eggs/PictureNoLight.vue";
|
|
||||||
import locale from "@/locales/easteregg";
|
|
||||||
|
|
||||||
const show_banner = ref(false);
|
const show_banner = ref(false);
|
||||||
const easteregg = ref("");
|
const easteregg = ref("");
|
||||||
|
|
||||||
const total_eastereggs = ref(getTotalEasterEggsCount());
|
const total_eastereggs = ref(getTotalEasterEggsCount());
|
||||||
const found_eastereggs = ref(getFoundEasterEggsCount());
|
const found_eastereggs = ref(0);
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
|
|
||||||
|
|
||||||
let current_dismiss_timeout:number|null = null;
|
onMounted(() => {
|
||||||
|
found_eastereggs.value = getFoundEasterEggsCount();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
let current_dismiss_timeout:NodeJS.Timeout|null = null;
|
||||||
|
|
||||||
function show(easteregg_name:string) {
|
function show(easteregg_name:string) {
|
||||||
easteregg.value = easteregg_name;
|
easteregg.value = easteregg_name;
|
||||||
16
components/easteregg-banner/eggs/CookieEgg.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="flex justify-center text-sm">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-10 h-10 flex items-center justify-center overflow-hidden">
|
||||||
|
<img src="~/assets/images/cookie.png" alt="" class="h-full w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 ml-2">
|
||||||
|
<p class="font-bold text-base">{{ $t("cookie.title") }}</p>
|
||||||
|
<p>{{ $t("cookie.description") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
16
components/easteregg-banner/eggs/FutureEgg.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="flex text-sm">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-10 h-10 flex items-center justify-center overflow-hidden">
|
||||||
|
<img src="~/assets/images/future.png" alt="" class="h-full w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 ml-2">
|
||||||
|
<p class="font-bold text-base">{{ $t("future.title") }}</p>
|
||||||
|
<p>{{ $t("future.description") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
25
components/easteregg-banner/eggs/PictureBrightEgg.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<ClientOnly>
|
||||||
|
<div class="flex text-sm">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-10 h-10 flex items-center justify-center overflow-hidden">
|
||||||
|
<img src="~/assets/images/sun.png" alt="" class="h-full w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 ml-2">
|
||||||
|
<p class="font-bold text-base">{{ $t("bright.title") }}</p>
|
||||||
|
<p v-if="!dark_unlocked">{{ $t("bright.description") }}</p>
|
||||||
|
<p v-if="dark_unlocked">{{ $t("bright_either.description") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const dark_unlocked = ref(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
dark_unlocked.value = getFoundEasterEggs().includes("picture-nolights");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
25
components/easteregg-banner/eggs/PictureNoLightEgg.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<ClientOnly>
|
||||||
|
<div class="flex text-sm">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-10 h-10 flex items-center justify-center overflow-hidden">
|
||||||
|
<img src="~/assets/images/moon.png" alt="" class="h-full w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 ml-2">
|
||||||
|
<p class="font-bold text-base">{{ $t("dark.title") }}</p>
|
||||||
|
<p v-if="!light_unlocked">{{ $t("dark.description") }}</p>
|
||||||
|
<p v-if="light_unlocked">{{ $t("dark_either.description") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const light_unlocked = ref(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
light_unlocked.value = getFoundEasterEggs().includes("picture-bright");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
16
components/easteregg-banner/eggs/SomethingEgg.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="flex text-sm">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-10 h-10 flex items-center justify-center overflow-hidden">
|
||||||
|
<img src="~/assets/images/sad.svg" alt="" class="h-full w-full dark:invert" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 ml-2">
|
||||||
|
<p class="font-bold text-base">{{ $t("something.title") }}</p>
|
||||||
|
<p>{{ $t("something.description") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
@ -1,22 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="props.to" :aria-current="is_active_page ? 'page' : null"
|
<NuxtLink :to="localePath(props.to)" :aria-current="is_active_page ? 'page' : null"
|
||||||
:class="`block py-2 md:p-0 text-right md:text-center
|
:class="`block py-2 md:p-0 text-right md:text-center
|
||||||
${is_active_page ? 'font-bold text-zinc-900 dark:text-zinc-400' : 'font-normal hover:underline text-gray-700 dark:text-slate-50'}`">
|
${is_active_page ? 'font-bold text-zinc-900 dark:text-zinc-400' : 'font-normal hover:underline text-gray-700 dark:text-slate-50'}`">
|
||||||
{{ props.label }}
|
{{ props.label }}
|
||||||
</router-link>
|
</NuxtLink>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
const localePath = useLocalePath()
|
||||||
const route = useRoute();
|
const router = useRouter();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
to: { type: String, required: true },
|
to: { type: String, required: true },
|
||||||
label: String
|
label: String
|
||||||
})
|
})
|
||||||
|
|
||||||
const is_active_page = ref(route.path === props.to);
|
let current_path = router.currentRoute.value.fullPath.replace(/\/$/, "");
|
||||||
|
if (current_path === "") { current_path = "/"; }
|
||||||
|
|
||||||
|
const is_active_page = ref(current_path === localePath(props.to) || current_path === props.to);
|
||||||
</script>
|
</script>
|
||||||
@ -4,14 +4,14 @@
|
|||||||
<div class="block md:flex w-full">
|
<div class="block md:flex w-full">
|
||||||
<div class="flex justify-end items-center order-2 md:w-1/2">
|
<div class="flex justify-end items-center order-2 md:w-1/2">
|
||||||
<a href="https://github.com/NotXia" class="rounded-full p-1 mx-1 hover:bg-slate-200 dark:hover:bg-slate-700">
|
<a href="https://github.com/NotXia" class="rounded-full p-1 mx-1 hover:bg-slate-200 dark:hover:bg-slate-700">
|
||||||
<img :src="github_icon" alt="Github" class="h-5 dark:invert" />
|
<img src="~/assets/images/icons/github.svg" alt="Github" class="h-5 dark:invert" />
|
||||||
</a>
|
</a>
|
||||||
<ThemeSwitch class="mx-1" />
|
<ThemeSwitch class="mx-1" />
|
||||||
<LanguageSelector class="mx-1" />
|
<LanguageSelector class="mx-1" />
|
||||||
|
|
||||||
<button class="inline-flex items-center mx-3 text-sm text-gray-500 md:hidden dark:text-gray-400"
|
<button class="inline-flex items-center mx-3 text-sm text-gray-500 md:hidden dark:text-gray-400"
|
||||||
data-collapse-toggle="navbar-main" type="button" aria-controls="navbar-main" aria-expanded="false">
|
data-collapse-toggle="navbar-main" type="button" aria-controls="navbar-main" aria-expanded="false">
|
||||||
<span class="sr-only">{{ t("open nav") }}</span>
|
<span class="sr-only">{{ $t("open nav") }}</span>
|
||||||
<svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
<path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
||||||
</svg>
|
</svg>
|
||||||
@ -21,11 +21,11 @@
|
|||||||
<div class="flex items-center order-1 md:w-full">
|
<div class="flex items-center order-1 md:w-full">
|
||||||
<div class="hidden w-full md:block md:w-auto" id="navbar-main">
|
<div class="hidden w-full md:block md:w-auto" id="navbar-main">
|
||||||
<ul class="flex flex-col py-4 pr-4 mt-0 md:flex-row md:space-x-8 md:text-sm md:font-medium bg-transparent">
|
<ul class="flex flex-col py-4 pr-4 mt-0 md:flex-row md:space-x-8 md:text-sm md:font-medium bg-transparent">
|
||||||
<NavLink to="/" :label="t('home')"/>
|
<NavLink to="/" :label="$t('home')"/>
|
||||||
<NavLink to="/about" :label="t('about')"/>
|
<NavLink to="/about" :label="$t('about')"/>
|
||||||
<NavLink to="/projects" :label="t('projects')"/>
|
<NavLink to="/projects" :label="$t('projects')"/>
|
||||||
<NavLink to="/resume" :label="t('resume')"/>
|
<NavLink to="/resume" :label="$t('resume')"/>
|
||||||
<NavLink to="/contacts" :label="t('contacts')"/>
|
<NavLink to="/contacts" :label="$t('contacts')"/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -36,18 +36,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import NavLink from "./NavLink.vue";
|
import NavLink from "./NavLink.vue"
|
||||||
import ThemeSwitch from "../theme-switch/ThemeSwitch.vue";
|
|
||||||
import LanguageSelector from "../language-selector/LanguageSelector.vue";
|
|
||||||
import { initCollapses } from "flowbite";
|
import { initCollapses } from "flowbite";
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import locale from "@/locales/navbar";
|
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
import github_icon from "@/assets/images/icons/github.svg";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initCollapses();
|
initCollapses();
|
||||||
})
|
})
|
||||||
21
components/projects/cards/AnimalHouse.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="Animal House" :image="image"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/animal-house' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_21-22") }}</p>
|
||||||
|
<p>{{ $t('animalhouse.description') }}</p>
|
||||||
|
<ul class="list-inside list-['-_']">
|
||||||
|
<li>{{ $t('animalhouse.description.game') }}</li>
|
||||||
|
<li>{{ $t('animalhouse.description.frontoffice') }}</li>
|
||||||
|
<li>{{ $t('animalhouse.description.backoffice') }}</li>
|
||||||
|
</ul>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import image from "@/assets/images/projects/animal-house.png";
|
||||||
|
</script>
|
||||||
16
components/projects/cards/Imaging.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="Image deblur" :image="image"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/imaging' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_21-22") }}</p>
|
||||||
|
<p>{{ $t('imaging.description') }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import image from "@/assets/images/projects/imaging.png";
|
||||||
|
</script>
|
||||||
16
components/projects/cards/MNKGame.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="MNK Game" :image="image"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/MNKGame' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_20-21") }}</p>
|
||||||
|
<p>{{ $t('mnk.description') }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import image from "@/assets/images/projects/mnkgame.png";
|
||||||
|
</script>
|
||||||
@ -5,7 +5,7 @@
|
|||||||
{ label: 'Repository', url: 'https://github.com/NotXia/notxia.github.io' },
|
{ label: 'Repository', url: 'https://github.com/NotXia/notxia.github.io' },
|
||||||
]">
|
]">
|
||||||
|
|
||||||
<p v-if="!show_recursive_message">{{ t('notxia.github.io.description') }}</p>
|
<p v-if="!show_recursive_message">{{ $t('notxia.github.io.description') }}</p>
|
||||||
|
|
||||||
<div class="w-full h-72 relative">
|
<div class="w-full h-72 relative">
|
||||||
<div role="status" v-if="!iframe_loaded && !show_recursive_message" class="absolute top-0 left-0 w-full h-full flex justify-center items-center">
|
<div role="status" v-if="!iframe_loaded && !show_recursive_message" class="absolute top-0 left-0 w-full h-full flex justify-center items-center">
|
||||||
@ -16,21 +16,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="show_recursive_message" class="flex justify-center items-center w-full h-full">
|
<div v-if="show_recursive_message" class="flex justify-center items-center w-full h-full">
|
||||||
<p>{{ t("no recursion") }}</p>
|
<p>{{ $t("no recursion") }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<iframe src="/" frameborder="0" width="100%" height="100%" @load="iframe_loaded = true"></iframe>
|
<iframe v-if="!show_recursive_message" src="/" frameborder="0" width="100%" height="100%" @load="iframe_loaded=true"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</ProjectCard>
|
</ProjectCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ProjectCard from "../ProjectCard.vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { ref, onMounted } from "vue";
|
|
||||||
import locale from "@/locales/projects";
|
|
||||||
|
|
||||||
const iframe_loaded = ref(false);
|
const iframe_loaded = ref(false);
|
||||||
const show_recursive_message = ref(false);
|
const show_recursive_message = ref(false);
|
||||||
|
|
||||||
@ -42,6 +37,4 @@
|
|||||||
}
|
}
|
||||||
catch (err) { show_recursive_message.value = false; }
|
catch (err) { show_recursive_message.value = false; }
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
</script>
|
</script>
|
||||||
11
components/projects/cards/PandOSplus.vue
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="PandOS+"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/pandos-plus' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_21-22") }}</p>
|
||||||
|
<p>{{ $t('pandos+.description') }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
@ -1,22 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
title="Pathfinding visualizer" :image="image"
|
title="Pathfinding visualizer" :image="image"
|
||||||
:description="t('description')"
|
|
||||||
:links="[
|
:links="[
|
||||||
{ label: 'Repository', url: 'https://github.com/NotXia/pathfinding-visualizer' },
|
{ label: 'Repository', url: 'https://github.com/NotXia/pathfinding-visualizer' },
|
||||||
{ label: 'Demo', url: 'https://notxia.github.io/pathfinding-visualizer/' }
|
{ label: 'Demo', url: 'https://notxia.github.io/pathfinding-visualizer/' }
|
||||||
]">
|
]">
|
||||||
|
|
||||||
{{ t('pathfinding_visualizer.description') }}
|
{{ $t('pathfinding_visualizer.description') }}
|
||||||
</ProjectCard>
|
</ProjectCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ProjectCard from "../ProjectCard.vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import image from "@/assets/images/projects/pathfinding-visualizer.png";
|
import image from "@/assets/images/projects/pathfinding-visualizer.png";
|
||||||
import locale from "@/locales/projects";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
</script>
|
</script>
|
||||||
16
components/projects/cards/Platform.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="Platform game" :image="image"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/platform-game' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_20-21") }}</p>
|
||||||
|
<p>{{ $t('platform.description') }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import image from "@/assets/images/projects/platform.png";
|
||||||
|
</script>
|
||||||
@ -1,22 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
title="Sorting visualizer" :image="image"
|
title="Sorting visualizer" :image="image"
|
||||||
:description="t('description')"
|
|
||||||
:links="[
|
:links="[
|
||||||
{ label: 'Repository', url: 'https://github.com/NotXia/sorting-visualizer' },
|
{ label: 'Repository', url: 'https://github.com/NotXia/sorting-visualizer' },
|
||||||
{ label: 'Demo', url: 'https://notxia.github.io/sorting-visualizer/' }
|
{ label: 'Demo', url: 'https://notxia.github.io/sorting-visualizer/' }
|
||||||
]">
|
]">
|
||||||
|
|
||||||
{{ t('sort_visualizer.description') }}
|
{{ $t('sort_visualizer.description') }}
|
||||||
</ProjectCard>
|
</ProjectCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ProjectCard from "../ProjectCard.vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import image from "@/assets/images/projects/sorting-visualizer.png";
|
import image from "@/assets/images/projects/sorting-visualizer.png";
|
||||||
import locale from "@/locales/projects";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
</script>
|
</script>
|
||||||
16
components/projects/cards/TweetAnalysis.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="Tweet Analysis" :image="image"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/tweet-analysis' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_22-23") }}</p>
|
||||||
|
<p>{{ $t('tweet_analysis.description') }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import image from "@/assets/images/projects/tweet-analysis.png";
|
||||||
|
</script>
|
||||||
12
components/projects/cards/Wirefilter.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<ProjectCard
|
||||||
|
title="Wirefilter"
|
||||||
|
:links="[
|
||||||
|
{ label: 'Repository', url: 'https://github.com/NotXia/vdeplug_wirefilter' },
|
||||||
|
{ label: 'VirtualSquare', url: 'http://wiki.virtualsquare.org/#!index.md' }
|
||||||
|
]">
|
||||||
|
|
||||||
|
<p class="text-center">{{ $t("unibo_22-23") }}</p>
|
||||||
|
<p>{{ $t("wirefilter.description") }}</p>
|
||||||
|
</ProjectCard>
|
||||||
|
</template>
|
||||||
@ -5,7 +5,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="tooltip-future" role="tooltip"
|
<div id="tooltip-future" role="tooltip"
|
||||||
class="absolute z-10 invisible inline-block px-2 py-1 text-xs font-medium transition-opacity duration-1000 rounded-lg opacity-0 tooltip">
|
class="absolute z-10 invisible inline-block px-2 py-1 text-xs font-medium transition-opacity duration-1000 rounded-lg opacity-0 tooltip">
|
||||||
{{ t("future") }}
|
{{ $t("future") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -13,19 +13,19 @@
|
|||||||
<Timeline
|
<Timeline
|
||||||
:right="[
|
:right="[
|
||||||
{
|
{
|
||||||
title: t('diploma'), time_label: '2015 - 2020',
|
title: $t('diploma'), time_label: '2015 - 2020',
|
||||||
description: t('aldini'),
|
description: $t('aldini'),
|
||||||
start: new Date(2015, september, 1), end: new Date(2020, june, 1)
|
start: new Date(2015, september, 1), end: new Date(2020, june, 1)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('bs in cs'), time_label: '2020 - 2023',
|
title: $t('bs in cs'), time_label: '2020 - 2023',
|
||||||
description: t('unibo'),
|
description: $t('unibo'),
|
||||||
start: new Date(2020, september, 1), end: new Date(), current: true
|
start: new Date(2020, september, 1), end: new Date(), current: true
|
||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
:left="[
|
:left="[
|
||||||
{
|
{
|
||||||
title: t('pcto toyota'), time_label: `${t('m_12')} 2019 | ${t('m_7')} 2019 | ${t('m_2')} 2019`,
|
title: $t('pcto toyota'), time_label: `${$t('m_12')} 2019 | ${$t('m_7')} 2019 | ${$t('m_2')} 2019`,
|
||||||
description: 'Toyota Material Handling Manufacturing Italy',
|
description: 'Toyota Material Handling Manufacturing Italy',
|
||||||
start: new Date(2019, february, 1), end: new Date(2019, december, 1)
|
start: new Date(2019, february, 1), end: new Date(2019, december, 1)
|
||||||
},
|
},
|
||||||
@ -42,19 +42,12 @@
|
|||||||
]" />
|
]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-center text-xs text-gray-400 dark:text-slate-600">{{ t("like timelines") }}</p>
|
<p class="text-center text-xs text-gray-400 dark:text-slate-600">{{ $t("like timelines") }}</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Timeline from "@/components/timeline/Timeline.vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { initTooltips } from "flowbite";
|
import { initTooltips } from "flowbite";
|
||||||
import { onMounted } from "vue";
|
|
||||||
import { addFoundEasterEgg } from "@/utilities/easteregg_handler";
|
|
||||||
import locale from "@/locales/resume";
|
|
||||||
|
|
||||||
const { t } = useI18n({ messages: locale });
|
|
||||||
|
|
||||||
const january = 0, february = 1, march = 2, april = 3, may = 4, june = 5, july = 6, august = 7, september = 8, october = 9, november = 10, december = 11;
|
const january = 0, february = 1, march = 2, april = 3, may = 4, june = 5, july = 6, august = 7, september = 8, october = 9, november = 10, december = 11;
|
||||||
|
|
||||||
@ -63,7 +56,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
let achievement_timer:number|null = null;
|
let achievement_timer:NodeJS.Timeout|null = null;
|
||||||
|
|
||||||
function startArchievementTimer() {
|
function startArchievementTimer() {
|
||||||
achievement_timer = setTimeout(() => {
|
achievement_timer = setTimeout(() => {
|
||||||