mirror of
https://codeberg.org/vlw/victorwesterlund.com.git
synced 2025-09-14 03:23:41 +02:00
dev21w36c
This commit is contained in:
parent
62cdb7aae5
commit
821ed27776
10 changed files with 123 additions and 67 deletions
|
@ -6,11 +6,13 @@ body {
|
|||
|
||||
body main .screen {
|
||||
transition: var(--transition) transform;
|
||||
transition-delay: calc(var(--transition) / 2);
|
||||
}
|
||||
|
||||
body.modalActive main .screen {
|
||||
transition: 300ms;
|
||||
transform: scale(.9,.95);
|
||||
body .modal.active ~ main .screen {
|
||||
transition: var(--transition);
|
||||
transition-delay: 1ms;
|
||||
transform: scale(.95);
|
||||
opacity: .5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -31,11 +33,6 @@ 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);
|
||||
|
|
|
@ -91,6 +91,10 @@ main.active {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
body.dark .screen.dark {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.screen .content {
|
||||
box-sizing: border-box;
|
||||
padding: calc(var(--padding) * 1.5);
|
||||
|
|
|
@ -5,10 +5,6 @@ class Component {
|
|||
constructor(tag) {
|
||||
this.element = document.createElement(tag); // Root element
|
||||
}
|
||||
|
||||
getElement() {
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
|
||||
// ⬇ UI Components ⬇
|
||||
|
|
|
@ -38,6 +38,20 @@ class Debug {
|
|||
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");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default window._debug = new Debug();
|
|
@ -17,12 +17,13 @@ class Modal extends Interaction {
|
|||
super(interactions,element);
|
||||
|
||||
this.element = this.applyTemplate(element);
|
||||
document.body.appendChild(this.element);
|
||||
this.element.close = () => this.close(); // Bind close to element prototype
|
||||
document.body.insertAdjacentElement("afterbegin",this.element);
|
||||
}
|
||||
|
||||
// Fetch page html from "assets/pages"
|
||||
async getPage(page) {
|
||||
const url = `assets/pages/${page}.html`;
|
||||
const url = `assets/pages/${page}`;
|
||||
const response = await fetch(url);
|
||||
if(!response.ok) {
|
||||
throw new Error(`Modal: Failed to fetch page "${page}"`);
|
||||
|
@ -57,18 +58,11 @@ class Modal extends Interaction {
|
|||
}
|
||||
|
||||
open() {
|
||||
document.body.classList.add("modalActive");
|
||||
setTimeout(() => this.element.classList.add("active"),this.transition / 2);
|
||||
}
|
||||
|
||||
// Close the modal and remove it from the DOM
|
||||
close() {
|
||||
const activeModals = document.getElementsByClassName("modal");
|
||||
if(!activeModals || activeModals.length === 1) {
|
||||
// Remove active effects if all modals have been closed
|
||||
setTimeout(() => document.body.classList.remove("modalActive"),this.transition / 2);
|
||||
}
|
||||
|
||||
this.element.classList.remove("active");
|
||||
setTimeout(() => destroy(this.element),this.transition + 1); // Wait for transition
|
||||
}
|
||||
|
@ -90,10 +84,27 @@ export class Card extends Modal {
|
|||
text: "close",
|
||||
action: "close"
|
||||
});
|
||||
const closeButtonElement = closeButton.getElement();
|
||||
|
||||
this.bind(closeButtonElement);
|
||||
this.inner.appendChild(closeButtonElement);
|
||||
this.bind(closeButton.element);
|
||||
this.inner.appendChild(closeButton.element);
|
||||
}
|
||||
|
||||
error(message) {
|
||||
const oops = document.createElement("p");
|
||||
const infoButton = new Button({
|
||||
text: "more info"
|
||||
});
|
||||
|
||||
oops.classList.add("error");
|
||||
oops.innerText = "🤯\nSomething went wrong";
|
||||
|
||||
infoButton.element.addEventListener("click",() => {
|
||||
oops.innerText = "📋\n" + message;
|
||||
destroy(infoButton.element);
|
||||
});
|
||||
|
||||
this.insertElement(infoButton.element);
|
||||
this.insertElement(oops);
|
||||
}
|
||||
|
||||
// Open page from "assets/pages"
|
||||
|
@ -107,11 +118,9 @@ export class Card extends Modal {
|
|||
// 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));
|
||||
this.bindAll(this.inner);
|
||||
})
|
||||
.catch(error => this.error(error))
|
||||
.finally(() => destroy(spinner));
|
||||
}
|
||||
}
|
|
@ -17,17 +17,31 @@ export default class Interaction extends Logging {
|
|||
this.interactions = interactions;
|
||||
this.attribute = "data-action"; // Target elements with this attribute
|
||||
|
||||
// Bind listeners to the target attribute within the provided scope
|
||||
const elements = scope.querySelectorAll(`[${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);
|
||||
}
|
||||
}
|
||||
|
||||
bind(element) {
|
||||
element.addEventListener("click",event => this.pointerEvent(event));
|
||||
}
|
||||
|
||||
// Set the page theme color (and the theme-color meta tag)
|
||||
setThemeColor(color) {
|
||||
const meta = document.head.querySelector("meta[name='theme-color']");
|
||||
|
|
|
@ -23,14 +23,19 @@ const interactions = {
|
|||
openContactCard: () => {
|
||||
const module = import("./modules/Modals.mjs");
|
||||
const interactions = {
|
||||
hello: () => {
|
||||
console.log("Hello world");
|
||||
getContact: (event) => {
|
||||
const service = event.target.getAttribute("data-value");
|
||||
module.then(modals => {
|
||||
event.target.closest(".modal").close();
|
||||
const card = new modals.Card(interactions);
|
||||
card.openPage(service);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.then(modals => {
|
||||
const card = new modals.Card(interactions);
|
||||
card.openPage("contact_card");
|
||||
card.openPage("contact");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -53,4 +58,5 @@ function updateTheme() {
|
|||
|
||||
// Set the current page theme, and listen for changes
|
||||
theme.addEventListener("change",updateTheme);
|
||||
updateTheme();
|
||||
updateTheme();
|
||||
window._debug.openContactsModal();
|
40
public/assets/pages/contact.html
Normal file
40
public/assets/pages/contact.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
<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);
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: var(--padding);
|
||||
}
|
||||
|
||||
.contact .item * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.contact .item img {
|
||||
height: 70%;
|
||||
}
|
||||
</style>
|
||||
<div class="contact">
|
||||
<div class="item center" data-action="getContact" data-value="contact_signal">
|
||||
<img src="assets/img/icons/signal.svg"/>
|
||||
<p>Signal</p>
|
||||
</div>
|
||||
<div class="item center" data-action="getContact" data-value="contact_email">
|
||||
<p>E-Mail</p>
|
||||
</div>
|
||||
<div class="item center" data-action="getContact">
|
||||
<p>
|
||||
</div>
|
||||
<div class="item center" data-action="getContact">
|
||||
</div>
|
||||
</div>
|
|
@ -1,27 +0,0 @@
|
|||
<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
public/assets/pages/contact_signal.html
Normal file
3
public/assets/pages/contact_signal.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<style>
|
||||
</style>
|
||||
<img src="assets/img/icons/signal.svg"/>
|
Loading…
Add table
Reference in a new issue