From 0e46eb84260504a8479f15dc15f9496d0ac336bd Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Wed, 20 Nov 2024 16:28:21 +0100 Subject: [PATCH] wip: 2024-11-20T09:08:18+0100 (1732090098) --- public/about.php | 31 +++++++- public/assets/css/pages/about.css | 106 ++++++++++++++++++++++++++ public/assets/css/pages/contact.css | 2 +- public/assets/js/modules/Hoverpop.mjs | 32 ++++++++ public/assets/js/pages/about.js | 7 ++ public/assets/js/pages/contact.js | 26 +------ public/contact.php | 8 +- 7 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 public/assets/js/modules/Hoverpop.mjs diff --git a/public/about.php b/public/about.php index 37cecd9..d34acdd 100644 --- a/public/about.php +++ b/public/about.php @@ -1,3 +1,20 @@ +call(Endpoints::ABOUT_LANGUAGES->value)->get()->json(); + $languages_bytes_total = array_sum($languages); + +?>
@@ -6,7 +23,19 @@

I​'m a full-stack web developer from Sweden.

-

The <programming/markup/command/query/whatever>-languages I currently use the most are (in a mostly accurate decending order): PHP, JavaScript, CSS, MySQL, TypeScript, Python, SQLite, Bash, and HTML.

+

Instead of telling you what <programming/markup/command/query/whatever>-languages I use the most and over-guesstimating how much I use them, I thought I'd just show you instead with this stacking bar chart which reads the number of bytes for each language for my public mirrors and sources on Forgejo and distributes them proportionally. The chart is updated automatically every day.

+
+
+ + + $bytes): ?> + + %
( bytes)
+

+
+ + +

This website

