mirror of
https://github.com/NotXia/notxia.github.io.git
synced 2025-12-14 19:01:51 +01:00
Add about me section
This commit is contained in:
BIN
src/assets/images/moon.png
Normal file
BIN
src/assets/images/moon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
src/assets/images/profile/picture-bright.png
Normal file
BIN
src/assets/images/profile/picture-bright.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
BIN
src/assets/images/profile/picture-dark.png
Normal file
BIN
src/assets/images/profile/picture-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
BIN
src/assets/images/profile/picture-light.png
Normal file
BIN
src/assets/images/profile/picture-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
BIN
src/assets/images/profile/picture-nolight.png
Normal file
BIN
src/assets/images/profile/picture-nolight.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
BIN
src/assets/images/sun.png
Normal file
BIN
src/assets/images/sun.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
@ -48,14 +48,6 @@
|
||||
border-radius: 0.2rem;
|
||||
border: 1px solid #424242;
|
||||
}
|
||||
.gr_grid_book_container:first-child {
|
||||
margin-left: 0;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.gr_grid_book_container:last-child {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.gr_grid_book_container > * img {
|
||||
height: 100%;
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
<CookieEgg v-if="easteregg === 'cookie'" />
|
||||
<FutureEgg v-if="easteregg === 'future'" />
|
||||
<SomethingEgg v-if="easteregg === 'change-something'" />
|
||||
<PictureBrightEgg v-if="easteregg === 'picture-bright'" />
|
||||
<PictureNoLightEgg v-if="easteregg === 'picture-nolights'" />
|
||||
|
||||
<div class="mt-1 text-center">
|
||||
<p v-if="found_eastereggs != total_eastereggs">{{ found_eastereggs }}/{{ total_eastereggs }} {{ t("easter eggs found") }}</p>
|
||||
@ -31,6 +33,8 @@
|
||||
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";
|
||||
|
||||
const show_banner = ref(false);
|
||||
const easteregg = ref("");
|
||||
@ -41,7 +45,7 @@
|
||||
const { t } = useI18n({ messages: {
|
||||
"en": {
|
||||
"easter eggs found": "easter eggs found",
|
||||
"all easter eggs found": "You found all the easter eggs 🥚"
|
||||
"all easter eggs found": "You found all easter eggs 🥚"
|
||||
},
|
||||
"it": {
|
||||
"easter eggs found": "easter egg trovati",
|
||||
|
||||
40
src/components/easteregg-banner/eggs/PictureBright.vue
Normal file
40
src/components/easteregg-banner/eggs/PictureBright.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<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="image" alt="" class="h-full w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 ml-2">
|
||||
<p class="font-bold text-base">{{ t("title") }}</p>
|
||||
<p>{{ t("description") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import image from "@/assets/images/sun.png";
|
||||
import { getFoundEasterEggs } from "@/utilities/easteregg_handler";
|
||||
|
||||
let locale = {
|
||||
"en": {
|
||||
"title": "It's bright",
|
||||
"description": "I don't like the light"
|
||||
},
|
||||
"it": {
|
||||
"title": "È luminoso",
|
||||
"description": "Non mi piace la luce"
|
||||
}
|
||||
};
|
||||
|
||||
if (getFoundEasterEggs().includes("picture-nolights")) {
|
||||
locale["en"]["description"] = "I don't like the light either"
|
||||
locale["it"]["description"] = "Non mi piace nemmeno la luce"
|
||||
}
|
||||
|
||||
const { t } = useI18n({ messages: locale });
|
||||
</script>
|
||||
40
src/components/easteregg-banner/eggs/PictureNoLight.vue
Normal file
40
src/components/easteregg-banner/eggs/PictureNoLight.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<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="image" alt="" class="h-full w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 ml-2">
|
||||
<p class="font-bold text-base">{{ t("title") }}</p>
|
||||
<p>{{ t("description") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import image from "@/assets/images/moon.png";
|
||||
import { getFoundEasterEggs } from "@/utilities/easteregg_handler";
|
||||
|
||||
let locale = {
|
||||
"en": {
|
||||
"title": "It's dark",
|
||||
"description": "I don't like the dark"
|
||||
},
|
||||
"it": {
|
||||
"title": "È buio",
|
||||
"description": "Non mi piace il buio"
|
||||
}
|
||||
};
|
||||
|
||||
if (getFoundEasterEggs().includes("picture-bright")) {
|
||||
locale["en"]["description"] = "I don't like the dark either"
|
||||
locale["it"]["description"] = "Non mi piace nemmeno il buio"
|
||||
}
|
||||
|
||||
const { t } = useI18n({ messages: locale });
|
||||
</script>
|
||||
108
src/components/profile-picture/ProfilePicture.vue
Normal file
108
src/components/profile-picture/ProfilePicture.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
|
||||
<div class="relative">
|
||||
<div class="flex items-center h-60 w-60">
|
||||
<img v-show="picture === 'dark'" :src="picture_dark" alt="" class="max-h-full max-w-full">
|
||||
<img v-show="picture === 'light'" :src="picture_light" alt="" class="max-h-full max-w-full">
|
||||
<img v-show="picture === 'bright'" :src="picture_bright" alt="" class="max-h-full max-w-full">
|
||||
<img v-show="picture === 'no light'" :src="picture_nolight" 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">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { addFoundEasterEgg } from "@/utilities/easteregg_handler";
|
||||
import { useRoute } from "vue-router";
|
||||
import picture_dark from "@/assets/images/profile/picture-dark.png";
|
||||
import picture_light from "@/assets/images/profile/picture-light.png";
|
||||
import picture_bright from "@/assets/images/profile/picture-bright.png";
|
||||
import picture_nolight from "@/assets/images/profile/picture-nolight.png";
|
||||
|
||||
const { t, locale } = useI18n({ messages: {
|
||||
"en": {
|
||||
"that's bright": "That's bright",
|
||||
"better": "Better",
|
||||
"where lights": "Who turned off the lights?",
|
||||
"here lights": "Here they are"
|
||||
},
|
||||
"it": {
|
||||
"that's bright": "È luminoso",
|
||||
"better": "Meglio",
|
||||
"where lights": "Chi ha spento le luci?",
|
||||
"here lights": "Eccole"
|
||||
}
|
||||
} });
|
||||
|
||||
const picture = ref(picture_dark);
|
||||
const message = ref("picture_dark");
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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 = t(states[current_state]?.message);
|
||||
}
|
||||
|
||||
function nextState() {
|
||||
current_state = states[current_state]?.next;
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
applyState();
|
||||
|
||||
let observer = new MutationObserver(function(mutations) {
|
||||
if (route.path !== "/about") { observer.disconnect(); return; } // Disconnect observer if on other routes
|
||||
|
||||
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'] });
|
||||
});
|
||||
|
||||
watch(locale, () => { // To update the language of the displayed message
|
||||
applyState();
|
||||
});
|
||||
|
||||
</script>
|
||||
@ -1,4 +1,4 @@
|
||||
const EASTER_EGGS = ["cookie", "future", "change-something"];
|
||||
const EASTER_EGGS = ["cookie", "future", "change-something", "picture-bright", "picture-nolights"];
|
||||
|
||||
export function addFoundEasterEgg(name:string):void {
|
||||
if (!EASTER_EGGS.includes(name)) { return; }
|
||||
|
||||
@ -1,20 +1,124 @@
|
||||
<template>
|
||||
<Navbar />
|
||||
|
||||
<ScreenCenter>
|
||||
<main>
|
||||
<div class="container mx-auto">
|
||||
<h1 class="text-5xl font-bold">
|
||||
{{ t("hello") }}
|
||||
</h1>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:justify-between items-center h-full">
|
||||
<div class="text-xl order-2 md:order-1 [&>*>p]:mb-2">
|
||||
<h1 class="text-5xl font-bold mb-5">{{ t("about me") }}</h1>
|
||||
|
||||
<div v-show="current_locale === 'it'">
|
||||
<p>
|
||||
Mi chiamo
|
||||
<span data-popover-target="popover-name" class="underline decoration-dashed decoration-slate-900/70 dark:decoration-slate-50/70">Xia Tian Cheng</span>,
|
||||
spesso conosciuto come Xia (cognome) o Riccardo.
|
||||
Studio informatica all'Università di Bologna e al momento i miei interessi sono orientati verso l'analisi dati e l'intelligenza artificiale.
|
||||
</p>
|
||||
<p>
|
||||
Oltre a premere tasti sulla tastiera,
|
||||
mi piace leggere,
|
||||
sperimentare in cucina <span class="text-xs">(preferibilmente con un estintore nei paraggi)</span>
|
||||
e giocare a giochi strategici.
|
||||
</p>
|
||||
<p>
|
||||
Secondo <a class="hover:underline" href="https://www.16personalities.com">16Personalities</a> sono un
|
||||
<a class="font-mono hover:underline" href="https://www.16personalities.com/profiles/6b57f54bf1242">Architetto (INTJ)</a>.
|
||||
Devo dire che la descrizione è decisamente accurata.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-show="current_locale === 'en'">
|
||||
<p>
|
||||
My name is
|
||||
<span data-popover-target="popover-name" class="underline decoration-dashed decoration-slate-900/70 dark:decoration-slate-50/70">Xia Tian Cheng</span>,
|
||||
frequently known as Xia (surname) or Richard.
|
||||
I am a computer science student at the University of Bologna and currently my interests are focused on data analysis and artificial intelligence.
|
||||
</p>
|
||||
<p>
|
||||
Aside from pressing keys on a keyboard,
|
||||
I like reading,
|
||||
cooking <span class="text-xs">(preferably with a fire extinguisher nearby)</span>
|
||||
and playing strategic games.
|
||||
</p>
|
||||
<p>
|
||||
According to <a class="hover:underline" href="https://www.16personalities.com">16Personalities</a> I'm an
|
||||
<a class="font-mono hover:underline" href="https://www.16personalities.com/profiles/6b57f54bf1242">Architect (INTJ)</a>.
|
||||
I must admit that the description is quiet accurate.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="order-1 mb-3 ml-0 md:order-2 md:mb-0 md:ml-10">
|
||||
<ProfilePicture />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<p class="text-center text-xl">{{ t("reading") }}</p>
|
||||
<div class="flex justify-center">
|
||||
<Goodreads class="h-48"/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</ScreenCenter>
|
||||
|
||||
<div data-popover id="popover-name" role="tooltip" class="absolute z-10 invisible inline-block transition-opacity duration-500 opacity-0">
|
||||
<div class="text-lg px-3 py-2 bg-slate-200 dark:bg-slate-800 rounded">
|
||||
夏天成
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import Navbar from "@/components/navbar/Navbar.vue";
|
||||
import Goodreads from "@/components/goodreads/Goodreads.vue";
|
||||
import ScreenCenter from "@/components/screen-center/ScreenCenter.vue";
|
||||
import ProfilePicture from "@/components/profile-picture/ProfilePicture.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import locale from "./locale.json";
|
||||
import { type ComputedRef, computed, onMounted, watch, ref } from "vue";
|
||||
import { initPopovers } from "flowbite";
|
||||
|
||||
const { t } = useI18n({ messages: locale });
|
||||
const { t, locale } = useI18n({ messages: {
|
||||
"en": {
|
||||
"about me": "About me",
|
||||
"reading": "Currently I'm reading",
|
||||
|
||||
"that's bright": "That's bright",
|
||||
"thanks": "Thanks"
|
||||
},
|
||||
"it": {
|
||||
"about me": "Su di me",
|
||||
"reading": "Attualmente sto leggendo",
|
||||
|
||||
"that's bright": "È luminoso",
|
||||
"thanks": "Grazie"
|
||||
}
|
||||
} });
|
||||
|
||||
const current_locale = ref(locale.value);
|
||||
|
||||
|
||||
const my_age: ComputedRef<number> = computed((): number => {
|
||||
const today = new Date();
|
||||
const birthDate = new Date(2001, 8, 29);
|
||||
const month_diff = today.getMonth() - birthDate.getMonth();
|
||||
let age = today.getFullYear() - birthDate.getFullYear();
|
||||
if (month_diff < 0 ||
|
||||
(month_diff === 0 && today.getDate() < birthDate.getDate())) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
initPopovers();
|
||||
});
|
||||
|
||||
watch(locale, () => {
|
||||
current_locale.value = locale.value;
|
||||
});
|
||||
</script>
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"en": {
|
||||
"hello": "Hello"
|
||||
},
|
||||
"it": {
|
||||
"hello": "Ciao"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user