Compare commits

..

3 commits

Author SHA1 Message Date
a7df408049 create facts section & by the way reengineer the IntersectionObserver function 2025-10-15 21:32:26 +02:00
7e6957ce7e add missing image 2025-08-22 21:17:03 +02:00
1c1fd4eaf2
Change details about apprenticeship (about section) (#2)
* begin pagescms implementation

* fix wrong path of hugo.toml

* test if params must be one object

* add languages + selection for pagetype

* change list type

* experiment with languages type

* move languages in own content type

* add tags & social media

* add content type

* implement hero section seperatly

* implement one language

* fix typo

* try more qualified name for language parameters

* remove language for the moment until better support available in pagescms

* Update content/de/about.md (via Pages CMS)

* Update content/en/about.md (via Pages CMS)
2025-08-22 21:13:38 +02:00
13 changed files with 189 additions and 30 deletions

View file

@ -78,6 +78,10 @@ content:
- name: websiteId - name: websiteId
label: Umami Website ID label: Umami Website ID
type: string type: string
- name: factsUrl
label: Facts JSON URL
description: URL to fetch facts data from
type: string
- name: socialmedia - name: socialmedia
label: Social Media label: Social Media

View file

@ -1,13 +1,14 @@
--- ---
title: "Über mich" title: Über mich
slug: "about" slug: about
image: "/assets/about-me/about-me.webp" image: "/assets/about-me/about-me.webp"
--- ---
Hallo! Ich heisse Michi und interessiere mich für Smartphones, Computer, Elektromobilität und weitere spannende Technik.
Hallo! Ich heisse Michi und interessiere mich für Smartphones, Computer, Elektromobilität (hauptsächlich Tesla) und weitere spannende Technik. * {{< age "16,09,2005" >}} Jahre alt
* Informatiker EFZ Plattformentwicklung
- {{< age "16,09,2005" >}} Jahre alt
- Informatiker Plattformentwicklung i.A.
Meine Freizeit verbringe ich gerne am Computer. Dort programmiere ich entweder kleine Dinge für mich ([siehe GitHub](https://github.com/michivonah)), wie diese Website, oder hoste neue Software auf meiner Infrastruktur. Ebenfalls gehe ich gerne Spazieren und höre dabei Musik oder Podcasts zu. Zudem bin ich ein grosser Fan des Europa-Park und besuche diesen regelmässig. Um meinen Tag dort optimal zu gestalten, habe ich sogar einen Bot gebaut, welchen mich jeweils per Push-Benachrichtung auf mein Smartphone über die aktuellen Wartezeiten informiert ([hier die Details auf GitHub](https://github.com/michivonah/themepark-alerts)). Ausserdem fliege ich gerne mit meiner Drohne oder mache Fotos mit meinem Smartphone. Und manchmal backe ich auch einen Kuchen. Meine Freizeit verbringe ich gerne am Computer. Dort programmiere ich entweder kleine Dinge für mich ([siehe GitHub](https://github.com/michivonah)), wie diese Website, oder hoste neue Software auf meiner Infrastruktur. Ebenfalls gehe ich gerne Spazieren und höre dabei Musik oder Podcasts zu. Zudem bin ich ein grosser Fan des Europa-Park und besuche diesen regelmässig. Um meinen Tag dort optimal zu gestalten, habe ich sogar einen Bot gebaut, welchen mich jeweils per Push-Benachrichtung auf mein Smartphone über die aktuellen Wartezeiten informiert ([hier die Details auf GitHub](https://github.com/michivonah/themepark-alerts)). Ausserdem fliege ich gerne mit meiner Drohne oder mache Fotos mit meinem Smartphone. Und manchmal backe ich auch einen Kuchen.

6
content/de/facts.md Normal file
View file

@ -0,0 +1,6 @@
---
title: "Fakten"
slug: "facts"
---
Einige Fakten über mich...

View file

@ -1,13 +1,14 @@
--- ---
title: "About me" title: About me
slug: "about" slug: about
image: "/assets/about-me/about-me.webp" image: "/assets/about-me/about-me.webp"
--- ---
Hi! My name is Michi and I'm interested in smartphones, computers, e-mobility and other exciting technology.
Hi! My name is Michi and I'm interested in smartphones, computers, e-mobility (mainly Tesla) and other exciting technology. * {{< age "16,09,2005" >}} years old
* Completed apprenticeship as Informatiker EFZ Plattformentwicklung with grade 5.7
- {{< age "16,09,2005" >}} years old
- Trainee computer scientist (Informatiker Plattformentwicklung)
I like to spend my free time at the computer. I either code little things for myself ([see GitHub](https://github.com/michivonah)), like this website, or host new software on my infrastructure. I also enjoy going for walks and listening to music or podcasts. I'm also a big fan of Europa-Park and visit it regularly. To optimise my day there, I even built a bot that informs me about the current waiting times via push notification on my smartphone ([here are the details on GitHub](https://github.com/michivonah/themepark-alerts)). I also like to fly my drone or take photos with my smartphone. And sometimes I bake a cake. I like to spend my free time at the computer. I either code little things for myself ([see GitHub](https://github.com/michivonah)), like this website, or host new software on my infrastructure. I also enjoy going for walks and listening to music or podcasts. I'm also a big fan of Europa-Park and visit it regularly. To optimise my day there, I even built a bot that informs me about the current waiting times via push notification on my smartphone ([here are the details on GitHub](https://github.com/michivonah/themepark-alerts)). I also like to fly my drone or take photos with my smartphone. And sometimes I bake a cake.

6
content/en/facts.md Normal file
View file

@ -0,0 +1,6 @@
---
title: "Facts"
slug: "facts"
---
Some facts about me...

View file

@ -99,3 +99,4 @@ defaultContentLanguage = 'de'
twitterUsername = "@michivonah" twitterUsername = "@michivonah"
umamiUrl = "https://data.mchvnh.ch/script.js" umamiUrl = "https://data.mchvnh.ch/script.js"
websiteId = "9b188ed8-77b0-4238-aef5-c1b3d48106e4" websiteId = "9b188ed8-77b0-4238-aef5-c1b3d48106e4"
factsUrl = "https://cdn.michivonah.ch/facts.json"

View file

@ -16,3 +16,4 @@ no-more-projects = 'Keine weiteren Projekte verfügbar'
faq = 'Häufige Fragen' faq = 'Häufige Fragen'
faq-short = 'FAQ' faq-short = 'FAQ'
close = 'Schliessen' close = 'Schliessen'
facts = 'Fakten'

View file

@ -16,3 +16,4 @@ no-more-projects = 'No more projects available'
faq = 'Frequently Asked Questions' faq = 'Frequently Asked Questions'
faq-short = 'FAQ' faq-short = 'FAQ'
close = 'Close' close = 'Close'
facts = 'Facts'

View file

@ -13,6 +13,8 @@
{{ partial "projects.html" . }} {{ partial "projects.html" . }}
{{ partial "facts.html" . }}
{{ partial "faq.html" . }} {{ partial "faq.html" . }}
</div> </div>

View file

@ -0,0 +1,34 @@
<div id="facts" class="facts">
<div class="facts-intro fade-up">
{{ with .Site.GetPage "facts" }}
<h1>{{ .Title }}</h1>
<p>{{ .Content }}</p>
{{ end }}
</div>
<div class="fact-container">
{{ $url := .Site.Params.factsUrl }}
{{ with try (resources.GetRemote $url) }}
{{ with .Err }}
{{ errorf "%s" . }}
{{ else with .Value }}
{{ $facts := . | transform.Unmarshal }}
{{ if $facts }}
{{ range $fact := $facts }}
{{ $count := 0 }}
{{ if isset $fact "total" }}
{{ $count = $fact.total }}
{{ else if isset $fact "items" }}
{{ $count = len $fact.items }}
{{ end }}
<div class="fact fade-up">
<p class="fact-counter" data-count="{{ $count }}"></p>
<p>{{ index $fact.titles $.Lang }}</p>
</div>
{{ end }}
{{ else }}
{{ errorf "Unable to get remote resource %q" $url }}
{{ end }}
{{ end }}
{{ end }}
</div>
</div>

View file

@ -5,6 +5,7 @@
<a href="#" alt='{{ T "home" }}'>{{ T "home" }}</a> <a href="#" alt='{{ T "home" }}'>{{ T "home" }}</a>
<a href="#about" alt='{{ T "about" }}'>{{ T "about" }}</a> <a href="#about" alt='{{ T "about" }}'>{{ T "about" }}</a>
<a href="#projects" alt='{{ T "projects" }}'>{{ T "projects" }}</a> <a href="#projects" alt='{{ T "projects" }}'>{{ T "projects" }}</a>
<a href="#facts" alt='{{ T "facts" }}'>{{ T "facts" }}</a>
<a href="#faq" alt='{{ T "faq-short" }}'>{{ T "faq-short" }}</a> <a href="#faq" alt='{{ T "faq-short" }}'>{{ T "faq-short" }}</a>
<a href="https://blog.michivonah.ch" alt='{{ T "blog" }}'>{{ T "blog" }}</a> <a href="https://blog.michivonah.ch" alt='{{ T "blog" }}'>{{ T "blog" }}</a>
<a href="#contact" alt='{{ T "contact" }}'>{{ T "contact" }}</a> <a href="#contact" alt='{{ T "contact" }}'>{{ T "contact" }}</a>

View file

@ -100,29 +100,65 @@ function updateNavStyle(){
document.querySelector("nav").classList.toggle("small", window.scrollY > 20); document.querySelector("nav").classList.toggle("small", window.scrollY > 20);
} }
// intersection observer for animations /**
// credits: https://coolcssanimation.com/how-to-trigger-a-css-animation-on-scroll/ * Template for easily creating a IntersectionObserver
* @param {*} triggerElement Element which triggers the IntersectionObserver
* @param {*} callback Function which gets interesction object back
* @param {*} rootMargin Parameter rootMargin of the IntersectionObserver
* @param {*} threshold Parameter threshold of the IntersectionObserver
* @returns IntersectionObserver
*/
function createIntersectionObserver(triggerElement, callback, rootMargin = '0px 0px 5% 0px', threshold = 0.1){
if(triggerElement){
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
callback(entry);
});
}, { rootMargin, threshold });
return observer.observe(triggerElement);
}
}
/**
* Function which applies an IntersectionObserver
* for running animations on scroll/visibility of a container.
*
* Original inspiration: https://coolcssanimation.com/how-to-trigger-a-css-animation-on-scroll/
* @param {*} triggerSelector Query selector of the element, which should trigger the animation
* @param {*} animationClass Class to append when animation is triggered
* @param {*} targetElement Element to apply the animation (css class) to. Will applied to triggerSelector if not defined.
* @returns IntersectionObserver
*/
function animationOnScroll(triggerSelector, animationClass, targetElement){ function animationOnScroll(triggerSelector, animationClass, targetElement){
const trigger = document.querySelector(triggerSelector); const trigger = document.querySelector(triggerSelector);
const target = ((targetElement) ? document.querySelector(targetElement) : trigger); const target = ((targetElement) ? document.querySelector(targetElement) : trigger);
if(trigger){ return createIntersectionObserver(trigger, (entry) => {
const observer = new IntersectionObserver(entries => { entry.isIntersecting ? target.classList.add(animationClass) : target.classList.remove(animationClass);
entries.forEach(entry => { });
if (entry.isIntersecting) {
target.classList.add(animationClass);
}
else{
target.classList.remove(animationClass);
}
});
}, { rootMargin: '0px 0px 5% 0px', threshold: 0.1 });
return observer.observe(trigger);
}
} }
/**
* Creates IntersectionObserver for triggering counter animation
* @param {*} elementSelector Selector of the element(s) to apply the counter effect to
* @param {*} cssPropertyName CSS Property with counter's value
* @param {*} valueAttribute HTML data attribute with the counter's final value
*/
function countOnScroll(elementSelector, cssPropertyName, valueAttribute){
const items = document.querySelectorAll(elementSelector);
items.forEach(element => {
const value = parseInt(element.getAttribute(valueAttribute));
createIntersectionObserver(element, (entry) => {
element.style.setProperty(cssPropertyName, entry.isIntersecting ? value : 0);
});
});
}
// apply on scroll effects
animationOnScroll('.contact-title-wrapper', 'typewriter-animation', '.contact-title'); animationOnScroll('.contact-title-wrapper', 'typewriter-animation', '.contact-title');
countOnScroll('.fact-counter', '--factCounter', 'data-count');
// calculate age // calculate age
function calculateAge(selector){ function calculateAge(selector){

View file

@ -777,6 +777,71 @@ nav.small .nav-links a:last-child:focus{
} }
} }
/* FACTS */
.facts{
margin-top: 30px;
padding-bottom: 20px;
text-align: center;
scroll-margin-top: calc(var(--navSmallHeight) + 10px);
}
.fact-container{
display: flex;
flex-direction: row;
justify-content: space-around;
}
.fact{
display: flex;
flex-direction: column;
font-size: 1.2rem;
font-weight: 600;
width: 100%;
padding-block: 40px 20px;
}
.fact p{
margin: 5px 0;
padding: 0;
}
@media screen and (max-width:690px){
.fact-container{
flex-direction: column;
}
.fact{
padding-block: 10px;
}
}
@property --factCounter{
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.fact-counter{
font-size: 3.8rem;
font-weight: 700;
color: var(--primary);
transition: --factCounter 1s, var(--baseTransition);
counter-reset: factCounter var(--factCounter);
}
@media (pointer: fine){
.fact-counter:hover,
.fact-counter:focus{
transform: scale(1.1);
transition: var(--baseTransition);
filter: drop-shadow(0 0 0.6rem var(--primary));
}
}
.fact-counter::after{
content: counter(factCounter);
}
/* FAQ */ /* FAQ */
.faq{ .faq{
padding-block: 40px; padding-block: 40px;