diff --git a/public/assets/css/pages/about.css b/public/assets/css/pages/about.css index dc66092..87f451f 100644 --- a/public/assets/css/pages/about.css +++ b/public/assets/css/pages/about.css @@ -45,6 +45,112 @@ section.about p i:not(:hover) { opacity: .3; } +/* ## Languages */ + +section.languages { + margin: calc(var(--padding) / 1.5) 0; +} + +section.languages stacked-bar-chart { + gap: 3px; + width: 100%; + display: flex; + border-radius: 100px; + height: calc(var(--padding) * 1.5); + background-color: rgba(255, 255, 255, 0); +} + +section.languages stacked-bar-chart:hover segment { + opacity: .5; +} + +section.languages stacked-bar-chart segment { + --border-corner-radius: 100px; + + transition: 150ms opacity; + min-width: 5%; + height: 100%; + color: white; + position: relative; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(255, 255, 255, .1); + border-radius: 2px; +} + +section.languages stacked-bar-chart segment:hover { + opacity: 1; +} + +section.languages stacked-bar-chart a:first-child segment { + border-top-right-radius: var(--padding); + border-bottom-right-radius: var(--padding); + border-top-left-radius: var(--border-corner-radius); + border-bottom-left-radius: var(--border-corner-radius); +} + +section.languages stacked-bar-chart a:last-child segment { + border-top-left-radius: var(--padding); + border-bottom-left-radius: var(--padding); + border-top-right-radius: var(--border-corner-radius); + border-bottom-right-radius: var(--border-corner-radius); +} + +section.languages stacked-bar-chart a:nth-child(odd) segment { + background-color: rgba(255, 255, 255, .3); +} + +section.languages stacked-bar-chart segment p { + text-align: center; + color: inherit; + overflow: hidden; + white-space: nowrap; + pointer-events: none; + text-overflow: ellipsis; + padding: 0 3px; +} + +section.languages stacked-bar-chart segment[style="width:0%;"] p span { + display: none; +} + +section.languages stacked-bar-chart segment[style="width:0%;"] p::before { + content: "<1%"; + opacity: .5; +} + +section.languages stacked-bar-chart a segment[data-lang="Go"] { background-color: #00add8; } +section.languages stacked-bar-chart a segment[data-lang="PHP"] { background-color: #4f5d95; } +section.languages stacked-bar-chart a segment[data-lang="CSS"] { background-color: #563d7c; } +section.languages stacked-bar-chart a segment[data-lang="HTML"] { background-color: #e34c26; } +section.languages stacked-bar-chart a segment[data-lang="Python"] { background-color: #3572a5; } +section.languages stacked-bar-chart a segment[data-lang="TypeScript"] { background-color: #3178c6; } +section.languages stacked-bar-chart a segment[data-lang="Shell"] { background-color: #89e051; color: black; } +section.languages stacked-bar-chart a segment[data-lang="JavaScript"] { background-color: #f1e05a; color: black; } + +/* ### Hoverpop */ + +section.languages stacked-bar-chart segment [data-hover] { + display: none; + position: absolute; + top: 0; + left: 0; + text-align: center; + transform: translate(0, 0); + background-color: inherit; + padding: 5px 10px; + white-space: nowrap; + pointer-events: none; + border-radius: 6px; + -webkit-backdrop-filter: brightness(.2) blur(20px); + backdrop-filter: brightness(.2) blur(20px); +} + +section.languages stacked-bar-chart segment [data-hover].hovering { + display: initial; +} + /* # Interests */ div.interests { diff --git a/public/assets/css/pages/contact.css b/public/assets/css/pages/contact.css index a1efd9a..1e8adda 100644 --- a/public/assets/css/pages/contact.css +++ b/public/assets/css/pages/contact.css @@ -71,7 +71,7 @@ section.social social:hover { fill: var(--color-accent); } -section.social social.hovering p { +section.social social p.hovering { display: initial; } diff --git a/public/assets/js/modules/Hoverpop.mjs b/public/assets/js/modules/Hoverpop.mjs new file mode 100644 index 0000000..34b085c --- /dev/null +++ b/public/assets/js/modules/Hoverpop.mjs @@ -0,0 +1,32 @@ +import { Elevent } from "/assets/js/modules/npm/Elevent.mjs"; + +export const TARGET_SELECTOR = "[data-hover]"; + +export class Hoverpop { + /** + * Bind hover targets on provided Elevent-compatible element(s) + * @param {HTMLElement|HTMLElements|string} elements + */ + constructor(elements) { + // Bind hover targets on element(s) + new Elevent("mouseenter", elements, (event) => { + const element = event.target.querySelector(TARGET_SELECTOR); + + // Bail out if target element contains no hover target element + if (!element) { + return; + } + + element.classList.add("hovering"); + event.target.addEventListener("mousemove", (event) => { + const x = event.layerX - (element.clientWidth / 2); + const y = event.layerY + element.clientHeight; + + element.style.setProperty("transform", `translate(${x}px, ${y}px)`); + }); + }); + + // Bind hover leave targets on element(s) + new Elevent("mouseleave", elements, () => elements.forEach(element => element.querySelector(TARGET_SELECTOR)?.classList.remove("hovering"))); + } +} \ No newline at end of file diff --git a/public/assets/js/pages/about.js b/public/assets/js/pages/about.js index bc933f2..df27e69 100644 --- a/public/assets/js/pages/about.js +++ b/public/assets/js/pages/about.js @@ -1,3 +1,5 @@ +import { Hoverpop } from "/assets/js/modules/Hoverpop.mjs"; + const randomIntFromInterval = (min, max) => { return Math.floor(Math.random() * (max - min + 1) + min); } @@ -65,3 +67,8 @@ const implodeInterests = () => { interestsElement.addEventListener(canHover ? "mouseleave" : "touchend", () => implodeInterests()); } + +// Languages stacking bar chart hoverpop +{ + new Hoverpop(document.querySelectorAll("stacked-bar-chart segment")); +} \ No newline at end of file diff --git a/public/assets/js/pages/contact.js b/public/assets/js/pages/contact.js index e42bdab..45f8a85 100644 --- a/public/assets/js/pages/contact.js +++ b/public/assets/js/pages/contact.js @@ -1,3 +1,5 @@ +import { Hoverpop } from "/assets/js/modules/Hoverpop.mjs"; + class ContactForm { static STORAGE_KEY = "contact_form_message"; @@ -60,27 +62,7 @@ class ContactForm { form ? (new ContactForm(form)) : ContactForm.removeSavedMessage(); } -// Social links hover +// Social links hoverpop { - const socialElementHover = (target) => { - const element = target.querySelector("p"); - - target.classList.add("hovering"); - target.addEventListener("mousemove", (event) => { - const x = event.layerX - (element.clientWidth / 2); - const y = event.layerY + element.clientHeight; - - element.style.setProperty("transform", `translate(${x}px, ${y}px)`); - }); - }; - - const elements = [...document.querySelectorAll("social")]; - - elements.forEach(element => { - element.addEventListener("mouseenter", () => socialElementHover(element)); - - element.addEventListener("mouseleave", () => { - elements.forEach(element => element.classList.remove("hovering")); - }); - }); + new Hoverpop(document.querySelectorAll("social")); } \ No newline at end of file diff --git a/public/contact.php b/public/contact.php index 51c2e6d..2223317 100644 --- a/public/contact.php +++ b/public/contact.php @@ -63,15 +63,15 @@ @@ -133,4 +133,4 @@
- \ No newline at end of file + \ No newline at end of file