dev21w36f-a

This commit is contained in:
Victor Westerlund 2021-09-12 15:57:38 +02:00
parent b05c451f11
commit 7d80341f34
7 changed files with 219 additions and 64 deletions

View file

@ -13,6 +13,10 @@ body .modal.active ~ main .screen {
pointer-events: none;
}
.modal.active + .modal {
z-index: 5;
}
/* -- Boilerplate -- */
.modal {

View file

@ -67,7 +67,9 @@
color: var(--swatch-accent);
}
a,
picture {
text-decoration: none;
display: contents;
}

View file

@ -67,6 +67,64 @@ class Modal extends Interaction {
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(`<h1>📄 Error report</h1><pre>${message}</pre>`);
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);
}
@ -117,58 +175,4 @@ export class Card extends Modal {
this.bind(closeButton.element);
this.inner.appendChild(closeButton.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(`<h1>📄 Error report</h1><pre>${message}</pre>`);
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();
// Attempt to fetch the requested url again
this.openPage(page);
});
this.insertElement(tryAgain.element);
this.error(error);
})
.finally(() => destroy(spinner));
}
}

View file

@ -1,6 +1,6 @@
// Copyright © Victor Westerlund - No libraries! 😲
import { default as Preload } from "./modules/Preload.mjs";
import { default as Interaction } from "./modules/UI.mjs";
import { default as Interaction, destroy } from "./modules/UI.mjs";
import "./modules/Debugging.mjs";
// Load these assets when the DOM is ready (not needed right away)
@ -37,7 +37,7 @@ const interactions = {
const module = import("./modules/Modals.mjs");
const interactions = {
getContact: (event) => {
const service = event.target.getAttribute("data-value");
const service = event.target.dataset.value;
module.then(modals => {
event.target.closest(".modal").close();
const card = new modals.Card(interactions);
@ -45,12 +45,21 @@ const interactions = {
});
},
copyText: (event) => {
const memory = event.target.innerText;
event.target.classList.add("bounce");
event.target.innerText = "copied!";
event.target.classList.add("copied");
const copied = document.createElement("p");
copied.innerText = "copied!";
event.target.appendChild(copied);
setTimeout(() => {
event.target.innerText = memory;
event.target.classList.remove("copied");
destroy(copied);
},1000);
},
showPgpKey: () => {
module.then(modals => {
const dialog = new modals.Dialog();
dialog.openPage("contact_email_pgp");
});
}
};
@ -58,10 +67,6 @@ const interactions = {
const card = new modals.Card(interactions);
card.openPage("contact");
});
},
openSearch: () => {
const module = import("./modules/Search.mjs");
document.body.classList.add("searchActive");
}
}

View file

@ -0,0 +1,64 @@
<style>
.button.copied {
pointer-events: none;
animation: beat 500ms forwards;
animation-delay: 200ms;
}
.button.copied svg,
.button.copied p:first-of-type {
opacity: 0;
}
.button.copied p:last-of-type {
position: absolute;
animation: slide 1000ms forwards;
}
@keyframes beat {
0% { transform: scale(1); }
25% { transform: scale(.95); }
55% { transform: scale(1.05); }
100% { transform: scale(1); }
}
@keyframes slide {
0% { transform: translateY(calc(var(--padding))); opacity: 0; }
30% { transform: translateY(0); opacity: 1; }
70% { transform: translateY(0); opacity: 1; }
100% { transform: translateY(calc(var(--padding) * -1)); opacity: 0; }
}
#interaction {
color: var(--swatch-accent);
cursor: pointer;
}
#interaction::before {
content: "tap ";
}
@media (max-width: 300px) {
.button.copied p:last-of-type {
display: initial;
}
}
@media (pointer: fine) {
#interaction::before {
content: "click ";
}
}
</style>
<div class="button phantom" data-action="showPgpKey">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12.65 10C11.83 7.67 9.61 6 7 6c-3.31 0-6 2.69-6 6s2.69 6 6 6c2.61 0 4.83-1.67 5.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
<p>show PGP key</p>
</div>
<p></p>
<h1>hello@victorwesterlund.com</h1>
<p>You can also <a id="interaction" href="mailto:hello@victorwesterlund.com?subject=Hello Victor!">here</a> to send a mail directly from your mail app</p>
<p></p>
<div class="button solid" data-action="copyText">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18 2H9c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H9V4h9v12zM3 15v-2h2v2H3zm0-5.5h2v2H3v-2zM10 20h2v2h-2v-2zm-7-1.5v-2h2v2H3zM5 22c-1.1 0-2-.9-2-2h2v2zm3.5 0h-2v-2h2v2zm5 0v-2h2c0 1.1-.9 2-2 2zM5 6v2H3c0-1.1.9-2 2-2z"/></svg>
<p>copy email</p>
</div>

View file

@ -0,0 +1,39 @@
<style>
</style>
<h1>🔑 PGP Public Key</h1>
<pre>
-----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-----</pre>
<h2>5466 B1EB 2F44 6D3D DC34 E9F7 5BE0 CB0B E3BB 69DA</h2>
<a href="https://storage.googleapis.com/public.victorwesterlund.com/publickey.gpg"><div class="button solid">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 20h14v-2H5v2zM19 9h-4V3H9v6H5l7 7 7-7z"/></svg>
<p>download .gpg</p>
</div></a>

View file

@ -29,10 +29,47 @@
padding: 10px 15px;
border-radius: 6px;
}
.button.copied {
pointer-events: none;
animation: beat 500ms forwards;
animation-delay: 200ms;
}
.button.copied svg,
.button.copied p:first-of-type {
opacity: 0;
}
.button.copied p:last-of-type {
position: absolute;
animation: slide 1000ms forwards;
}
@keyframes beat {
0% { transform: scale(1); }
25% { transform: scale(.95); }
55% { transform: scale(1.05); }
100% { transform: scale(1); }
}
@keyframes slide {
0% { transform: translateY(calc(var(--padding))); opacity: 0; }
30% { transform: translateY(0); opacity: 1; }
70% { transform: translateY(0); opacity: 1; }
100% { transform: translateY(calc(var(--padding) * -1)); opacity: 0; }
}
@media (max-width: 300px) {
.button.copied p:last-of-type {
display: initial;
}
}
</style>
<img id="logo_signal" src="assets/img/icons/signal.svg"/>
<h1 id="number">+4670-2452459</h1>
<p>Signal is a free and encrypted message platform with apps for all major platforms.</p>
<div class="button solid" data-action="copyText">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18 2H9c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H9V4h9v12zM3 15v-2h2v2H3zm0-5.5h2v2H3v-2zM10 20h2v2h-2v-2zm-7-1.5v-2h2v2H3zM5 22c-1.1 0-2-.9-2-2h2v2zm3.5 0h-2v-2h2v2zm5 0v-2h2c0 1.1-.9 2-2 2zM5 6v2H3c0-1.1.9-2 2-2z"/></svg>
<p>copy number</p>
</div>