mirror of
https://codeberg.org/vlw/victorwesterlund.com.git
synced 2025-09-14 11:33:41 +02:00
dev21w36b
This commit is contained in:
parent
ff474e1786
commit
62cdb7aae5
8 changed files with 176 additions and 24 deletions
|
@ -23,7 +23,7 @@ body.modalActive main .screen {
|
|||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
|
@ -31,13 +31,46 @@ body.modalActive main .screen {
|
|||
padding: var(--padding);
|
||||
}
|
||||
|
||||
.modal + .modal {
|
||||
transition: var(--transition) backdrop-filter;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.modal.active {
|
||||
pointer-events: all;
|
||||
background-color: rgba(var(--comp-inverted),.4);
|
||||
}
|
||||
|
||||
.modal .button {
|
||||
background-color: rgba(var(--comp-inverted),.3);
|
||||
background-color: rgba(var(--comp-inverted),.05);
|
||||
}
|
||||
|
||||
.modal .button p {
|
||||
color: var(--color-inverted);
|
||||
}
|
||||
|
||||
.spinner.logo {
|
||||
--size: 10vw;
|
||||
--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: 15vw;
|
||||
}
|
||||
|
||||
@keyframes logoSpinner {
|
||||
to {
|
||||
opacity: .1;
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Cards -- */
|
||||
|
@ -45,18 +78,25 @@ body.modalActive main .screen {
|
|||
.modal.card .inner {
|
||||
transition: var(--transition) transform, var(--transition) opacity;
|
||||
position: relative;
|
||||
background-color: var(--color-contrast);
|
||||
background-color: var(--color-background);
|
||||
width: calc(100vw - var(--padding));
|
||||
max-width: 600px;
|
||||
max-width: 500px;
|
||||
align-self: flex-end;
|
||||
box-sizing: border-box;
|
||||
padding: var(--padding);
|
||||
transform: translateY(1vh);
|
||||
border-radius: var(--border-radius);
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
}
|
||||
|
||||
.modal.card.active .inner {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal.card .button[data-action="close"] {
|
||||
margin-top: auto;
|
||||
}
|
|
@ -8,15 +8,36 @@ class Debug {
|
|||
list() {
|
||||
const functions = [
|
||||
"list",
|
||||
"toggleMenu",
|
||||
"openContactsModal"
|
||||
];
|
||||
console.log("Available functions:",functions.map(f => `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","<p>Hello world</p>");
|
||||
card.open();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default window._debug = new Debug();
|
|
@ -17,25 +17,25 @@ class Modal extends Interaction {
|
|||
super(interactions,element);
|
||||
|
||||
this.element = this.applyTemplate(element);
|
||||
this.importStyleSheet();
|
||||
document.body.appendChild(this.element);
|
||||
}
|
||||
|
||||
// Import the companion CSS rules
|
||||
importStyleSheet() {
|
||||
let sheet = "assets/css/modal.css";
|
||||
const element = document.createElement("link");
|
||||
|
||||
// Exit if the stylesheet has already been imported
|
||||
if(document.head.querySelector("link[data-async-modalcss]")) {
|
||||
return false;
|
||||
// Fetch page html from "assets/pages"
|
||||
async getPage(page) {
|
||||
const url = `assets/pages/${page}.html`;
|
||||
const response = await fetch(url);
|
||||
if(!response.ok) {
|
||||
throw new Error(`Modal: Failed to fetch page "${page}"`);
|
||||
}
|
||||
return response.text();
|
||||
}
|
||||
|
||||
// Import the stylesheet with a link tag
|
||||
element.setAttribute("rel","stylesheet");
|
||||
element.setAttribute("href",sheet);
|
||||
element.setAttribute("data-async-modalcss","");
|
||||
document.head.appendChild(element);
|
||||
insertHTML(element) {
|
||||
this.inner.insertAdjacentHTML("afterbegin",element);
|
||||
}
|
||||
|
||||
insertElement(element) {
|
||||
this.inner.insertAdjacentElement("afterbegin",element);
|
||||
}
|
||||
|
||||
// Apply a modal template to the provided element
|
||||
|
@ -83,10 +83,6 @@ export class Card extends Modal {
|
|||
this.init();
|
||||
}
|
||||
|
||||
setContent(content) {
|
||||
this.element.insertAdjacentHTML("beforeend",content);
|
||||
}
|
||||
|
||||
init(slim) {
|
||||
this.element.classList.add("card");
|
||||
this.element.classList.add("center");
|
||||
|
@ -100,7 +96,22 @@ export class Card extends Modal {
|
|||
this.inner.appendChild(closeButtonElement);
|
||||
}
|
||||
|
||||
// Open page from "assets/pages"
|
||||
openPage(page) {
|
||||
// Show a spinner while fetching
|
||||
const spinner = document.createElement("div");
|
||||
spinner.classList = "logo spinner";
|
||||
this.insertElement(spinner);
|
||||
this.open();
|
||||
|
||||
// Fetch the requested page
|
||||
this.getPage(page).then(html => {
|
||||
this.insertHTML(html);
|
||||
}).catch(error => {
|
||||
const element = document.createElement("p");
|
||||
element.classList.add("error");
|
||||
element.innerText = "🤯\nSomething went wrong";
|
||||
this.insertElement(element);
|
||||
}).finally(() => destroy(spinner));
|
||||
}
|
||||
}
|
42
public/assets/js/modules/Preload.mjs
Normal file
42
public/assets/js/modules/Preload.mjs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright © Victor Westerlund - No libraries! 😲
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,7 +1,15 @@
|
|||
// Copyright © Victor Westerlund - No libraries! 😲
|
||||
import { default as Preload } from "./modules/Preload.mjs";
|
||||
import { default as Interaction } from "./modules/UI.mjs";
|
||||
import { default as Debug } from "./modules/Debugging.mjs";
|
||||
|
||||
// Load these assets when the DOM is ready (not needed right away)
|
||||
const preload = new Preload([
|
||||
"modules/Modals.mjs",
|
||||
"modules/Components.mjs",
|
||||
"modal.css"
|
||||
]);
|
||||
|
||||
// All default interactions
|
||||
const interactions = {
|
||||
toggleMenu: () => {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<style>
|
||||
.contact {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--padding);
|
||||
}
|
||||
|
||||
.contact .item {
|
||||
height: 140px;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: rgba(var(--comp-inverted),.05);
|
||||
}
|
||||
</style>
|
||||
<div class="contact">
|
||||
<div class="item" data-action="hello" data-value="signal">
|
||||
<p>Signal</p>
|
||||
</div>
|
||||
<div class="item" data-action="getContact" data-value="email">
|
||||
<p>E-Mail</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<p>
|
||||
</div>
|
||||
<div class="item">
|
||||
</div>
|
||||
</div>
|
|
@ -3,12 +3,15 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Victor Westerlund</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Full-stack web developer from Stockholm, Sweden.">
|
||||
<meta name="theme-color" content="">
|
||||
<meta name="theme-color" content="red">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#212121">
|
||||
|
||||
<link href="assets/img/favicon.png" rel="icon">
|
||||
<link href="assets/css/style.css" rel="stylesheet">
|
||||
<title>Victor Westerlund</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
|
|
Loading…
Add table
Reference in a new issue