diff --git a/.pugrc b/.pugrc index 611be22..5a39ffc 100644 --- a/.pugrc +++ b/.pugrc @@ -45,6 +45,7 @@ "email": ["hello", "at", "dailysh.it"], "name": "Michael W. Czechowski", "logoSvg": "./src/assets/nls.svg", + "logoSvgInverted": "./src/assets/nls_inverted.svg", "emojiSvg": "./src/assets/waving-hand.svg", "jobTitle": ["Enterprise Software Architect", "Digital Transformation Expert"] }, @@ -129,7 +130,7 @@ ], "sectionTitles": { "computerScience": "Computer Science", - "expertise": "Software Architecture and Development" + "expertise": "Software Architect­ure and Develop­ment" }, "courseInstitutions": { "dhbw": "Duale Hochschule Baden-Württemberg (DHBW)", @@ -1164,7 +1165,7 @@ "ariaLabel": "The twelve-factor methodology can be applied to apps written in any programming language, and which use any combination of backing services (database, queue, memory cache, etc).", "text": "The 12-Factor App" }, - "text": " Microservices and Software-as-a-Service Methodology" + "text": "Microservices and Software-as-a-Service Methodology" }, { "text": "Testing Pyramid" diff --git a/index.pug b/index.pug index b3be88e..038fca9 100644 --- a/index.pug +++ b/index.pug @@ -32,12 +32,15 @@ html.scroll-smooth(lang=lang) }); sections.forEach((section) => sectionObserver(section.id).observe(section)); - let yearsOfAge = 0; - let yearsOfDeveloping = 0; + // tailwindcss set correct dark/light theme depending on client preference + // https://tailwindcss.com/docs/dark-mode#toggling-dark-mode - setInterval(() => { - yearsOfAge = (new Date().getTime() - new Date("1988-10-07").getTime()) / 1000 / 60 / 60 / 24 / 365.25; - yearsOfDeveloping = (new Date().getTime() - new Date("2005-07-07").getTime()) / 1000 / 60 / 60 / 24 / 365.25; - document.getElementById("yearsOfAge").innerText = yearsOfAge.toFixed(6); - document.getElementById("yearsOfDeveloping").innerText = yearsOfDeveloping.toFixed(6); - }, 500); + // let yearsOfAge = 0; + // let yearsOfDeveloping = 0; + // + // setInterval(() => { + // yearsOfAge = (new Date().getTime() - new Date("1988-10-07").getTime()) / 1000 / 60 / 60 / 24 / 365.25; + // yearsOfDeveloping = (new Date().getTime() - new Date("2005-07-07").getTime()) / 1000 / 60 / 60 / 24 / 365.25; + // document.getElementById("yearsOfAge").innerText = yearsOfAge.toFixed(6); + // document.getElementById("yearsOfDeveloping").innerText = yearsOfDeveloping.toFixed(6); + // }, 500); diff --git a/src/assets/CV_2024_Michael-Werner-Czechowski_de.pdf b/src/assets/CV_2024_Michael-Werner-Czechowski_de.pdf new file mode 100644 index 0000000..4a9a594 Binary files /dev/null and b/src/assets/CV_2024_Michael-Werner-Czechowski_de.pdf differ diff --git a/src/assets/nls.svg b/src/assets/nls.svg index f5bc8b3..59068dd 100644 --- a/src/assets/nls.svg +++ b/src/assets/nls.svg @@ -1,1225 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/nls_inverted.svg b/src/assets/nls_inverted.svg new file mode 100644 index 0000000..6f4b332 --- /dev/null +++ b/src/assets/nls_inverted.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Academia.pug b/src/components/Academia.pug index 18933fa..27a38ed 100644 --- a/src/components/Academia.pug +++ b/src/components/Academia.pug @@ -2,15 +2,15 @@ include Collapsable include Title include Container -section#academia.bg-nls-black.text-white - .p-8(class="sm:p-20 min-h-[120vh]") +section#academia + .p-8.bg-white.text-nls-black(class="dark:bg-nls-black dark:text-white sm:p-20 min-h-[120vh]") +Container // region Skills - +Title("h2")= academia.sectionTitles.expertise + +Title("h2") !{academia.sectionTitles.expertise} .mb-8.max-w-prose each paragraph, i in academia.expertise.intro - - const additionalClasses = i !== 0 ? "indent-3" : "mb-2 font-serif leading-widest sm:text-md text-sm tracking-tight w-5/6 text-white"; - p.text-slate-200(class=`hover:text-white transition ${additionalClasses}`) !{paragraph} + - const additionalClasses = i !== 0 ? "indent-3" : "mb-2 font-serif leading-widest sm:text-md text-sm tracking-tight w-5/6"; + p(class=`text-slate-700 dark:text-slate-300 ${additionalClasses}`) !{paragraph} // endregion // region Expertise @@ -31,15 +31,15 @@ section#academia.bg-nls-black.text-white .mb-8.max-w-prose.prose(class="lg:prose-xl") each paragraph, i in academia.intro - const additionalClasses = i !== 0 ? "indent-3" : "mb-2 font-serif leading-widest sm:text-md text-sm tracking-tight w-5/6 text-white"; - p.text-slate-200(class=`hover:text-white transition ${additionalClasses}`) !{paragraph} + p.text-slate-700(class=`dark:text-slate-300 ${additionalClasses}`) !{paragraph} // endregion // region Courses .grid.grid-cols-1.gap-6.mb-8(class="md:grid-cols-1") div details.mb-4 - summary.rounded-sm.text-white.transition.underline-offset-2.mb-2.cursor-pointer( - class="focus:outline-none focus:z-10 focus:ring-4 focus:ring-white focus:bg-white focus:text-black focus:no-underline", + summary.rounded-sm.text-nls-black.transition.underline-offset-2.mb-2.cursor-pointer( + class="dark:text-white focus:outline-none focus:z-10 focus:ring-4 focus:ring-nls-black dark:focus:ring-white focus:bg-nls-black focus:text-white dark:focus:bg-white dark:focus:text-nls-black focus:no-underline", onclick="umami.track('collapsable clicked', { category: 'courses dhbw', visitDuration: getVisitDuration() })" )= academia.courseInstitutions.dhbw ul.list-disc.list-inside @@ -47,8 +47,8 @@ section#academia.bg-nls-black.text-white li= course div details.mb-4 - summary.rounded-sm.text-white.transition.underline-offset-2.mb-2.cursor-pointer( - class="focus:outline-none focus:z-10 focus:ring-4 focus:ring-white focus:bg-white focus:text-black focus:no-underline", + summary.rounded-sm.text-md.text-nls-black.transition.underline-offset-2.mb-2.cursor-pointer( + class="sm:text-lg dark:text-white focus:outline-none focus:z-10 focus:ring-4 focus:ring-nls-black dark:focus:ring-white focus:bg-nls-black focus:text-white dark:focus:bg-white dark:focus:text-nls-black focus:no-underline", onclick="umami.track('collapsable clicked', { category: 'courses leibniz-fh', visitDuration: getVisitDuration() })" )= academia.courseInstitutions.lfh ul.list-disc.list-inside diff --git a/src/components/Collapsable.pug b/src/components/Collapsable.pug index 3018203..a342b6c 100644 --- a/src/components/Collapsable.pug +++ b/src/components/Collapsable.pug @@ -6,11 +6,11 @@ mixin Collapsable(data, open) div details.mb-4(open=isExpanded) - summary.rounded-sm.transition.mb-2.cursor-pointer.text-md.font-semibold.mb-2.cursor-pointer( - class=`sm:text-lg text-nls-${color} focus:outline-none focus:z-10 focus:ring-4 focus:ring-nls-${color} focus:bg-nls-${color} focus:text-black focus:no-underline`, + summary( + class=`rounded-sm transition mb-2 cursor-pointer text-md font-semibold mb-2 cursor-pointer sm:text-lg text-nls-${color} dark:text-nls-${color} focus:outline-none focus:z-10 focus:ring-4 focus:ring-nls-${color} focus:bg-nls-${color} focus:text-black focus:no-underline`, onclick=`umami.track('collapsable clicked', { category: '${category}', visitDuration: getVisitDuration() })` )= data.summary - ul.list-disc.list-inside.text-stone-300 + ul.list-disc.list-inside.text-slate-600(class="dark:text-stone-300") if data.items each item in data.items li @@ -18,15 +18,15 @@ mixin Collapsable(data, open) = item.text if item.links each link, index in item.links - a.transition.underline-offset-2.underline( - class=`text-nls-${color} hover:text-white hover:decoration-2`, + a( + class=`transition underline-offset-2 underline text-nls-${color} hover:text-nls-black dark:hover:text-white hover:decoration-2`, href=link.url, title=link.description, target="_blank", aria-label=link.description, rel="noopener noreferrer", onclick=`umami.track('${linkEventName}', { category: '${category}', position: 'collapsable', label: '${link.label}', visitDuration: getVisitDuration() })` - )= link.text + ) #{link.text} if index < item.links.length - 1 | ,  if item.suffix diff --git a/src/components/Footer.pug b/src/components/Footer.pug index 6552364..6684173 100644 --- a/src/components/Footer.pug +++ b/src/components/Footer.pug @@ -5,15 +5,15 @@ mixin Link(href, label, target, rel) - const eventCategory = "footer"; - const onclick = `umami.track('${eventName}', { category: 'icons', position: 'footer', label: '${label}', visitDuration: getVisitDuration() })`; - a.transition-colors.text-white(href=href, class="hover:text-amber-300", target=target, rel=rel, onclick=onclick) + a.transition-colors.text-nls-black(href=href, class="dark:text-white hover:text-amber-300", target=target, rel=rel, onclick=onclick) block mixin Svg svg.w-24.h-24(class="sm:w-8 sm:h-8", aria-hidden="true", fill="currentColor", viewbox="0 0 24 24") block -footer#footer.bg-nls-black.text-white - .p-8(class="sm:p-20 min-h-[120vh]") +footer#footer + .p-8.bg-white.text-nls-black(class="dark:bg-nls-black dark:text-white sm:p-20 min-h-[120vh]") +Container // region Contact h2.text-5xl.mb-4 #{footer.title} @@ -44,14 +44,14 @@ footer#footer.bg-nls-black.text-white style="fill: currentColor" ) - a.transition-colors.text-white.uppercase.font-semibold( + a.transition-colors.text-nls-black.uppercase.font-semibold( href=footer.emailLink, - class="hover:text-amber-300", + class="dark:text-white hover:text-amber-300", rel="noopener noreferrer", onclick="umami.track('email clicked', { position: 'footer', visitDuration: getVisitDuration() })" ) #{footer.emailText} - +Link("./src/assets/CV_2019_Michael-Werner-Czechowski_en.pdf", "CV", "_blank", "noopener noreferrer") + +Link("./src/assets/CV_2024_Michael-Werner-Czechowski_de.pdf", "CV", "_blank", "noopener noreferrer") | CV +Link("https://git.dailysh.it/nextlevelshit/dailysh.it", "gitea", "_blank", "noopener noreferrer")= footer.gitea diff --git a/src/components/Head.pug b/src/components/Head.pug index d6157f6..dc0904c 100644 --- a/src/components/Head.pug +++ b/src/components/Head.pug @@ -51,6 +51,7 @@ head script(src="https://cdn.tailwindcss.com") script. tailwind.config = { + darkMode: "media", theme: { fontFamily: { mono: ["Roboto Mono", "monospace"], @@ -146,3 +147,26 @@ head const getVisitDuration = () => { return Math.floor((Date.now() - window.visitDuration) / 1000); }; + + // Check for saved user preference, if any, on load of the website + const darkMode = localStorage.getItem("darkMode"); + + // If no preference is set, check system preference + if (darkMode === null) { + if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + document.documentElement.classList.add("dark"); + localStorage.setItem("darkMode", "dark"); + } + } else if (darkMode === "dark") { + document.documentElement.classList.add("dark"); + } + + function toggleDarkMode() { + if (document.documentElement.classList.contains("dark")) { + document.documentElement.classList.remove("dark"); + localStorage.setItem("darkMode", "light"); + } else { + document.documentElement.classList.add("dark"); + localStorage.setItem("darkMode", "dark"); + } + } diff --git a/src/components/Landingpage.pug b/src/components/Landingpage.pug index e0c4fb4..1ccc045 100644 --- a/src/components/Landingpage.pug +++ b/src/components/Landingpage.pug @@ -1,13 +1,16 @@ -header.bg-nls-black.text-white +header.bg-white.text-nls-black(class="dark:text-white dark:bg-nls-black") + //button.absolute.top-0.right-0.w-8.h-8.m-3.p-3.rounded-full.bg-slate-300( + // onclick="toggleDarkMode()" + //) + // div(class="block dark:hidden") + // span.sr-only Toggle dark mode + // | 🌙 + // div(class="hidden dark:block") + // span.sr-only Toggle light mode + // | ☀️ + .teaser.p-8.flex.flex-col.items-center.justify-center(class="sm:p-20") .max-w-3xl.mb-8.relative(class="w-4/5 min-h-[90vh]") - img.absolute.z-10.left-0.right-0.mx-auto.opacity-0.transition( - class="top-[30vh] max-h-[37vh] peer-hover:opacity-100 peer-hover:scale-150", - src=landingpage.emojiSvg - ) - - img.absolute.z-0.left-0.right-0.mx-auto.transition(class="h-[54vh] peer-hover:opacity-60 peer-hover:scale-50", src=landingpage.logoSvg) - .peer.absolute.bottom-0.left-0.right-0.z-40.text-center.max-w-3xl.center.py-8 h2.tracking-widest.text-xl.font-semibold.opacity-80.transition(class="sm:text-2xl peer-hover:opacity-100", itemprop="name")= landingpage.name @@ -17,24 +20,12 @@ header.bg-nls-black.text-white wbr | | & #{landingpage.jobTitle[1]} - a.group.text-2xl.mt-8( - class="sm:text-5xl sm:mt-16", - onclick="umami.track('email clicked', { position: 'title', visitDuration: getVisitDuration() })", - onmouseover="umami.track('email hovered', { position: 'title', visitDuration: getVisitDuration() })", - href=footer.emailLink, - rel="noopener noreferrer", - itemprop="email" - ) - .whitespace-nowrap.items-center.transition(class="group-hover:opacity-100") - span(class="group-hover:opacity-100") #{landingpage.email[0]} - span.opacity-20 – - span.opacity-90(class="group-hover:opacity-20") #{landingpage.email[1]} - span.opacity-20 – - span.opacity-90(class="group-hover:opacity-20") #{landingpage.email[2]} - .hidden - | Years of age: - span#yearsOfAge - | - | | - | Years of developing: - span#yearsOfDeveloping + + //img.absolute.z-10.left-0.right-0.mx-auto.opacity-0.transition( + // class="top-[30vh] max-h-[37vh] peer-hover:opacity-100 peer-hover:scale-150", + // src=landingpage.emojiSvg + //) + + img.absolute.z-0.left-0.right-0.mx-auto.transition.invisible(class="dark:visible h-[54vh]", src=landingpage.logoSvg) + + img.absolute.z-0.left-0.right-0.mx-auto.transition.visible(class="dark:invisible h-[54vh]", src=landingpage.logoSvgInverted) diff --git a/src/components/Professional.pug b/src/components/Professional.pug index 4042518..b6dca8b 100644 --- a/src/components/Professional.pug +++ b/src/components/Professional.pug @@ -1,18 +1,14 @@ -include Collapsable -include Title -include Container - -section#professional.bg-nls-black.text-white +section#professional.bg-white.text-nls-black(class="dark:bg-nls-black dark:text-white") .p-8(class="sm:p-20 min-h-[120vh]") +Container +Title("h2")= professional.title - p.mb-4.max-w-prose.prose.indent-3(class="lg:prose-xl") + p.mb-4.max-w-prose.prose.indent-3(class="lg:prose-xl dark:prose-invert") | #{professional.description} - p.mb-8.max-w-prose.prose(class="lg:prose-xl") + p.mb-8.max-w-prose.prose(class="lg:prose-xl dark:prose-invert") | #{professional.principlesIntro} .list-disc.list-inside.mb-8 each person, i in professional.principlesPeople - - const data = {summary: `${person.name} — ${person.concept}`, color: "white", category: "professional"}; + - const data = {summary: `${person.name} — ${person.concept}`, color: "text-nls-black dark:text-white", category: "professional"}; - const isOpen = i === 0; +Collapsable(data, isOpen) each paragraph, j in person.paragraphs