diff --git a/public/assets/css/modal.css b/public/assets/css/modal.css
deleted file mode 100644
index 1abd25b..0000000
--- a/public/assets/css/modal.css
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Victor Westerlund */
-
-/* -- Transition overrides -- */
-
-body main .screen {
- transition: var(--transition) transform, var(--transition) filter;
- transition-delay: calc(var(--transition) / 2);
-}
-
-.modal.active + .modal:nth-child(n+2),
-body .modal.active ~ main .screen {
- transition: var(--transition);
- transition-delay: 1ms;
- transform: scale(.95);
- pointer-events: none;
- filter: blur(2px);
-}
-
-.modal.active + .modal {
- z-index: 10;
-}
-
-.modal:first-child {
- z-index: 15;
-}
-
-.modal.active + .modal:nth-child(n+2) {
- filter: blur(2px) brightness(.5);
- z-index: 5;
-}
-
-/* -- Boilerplate -- */
-
-.modal {
- transition: var(--transition) transform, var(--transition) filter;
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100%;
- z-index: 10;
- pointer-events: none;
- box-sizing: border-box;
- padding: var(--padding);
-}
-
-.modal.active {
- pointer-events: all;
-}
-
-.modal .button {
- align-self: stretch;
-}
-
-.modal .inner {
- transition: var(--transition) transform, var(--transition) opacity;
- position: relative;
- background-color: var(--swatch-background);
- width: calc(100vw - var(--padding));
- max-width: 500px;
- max-height: 100%;
- overflow-y: auto;
- word-break: break-word;
- box-sizing: border-box;
- padding: var(--padding);
- border-radius: var(--border-radius);
- box-shadow: 0 3px 30px 0 rgba(33,33,33,.2);
- opacity: 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: var(--padding);
-}
-
-.modal.active .inner {
- opacity: 1;
-}
-
-.modal .inner > h1,
-.modal .inner > h2,
-.modal .inner > p {
- text-align: center;
-}
-
-/* ---- */
-
-.spinner.logo {
- --size: clamp(30px,5vw,60px);
- --anim-speed: 1s;
- align-self: center;
- margin-top: var(--padding);
- margin-left: calc((var(--size) / 2) * -1);
- animation: logoSpinner var(--anim-speed) infinite alternate linear;
-}
-
-.error {
- text-align: center;
- font-size: 20px;
-}
-
-.error:first-line {
- font-size: 50px;
-}
-
-@keyframes logoSpinner {
- to {
- opacity: .1;
- }
-}
-
-/* ---- */
-
-.modal h1 {
- font-size: clamp(20px,2vw,20px);
-}
-
-.modal pre {
- align-self: stretch;
- overflow: scroll;
- background-color: black;
- color: white;
- padding: 10px 15px;
- border-radius: 6px;
-}
-
-/* -- Cards -- */
-
-.modal.card .inner {
- align-self: flex-end;
- transform: scale(.99) translateY(1vh);
-}
-
-.modal.card.active .inner {
- transform: scale(1) translateY(0);
-}
-
-.modal.card .button[data-action="close"] {
- margin-top: auto;
-}
-
-/* -- Dialogs -- */
-
-.modal.dialog .inner {
- transform: scale(.95);
-}
-
-.modal.dialog.active .inner {
- transform: scale(1);
-}
-
-@media (min-aspect-ratio: 14/9) {
- /* -- Transition overrides -- */
-
- body .modal {
- transition-delay: calc(var(--transition) / 2);
- }
-
- body .modal.active {
- transition-delay: 1ms;
- }
-
- /* -- Boilerplate -- */
-
- .modal.card .inner {
- align-self: unset;
- transform: scale(.99) translateY(10px);
- }
-
- .modal.dialog .inner {
- width: unset;
- min-width: 100px;
- max-width: 50vw;
- }
-
- .modal.dialog .button {
- align-self: unset;
- width: clamp(100px,100%,500px);
- }
-}
\ No newline at end of file
diff --git a/public/assets/css/style.css b/public/assets/css/style.css
index ac30e44..4aca975 100644
--- a/public/assets/css/style.css
+++ b/public/assets/css/style.css
@@ -1,39 +1,10 @@
-/* Victor Westerlund */
-
+/* Victor Westerlund - www.victorwesterlund.com */
:root {
- /* Component colors */
--palette-background: 255,255,255;
- --palette-inverted: 0,0,0;
--palette-contrast: 33,33,33;
- --palette-accent: 22,183,255;
-
- /* Compiled colors */
- --swatch-background: rgb(var(--palette-background));
- --swatch-inverted: rgb(var(--palette-inverted));
- --swatch-contrast: rgb(var(--palette-contrast));
- --swatch-accent: rgb(var(--palette-accent));
-
- /* Default styles */
- --padding: 20px;
- --border-radius: 10px;
- --header-height: 100px;
- --transition: 300ms;
-}
-
-.dark {
- --palette-background: 33,33,33;
- --palette-inverted: 255,255,255;
- --palette-contrast: 255,255,255;
- --palette-accent: 255,255,255;
--swatch-background: rgb(var(--palette-background));
- --swatch-inverted: rgb(var(--palette-inverted));
--swatch-contrast: rgb(var(--palette-contrast));
- --swatch-accent: rgb(var(--palette-accent));
-}
-
-.wide {
- display: none; /* Hide wide-screen elements */
}
@font-face {
@@ -64,433 +35,65 @@
*::selection {
background-color: var(--swatch-contrast);
- color: var(--swatch-accent);
-}
-
-a,
-picture {
- text-decoration: none;
- display: contents;
+ color: var(--swatch-background);
}
html,
body {
+ display: flex;
+ justify-content: center;
+ align-items: center;
width: 100%;
height: 100%;
overflow: hidden;
background-color: var(--swatch-background);
}
-main {
- width: 200vw;
- height: 100%;
- overflow: hidden;
- display: flex;
-}
-
-body.menuActive {
- background-color: var(--swatch-contrast);
-}
-
-body.dark.menuActive {
- background-color: black;
-}
-
-body.menuActive main {
- transform: translateX(-100vw);
-}
-
-/* ---- */
-
-.screen {
- --background-pattern:
- linear-gradient(90deg, var(--swatch-background) calc(var(--padding) + 1px), transparent 1%) center,
- linear-gradient(var(--swatch-background) calc(var(--padding) + 1px), transparent 1%) center, var(--swatch-contrast);
- --background-pattern-size: calc(var(--padding) + 2px) calc(var(--padding) + 2px);
-
- width: 100vw;
- background-color: var(--swatch-background);
- display: flex;
- flex-direction: column;
-}
-
-body.dark .screen.dark {
- background-color: black;
-}
-
-.screen .inner {
- display: contents;
-}
-
-.screen .content {
- position: relative;
- box-sizing: border-box;
- padding: calc(var(--padding) * 1.5);
- padding-top: 0;
- flex-grow: 1;
-}
-
-/* -- Positioning -- */
-
-.center {
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-/* ---- */
-
-.logo {
- --size: 1em;
- --skew: calc(var(--size) / 1.7);
-
- width: 0;
- height: 0;
- border: var(--skew) solid transparent;
- border-top: var(--size) solid var(--swatch-accent);
-}
-
-.logo::after {
- content: "";
- border: var(--skew) solid transparent;
- border-top: var(--size) solid rgba(var(--palette-accent),.3);
-}
-
-/* ---- */
-
-.button {
- text-align: center;
- padding: 25px;
- border-radius: var(--border-radius);
- font-size: clamp(16px,5vw,22px);
- display: flex;
- justify-content: center;
- align-items: center;
- gap: var(--padding);
-}
-
-a.button,
-p.button {
- padding: unset;
- display: inline;
- font-size: inherit;
- color: var(--swatch-accent);
- text-decoration: underline;
-}
-
-.button.solid {
- background-color: var(--swatch-contrast);
- color: var(--swatch-background);
- fill: var(--swatch-background);
-}
-
-.button.phantom {
- background-color: rgba(var(--palette-inverted),.05);
- color: var(--swatch-contrast);
- fill: var(--swatch-contrast);
-}
-
-.button svg {
- pointer-events: none;
- fill: inherit;
- transform: scale(1.2);
-}
-
-.button p {
- pointer-events: none;
- font-size: inherit;
- color: inherit;
-}
-
-.button.loading p {
- opacity: 0;
-}
-
-.button.loading::after {
- position: absolute;
- content: "loading...";
- opacity: 1;
-}
-
-/* -- Screens -- */
-
-header {
- --size: var(--header-height,100px);
- box-sizing: border-box;
- padding: var(--padding);
- height: var(--size);
- display: flex;
- align-items: center;
+a {
+ display: content;
+ text-decoration: none;
font-weight: bold;
}
-header > *:nth-child(2) {
- margin-left: 10px;
+a::after {
+ content: " →";
}
-header > *:nth-child(n+3) {
- margin-left: var(--padding);
-}
-
-header .hamburger {
- width: calc(var(--size) - (var(--padding) * 2));
- height: calc(var(--size) - (var(--padding) * 2));
- box-sizing: border-box;
- flex-shrink: 0;
- padding: 15px;
-}
-
-header .hamburger div {
- width: 100%;
- height: 2px;
- background: var(--swatch-contrast);
- box-shadow: 0 -10px 0 0 var(--swatch-contrast), 0 10px 0 0 var(--swatch-contrast);
-}
-
-header .hamburger svg {
- fill: none;
- stroke: var(--swatch-contrast);
- stroke-linecap: round;
- stroke-width: 2;
-}
-
-header .spacer {
- width: 1px;
- height: 80%;
- background-color: rgba(var(--palette-contrast),.2);
-}
-
-.dark header .spacer {
- background-color: black;
-}
-
-body.dark .dark header .spacer {
- background-color: rgba(var(--palette-contrast),.2);
-}
-
-header .logo {
- --size: 25px;
- margin-top: calc(var(--size) / 2);
- margin-right: calc(var(--size) / 2);
-}
-
-/* -- Screen > Landingpage -- */
-
-.screen.landingpage {
- background: var(--background-pattern);
- background-size: var(--background-pattern-size);
-}
-
-.screen.landingpage .content {
- padding-bottom: 0;
-}
-
-.screen.landingpage img {
- position: relative;
- width: clamp(100px,80vw,40vh);
- align-self: flex-end;
- z-index: 1;
-}
-
-.screen.landingpage .pattern {
- position: absolute;
- top: var(--header-height);
- width: 100vw;
- height: calc(100% - var(--header-height));
- overflow: hidden;
-}
-
-.screen.landingpage .pattern div {
- --size: clamp(100px,100vw,35vh);
- position: relative;
- top: calc((var(--size) - var(--header-height)) * -1);
- width: 0;
- height: 0;
- border: solid var(--size) transparent;
- border-bottom: solid calc(var(--size) * 2) rgba(var(--palette-accent),.1);
- transform-origin: 50% 75%;
- transform: rotate(20deg);
-}
-
-/* -- Screen > Menu -- */
-
-.screen.menu .content {
+main {
display: flex;
flex-direction: column;
- align-items: center;
- gap: 20px;
+ gap: 30px;
+ font-size: 20px;
+ transform: translateY(0);
}
-.screen.menu .button {
- width: calc(100% - (var(--padding) * 2));
- max-width: 400px;
- flex: 0;
-}
+/* -- Media Queries -- */
-.screen.menu .button[data-value="contact"] {
- margin-top: auto;
-}
-
-/* WIP */
-.screen.menu .content > .narrow {
- align-items: flex-start;
- max-width: 900px;
- gap: var(--padding);
-}
-
-/* -- Media queries -- */
-
-@media (max-width: 570px) {
- .screen.menu .content > .narrow {
- flex-direction: column;
- }
-}
-
-/* Wide-screen */
-@media (min-aspect-ratio: 14/9) and (min-height: 300px) {
- /* -- Cornerstones -- */
-
- .narrow,
- header {
- display: none;
- }
-
- main {
- width: 100vw;
- flex-direction: row-reverse;
- }
-
- /* -- Cornerstones > State overrides -- */
-
- body.menuActive {
- background-color: inherit;
- }
-
- body.menuActive main {
- transform: unset;
- }
-
- /* -- Screens -- */
-
- .screen.menu,
- .screen.landingpage {
- width: 50vw;
- flex-direction: row;
- background: var(--background-pattern);
- background-size: var(--background-pattern-size);
- }
-
- body.dark .screen {
- --swatch-background: black;
- }
-
- /* -- Screens > Menu -- */
-
- body:not(.dark) .screen.menu {
- /* Component colors */
- --palette-background: 255,255,255;
- --palette-inverted: 0,0,0;
- --palette-contrast: 33,33,33;
- --palette-accent: 33,33,33;
-
- /* Compiled colors */
- --swatch-background: rgb(var(--palette-background));
- --swatch-inverted: rgb(var(--palette-inverted));
- --swatch-contrast: rgb(var(--palette-contrast));
- --swatch-accent: rgb(var(--palette-accent));
- }
-
- .screen.menu .content {
- padding-top: calc(var(--padding) * 1.5);
- }
-
- .screen.menu .wide {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- box-sizing: border-box;
- padding: clamp(var(--padding),5vw,5vh);
- width: 100%;
- height: 100%;
- overflow-y: auto;
- }
-
- .screen.menu .wide .group {
- display: flex;
- flex-direction: column;
- gap: var(--padding);
- }
-
- .screen.menu .wide .logo {
- --size: clamp(20px,3.5vw,5vh);
- }
-
- .screen.menu .wide h1 {
- margin: 0;
- font-size: clamp(20px,3vw,5vh);
- }
-
- .screen.menu .wide h1 span {
- background: var(--swatch-contrast);
- color: var(--swatch-background);
- padding: 0 var(--padding);
- }
-
- .screen.menu .wide p {
- margin: 0;
- font-size: clamp(16px,5vw,2vh);
- }
-
- .screen.menu .wide nav {
- display: flex;
- margin-top: calc(var(--padding) * 2);
- gap: clamp(var(--padding),3vw,500px);
- }
-
- .screen.menu .wide nav p {
- display: inline-block;
- padding: var(--padding);
- }
-
- .screen.menu .button[data-value="contact"] {
- display: none;
- }
-}
-
-/* Narrow display */
@media (max-width: 300px) {
- .button svg:not(.hidden) ~ p,
- header .logo {
- display: none;
+ main {
+ text-align: center;
+ align-items: center;
}
}
-/* Super-narrow display */
-@media (max-width: 230px) {
- header {
- justify-content: center;
- }
-
- header .spacer,
- header p {
- display: none;
+@media print {
+ a::after {
+ content: ": " attr(href);
}
}
-/* -- Media queries > Media features -- */
-
@media (pointer: fine) {
- .button {
- cursor: pointer;
+ a:hover {
+ background: rgba(var(--palette-contrast),.1);
}
}
-@media (any-hover: hover) {
- .button {
- transition: var(--transition) background-color;
- }
+@media (prefers-color-scheme: dark) {
+ :root {
+ --palette-background: 0,0,0;
+ --palette-contrast: 255,255,255;
- .button.phantom:hover {
- background-color: rgba(var(--palette-inverted),.2);
+ --swatch-background: rgb(var(--palette-background));
+ --swatch-contrast: rgb(var(--palette-contrast));
}
}
\ No newline at end of file
diff --git a/public/assets/img/icons/email.svg b/public/assets/img/icons/email.svg
deleted file mode 100644
index 3e44b87..0000000
--- a/public/assets/img/icons/email.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/assets/img/icons/signal.svg b/public/assets/img/icons/signal.svg
deleted file mode 100644
index fa9c720..0000000
--- a/public/assets/img/icons/signal.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/assets/img/myface/highres.avif b/public/assets/img/myface/highres.avif
deleted file mode 100644
index 85c50e9..0000000
Binary files a/public/assets/img/myface/highres.avif and /dev/null differ
diff --git a/public/assets/img/myface/highres.webp b/public/assets/img/myface/highres.webp
deleted file mode 100644
index 11e709b..0000000
Binary files a/public/assets/img/myface/highres.webp and /dev/null differ
diff --git a/public/assets/img/myface/mediumres.avif b/public/assets/img/myface/mediumres.avif
deleted file mode 100644
index 190a9b0..0000000
Binary files a/public/assets/img/myface/mediumres.avif and /dev/null differ
diff --git a/public/assets/img/myface/mediumres.png b/public/assets/img/myface/mediumres.png
deleted file mode 100644
index c8ca5cc..0000000
Binary files a/public/assets/img/myface/mediumres.png and /dev/null differ
diff --git a/public/assets/img/myface/mediumres.webp b/public/assets/img/myface/mediumres.webp
deleted file mode 100644
index 8b7cc86..0000000
Binary files a/public/assets/img/myface/mediumres.webp and /dev/null differ
diff --git a/public/assets/img/pattern.gif b/public/assets/img/pattern.gif
deleted file mode 100644
index b85a387..0000000
Binary files a/public/assets/img/pattern.gif and /dev/null differ
diff --git a/public/assets/img/pattern.php b/public/assets/img/pattern.php
deleted file mode 100644
index 93cfa1f..0000000
--- a/public/assets/img/pattern.php
+++ /dev/null
@@ -1,8 +0,0 @@
- `window._debug.${f}();`));
- }
-
- toggleMenu() {
- document.getElementsByClassName("hamburger")[0].click();
- }
-
- openContactsModal() {
- document.getElementsByClassName("hamburger")[0].click();
- document.querySelector("div[data-action='openContactCard']").click();
- }
-
- demoCard() {
- const module = import("./Modals.mjs");
- const interactions = {
- hello: () => {
- console.log("Hello world");
- }
- };
-
- module.then(modals => {
- const card = new modals.Card(interactions);
- card.inner.style.height = "80vh";
- card.inner.insertAdjacentHTML("afterbegin","
Hello world
");
- card.open();
- });
- }
-
- invalidCard() {
- const module = import("./Modals.mjs");
- const interactions = {
- hello: () => {
- console.log("Hello world");
- }
- };
-
- module.then(modals => {
- const card = new modals.Card(interactions);
- card.openPage("invalid_card");
- });
- }
-
- infiniteLoadingCard() {
- const module = import("./Modals.mjs");
- const spinner = document.createElement("div");
- spinner.classList = "logo spinner";
-
- module.then(modals => {
- const card = new modals.Card(new Object());
- card.insertElement(spinner);
- card.open();
- });
- }
-}
-
-export default window._debug = new Debug();
\ No newline at end of file
diff --git a/public/assets/js/modules/Logging.mjs b/public/assets/js/modules/Logging.mjs
deleted file mode 100644
index e59e49e..0000000
--- a/public/assets/js/modules/Logging.mjs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Victor Westerlund - www.victorwesterlund.com
-
-class Logging {
- constructor() {
- this.endpoint = "/log/";
- this.data = new URLSearchParams();
-
- document.addEventListener("visibilitychange",() => {
- if(document.visibilityState === "hidden") {
- this.send();
- }
- });
-
- this.log("foo","bar");
- }
-
- log(key,value) {
- this.data.append(key,value);
- }
-
- send() {
- const send = navigator.sendBeacon(this.endpoint,this.data);
- if(send !== true) {
- const url = this.endpoint + this.data.toString();
- fetch(url).catch(response => console.log(response));
- }
- }
-}
-
-export default class Log {
- constructor(value,key = "u") {
- // WIP
- }
-}
\ No newline at end of file
diff --git a/public/assets/js/modules/Modals.mjs b/public/assets/js/modules/Modals.mjs
deleted file mode 100644
index fdb0c83..0000000
--- a/public/assets/js/modules/Modals.mjs
+++ /dev/null
@@ -1,191 +0,0 @@
-// Victor Westerlund - www.victorwesterlund.com
-
-import { default as Interaction, destroy } from "./UI.mjs";
-import { Button } from "./Components.mjs";
-
-// Boilerplate for creating element overlays
-class Modal extends Interaction {
- constructor(extendedInteractions = {}) {
- const element = document.createElement("div");
- let interactions = {
- close: () => {
- this.close();
- },
- openPage: (event) => {
- let modal = undefined;
- switch(event.target.dataset.type) {
- case "card":
- modal = new Card({});
- break;
- case "dialog":
- default:
- modal = new Dialog({});
- break;
- }
- modal.openPage(event.target.dataset.value);
- }
- };
- // Combine template and incoming interactions into one object
- interactions = Object.assign(interactions,extendedInteractions);
- super(interactions,element);
-
- this.transition = 300;
-
- this.element = this.applyTemplate(element);
- this.element.close = () => this.close(); // Bind modal close to element prototype
- document.body.insertAdjacentElement("afterbegin",this.element);
- }
-
- // Fetch page html from "assets/pages"
- async getPage(page) {
- const url = `assets/pages/${page}`;
- const response = await fetch(url);
- if(!response.ok) {
- const report = {
- "self": "Modal.getPage()",
- "self_page": page,
- "resp_status": response.status,
- "resp_statusText": response.statusText,
- "resp_url": response.url,
- "rqst_ua": navigator.userAgent
- };
- throw new Error(JSON.stringify(report,null,2));
- }
- return response.text();
- }
-
- insertHTML(element) {
- this.inner.insertAdjacentHTML("afterbegin",element);
- }
-
- insertElement(element) {
- this.inner.insertAdjacentElement("afterbegin",element);
- }
-
- // Apply a modal template to the provided element
- applyTemplate(element) {
- // The inner div will contain modal content
- this.inner = document.createElement("div");
- this.inner.classList.add("inner");
- element.appendChild(this.inner);
- element.classList.add("modal");
-
- // PointerEvents on the outer div will close the modal
- element.addEventListener("click",event => {
- if(event.target == element) {
- this.close();
- }
- });
-
- return element;
- }
-
- error(message) {
- const oops = document.createElement("p");
- const infoButton = document.createElement("p");
-
- oops.classList.add("error");
- oops.innerText = "🤯\nSomething went wrong";
-
- infoButton.innerText = "more info..";
- infoButton.addEventListener("click",() => {
- const details = new Dialog();
-
- details.insertHTML(`📄 Error report ${message} `);
- details.open();
-
- this.close();
- });
-
- this.insertElement(infoButton);
- this.insertElement(oops);
- }
-
- // Open page from "assets/pages"
- openPage(page) {
- // Show a spinner while fetching
- const spinner = document.createElement("div");
- spinner.classList = "logo spinner";
- this.element.setAttribute("data-page",page);
- this.insertElement(spinner);
- this.open();
-
- // Fetch the requested page
- this.getPage(page).then(html => {
- this.insertHTML(html);
- this.bindAll(this.inner);
- })
- .catch(error => {
- const tryAgain = new Button({
- text: "try again",
- type: "solid"
- });
- tryAgain.element.addEventListener("click",() => {
- // Clear and recreate modal structure
- destroy(this.inner);
- this.applyTemplate(this.element);
- this.init();
- this.insertElement(spinner);
- // Attempt to fetch the requested url again (with soft rate-limiting)
- setTimeout(() => {
- this.openPage(page);
- destroy(spinner);
- },500);
- });
- this.insertElement(tryAgain.element);
- this.error(error);
- })
- .finally(() => destroy(spinner));
- }
-
- open() {
- setTimeout(() => this.element.classList.add("active"),this.transition / 2);
- }
-
- // Close the modal and remove it from the DOM
- close() {
- this.element.classList.remove("active");
- setTimeout(() => destroy(this.element),this.transition + 1); // Wait for transition
- }
-}
-
-export class Dialog extends Modal {
- constructor(interactions = {}) {
- super(interactions);
- this.init();
- }
-
- init() {
- this.element.classList.add("dialog");
- this.element.classList.add("center");
- const closeButton = new Button({
- text: "close",
- action: "close",
- type: "phantom"
- });
-
- this.bind(closeButton.element);
- this.inner.appendChild(closeButton.element);
- }
-}
-
-// Overlay with a slide-in animation from the bottom of the viewport
-export class Card extends Modal {
- constructor(interactions = {}) {
- super(interactions);
- this.init();
- }
-
- init() {
- this.element.classList.add("card");
- this.element.classList.add("center");
- const closeButton = new Button({
- text: "close",
- action: "close",
- type: "phantom"
- });
-
- this.bind(closeButton.element);
- this.inner.appendChild(closeButton.element);
- }
-}
\ No newline at end of file
diff --git a/public/assets/js/modules/Preload.mjs b/public/assets/js/modules/Preload.mjs
deleted file mode 100644
index 48e32bd..0000000
--- a/public/assets/js/modules/Preload.mjs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Victor Westerlund - www.victorwesterlund.com
-
-// Load assets for later use on this page.
-// This implements a hybrid of the link types "preload" and "prefetch"
-export default class Preload {
- constructor(assets) {
- this.scripts = [];
- this.stylesheets = [];
-
- // Get the type of asset from the file extension
- assets.forEach(asset => {
- const components = asset.split(".");
- const extension = components[components.length - 1];
- switch(extension) {
- case "mjs":
- this.scripts.push(asset);
- break;
- case "css":
- this.stylesheets.push(asset);
- break;
- }
- });
-
- // Append tags when DOM is ready
- window.addEventListener("DOMContentLoaded",() => this.import());
- }
-
- import() {
- this.scripts.forEach(script => {
- const element = document.createElement("script");
- element.setAttribute("type","module");
- element.src = "assets/js/" + script;
- document.body.appendChild(element);
- });
- this.stylesheets.forEach(sheet => {
- const element = document.createElement("link");
- element.setAttribute("rel","stylesheet");
- element.href = "assets/css/" + sheet;
- document.head.appendChild(element);
- });
- }
-}
\ No newline at end of file
diff --git a/public/assets/js/modules/UI.mjs b/public/assets/js/modules/UI.mjs
deleted file mode 100644
index 09fffe8..0000000
--- a/public/assets/js/modules/UI.mjs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Victor Westerlund - www.victorwesterlund.com
-
-import { default as Logging } from "./Logging.mjs";
-
-// Remove an element and its subtree
-export function destroy(family) {
- while(family.firstChild) {
- family.removeChild(family.lastChild);
- }
- family.parentNode.removeChild(family);
-}
-
-// General-purpose scoped event handler
-export default class Interaction extends Logging {
- constructor(interactions,scope) {
- super();
- this.interactions = interactions;
- this.attribute = "data-action"; // Target elements with this attribute
-
- this.bindAll(scope);
- }
-
- // Bind event listeners to this element
- bind(element) {
- if(element.hasAttribute("data-bound") || !element.hasAttribute(this.attribute)) {
- return false;
- }
- element.addEventListener("click",event => this.pointerEvent(event));
- element.setAttribute("data-bound","");
- }
-
- // Get all elements with the target attribute in scope
- getAll(scope) {
- return scope.querySelectorAll(`[${this.attribute}]`);
- }
-
- // Bind listeners to all attributed elements within scope
- bindAll(scope) {
- const elements = this.getAll(scope);
- for(const element of elements) {
- this.bind(element);
- }
- }
-
- // Handle click/touch interactions
- pointerEvent(event) {
- const target = event.target.closest(`[${this.attribute}]`);
- const action = target?.getAttribute(this.attribute) ?? null;
-
- if(!target || !action || !Object.keys(this.interactions).includes(action)) {
- // Exit if the interaction is invalid or action doesn't exist
- return false;
- }
- // Execute the function from the data-action attribute
- this.interactions[action](event);
- }
-}
\ No newline at end of file
diff --git a/public/assets/js/nomodule.js b/public/assets/js/nomodule.js
deleted file mode 100644
index 2e68d64..0000000
--- a/public/assets/js/nomodule.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Promote IE to Edge
-if(/MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
- window.location = 'microsoft-edge:' + window.location;
- setTimeout(function() {
- window.location = 'https://go.microsoft.com/fwlink/?linkid=2135547';
- },1);
-}
diff --git a/public/assets/js/script.js b/public/assets/js/script.js
deleted file mode 100644
index b7ce617..0000000
--- a/public/assets/js/script.js
+++ /dev/null
@@ -1,85 +0,0 @@
-// Victor Westerlund - www.victorwesterlund.com
-import { default as Preload } from "./modules/Preload.mjs";
-import { default as Interaction, destroy } from "./modules/UI.mjs";
-
-// Load these assets when the DOM is ready (not needed right away)
-new Preload([
- "modules/Modals.mjs",
- "modules/Components.mjs",
- "modal.css"
-]);
-
-function updateTheme() {
- const media = window.matchMedia("(prefers-color-scheme: dark)");
- document.body.classList.remove("dark");
-
- // Force dark theme on all pages
- if(media.matches) {
- document.body.classList.add("dark");
- return;
- }
-}
-
-// All default interactions
-const interactions = {
- toggleMenu: () => {
- const transition = 200;
- const menu = document.getElementsByTagName("main")[0];
-
- // Animate menu state change
- menu.style.setProperty("transition",`${transition}ms`);
- document.body.classList.toggle("menuActive");
- // Remove transition CSS when finished. Wonky resize effects otherwise
- setTimeout(() => menu.style.removeProperty("transition"),transition + 1);
- },
- // Open page defined with data-value as a card
- newCard: (event) => {
- const module = import("./modules/Modals.mjs");
- const interactions = {
- // Like newCard() except it closes the previous card
- getContact: (event) => {
- const service = event.target.dataset.value;
- module.then(modals => {
- event.target.closest(".modal").close();
- const card = new modals.Card(interactions);
- card.openPage(service);
- });
- },
- // Copy text defined in data-value to clipboard and play animation
- copyText: (event) => {
- const copy = navigator.clipboard.writeText(event.target.dataset.value);
- copy.then(() => {
- event.target.classList.add("copied");
- const copied = document.createElement("p");
- copied.innerText = "copied!";
- event.target.appendChild(copied);
-
- // Reset button state
- setTimeout(() => {
- event.target.classList.remove("copied");
- destroy(copied);
- },1000);
- });
- }
- };
-
- // Create card and open the specified page asynchronously
- module.then(modals => {
- const card = new modals.Card(interactions);
- card.openPage(event.target.dataset.value);
- });
- }
-}
-
-navigator.serviceWorker.getRegistrations().then(serviceWorkers => {
- for(const serviceWorker of serviceWorkers) {
- serviceWorker.unregister();
- }
-});
-
-// Set the current page theme, and listen for changes
-const theme = window.matchMedia("(prefers-color-scheme: dark)");
-theme.addEventListener("change",updateTheme);
-
-new Interaction(interactions,document.body); // Initialize default interactions
-updateTheme();
diff --git a/public/assets/pages/contact.html b/public/assets/pages/contact.html
deleted file mode 100644
index 104487e..0000000
--- a/public/assets/pages/contact.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/public/assets/pages/contact_email.html b/public/assets/pages/contact_email.html
deleted file mode 100644
index a0be5ff..0000000
--- a/public/assets/pages/contact_email.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-hello@victorwesterlund.com
-You can also here to send a mail directly from your mail app
-
-
\ No newline at end of file
diff --git a/public/assets/pages/contact_email_pgp.html b/public/assets/pages/contact_email_pgp.html
deleted file mode 100644
index e9b2895..0000000
--- a/public/assets/pages/contact_email_pgp.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-🔑 PGP Public Key
-
-5466 B1EB 2F44 6D3D DC34 E9F7 5BE0 CB0B E3BB 69DA
-show key
-
\ No newline at end of file
diff --git a/public/assets/pages/contact_email_pgp_view.html b/public/assets/pages/contact_email_pgp_view.html
deleted file mode 100644
index 36144b4..0000000
--- a/public/assets/pages/contact_email_pgp_view.html
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-mQENBF/K6MkBCACkRMhMfYdeNP+M3XQoZHQVJgippQvYZ4QqH6F6brWD5989Xy5W
-kDCvLbmPJ66boqB0dHExswOvMlhfFha65pRmfP6lIoIxZlZKwll1XASP2osS8f6r
-63T7hAbL3V2Dkm49tiH1tk578xGomDrxOrd4izpH4mn9AyBIL4M+5j34bKFVZKQ+
-QfMu7tduF/1oQHfDaXJeLXSfn5cNTy8DlLcLJKUSk4cjabf1D88gMVszqAAC5o1a
-fI0YxoyZ+Fv+CmyrQm2iIZ3+MyDU9JAvoImtlp1h5aNgbFRDi2vKcSlv158Hq97Z
-XlH1ttRZuFZiJzb8iukgUUFi4RORoXWt2rtNABEBAAG0LlZpY3RvciBXZXN0ZXJs
-dW5kIDxoZWxsb0B2aWN0b3J3ZXN0ZXJsdW5kLmNvbT6JATUEEAEIACkFAl/K6MkG
-CwkIBwMCCRBb4MsL47tp2gQVCAIKAxYCAQIZAQIbAwIeAQAAJ5MIAKDl9yHjwTO7
-20sDrPa6ECsSBU/FwkvkWecuauvY19/OqtacNk8dEeiITLeUeBXkvNzN+P0y8hoF
-ABZeir59dsY00iIp8gm03eLalhcblR5jYe3c08HssJH8PksczP3kitRNLvPAf2nU
-BYg3zca5Ka21/4BPRLFb9SAQGxfHyZdy3Poug+o+pokbeK2wLqqfSMtH+waBB6Lg
-2dRXuEnaZorUpNBpsahxastvNehv31Ke41Brvft15VKpO25GKZDPhm0odXMth1/J
-pzWRQtndazY2guB0Ft+5wujv28HFCgVgZn2fKiQVytAetO+/wzPijBkGRvdIE+Zb
-VRd3Nc0mHI65AQ0EX8royQEIALcoWEurmyXD2LoGvR+sYW+YPAPM6KG8KF4cWUn8
-8+kZ6F4FH9OW64di2npYe3x+zR7DgQ1yHXcmalAsP0nN4JWTavLwsSO+JAv8NpL5
-bgDs6fGaEQFl+X4fYOpkBkBmb1JrbnBk1a2u3qsEw8t7+wW1LG9z/Si5+G1KQko8
-x/PEaZ2ZVv7L51ZfIQRnMtl4vL5X23BPVsDywotvuFqlTiSjGP4CR0lVa5CRv3DJ
-FSmHxAxeI0vMMlwbIIUTrtwJR320sZvh2cRiwAXHQXm6l0ojzRnl46mmXnB3N6q9
-PyWOaUgPrMFjT24wtgopIOwbFAT3xTr1Un0FbdeaG9JhdJ8AEQEAAYkBHwQYAQgA
-EwUCX8royQkQW+DLC+O7adoCGwwAAIV/B/9OLYeQOxbXh1/hvW7/oTvN1py8wfFq
-buvQSrb/MZKm6lZgG+kQy3DWjGTi/xvNqDHfBiObFSGso8RHSbHFldzEuMgrgoWW
-/4JH1GDiKOp+rmBxfG30/DzOoFSfVcUfP5r8xNQby4Bh6zJhKPKVB3sZjO8cHNZD
-HcNAqT3Gh5yFzsUna+ZjvPF7iU5RF1YP46dsIdvuo4xFbHpEPoZs7wgZijf+vmKO
-lP61UFvKuXzwcLiI6s919EBJ9+7je8ZAxe6BCaazk+AhxXeokVvDgwQ150DNk4up
-1ftWZI0LHqEpVGNejQ09uu+TdC/ISy/Ti0XKlJDER1eUL577YRUl876Y
-=2qWm
------END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file
diff --git a/public/assets/pages/contact_signal.html b/public/assets/pages/contact_signal.html
deleted file mode 100644
index 9e9191f..0000000
--- a/public/assets/pages/contact_signal.html
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-+4670-245-2459
-Signal is a free and encrypted message platform with apps for all major platforms.
-
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index a754867..5759bed 100644
--- a/public/index.html
+++ b/public/index.html
@@ -4,71 +4,27 @@
Victor Westerlund
-
-
-
-
-
-
-
-
- victor westerlund
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ victor westerlund
+ github
-
-
+