dev21w36d

This commit is contained in:
Victor Westerlund 2021-09-10 10:27:10 -04:00
parent 821ed27776
commit 9641533b24
8 changed files with 211 additions and 94 deletions

View file

@ -1,9 +1,5 @@
/* -- Transition overrides -- */ /* -- Transition overrides -- */
body {
transition: var(--transition) background-color;
}
body main .screen { body main .screen {
transition: var(--transition) transform; transition: var(--transition) transform;
transition-delay: calc(var(--transition) / 2); transition-delay: calc(var(--transition) / 2);
@ -39,13 +35,40 @@ body .modal.active ~ main .screen {
} }
.modal .button { .modal .button {
background-color: rgba(var(--comp-inverted),.05); align-self: stretch;
} }
.modal .button p { .modal .inner {
color: var(--color-inverted); transition: var(--transition) transform, var(--transition) opacity;
position: relative;
background-color: var(--color-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);
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 { .spinner.logo {
--size: 10vw; --size: 10vw;
--anim-speed: 1s; --anim-speed: 1s;
@ -70,30 +93,42 @@ body .modal.active ~ main .screen {
} }
} }
/* ---- */
.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 -- */ /* -- Cards -- */
.modal.card .inner { .modal.card .inner {
transition: var(--transition) transform, var(--transition) opacity;
position: relative;
background-color: var(--color-background);
width: calc(100vw - var(--padding));
max-width: 500px;
align-self: flex-end; align-self: flex-end;
box-sizing: border-box;
padding: var(--padding);
transform: translateY(1vh); transform: translateY(1vh);
border-radius: var(--border-radius);
opacity: 0;
display: flex;
flex-direction: column;
gap: var(--padding);
} }
.modal.card.active .inner { .modal.card.active .inner {
transform: translateY(0); transform: translateY(0);
opacity: 1;
} }
.modal.card .button[data-action="close"] { .modal.card .button[data-action="close"] {
margin-top: auto; margin-top: auto;
} }
/* -- Dialogs -- */
.modal.dialog .inner {
transform: scale(.95);
}
.modal.dialog.active .inner {
transform: scale(1);
}

View file

@ -78,7 +78,15 @@ main {
display: flex; display: flex;
} }
main.active { body.menuActive {
background-color: var(--color-contrast);
}
body.dark.menuActive {
background-color: black;
}
body.menuActive main {
transform: translateX(-100vw); transform: translateX(-100vw);
} }
@ -95,6 +103,10 @@ body.dark .screen.dark {
background-color: black; background-color: black;
} }
.screen .inner {
display: contents;
}
.screen .content { .screen .content {
box-sizing: border-box; box-sizing: border-box;
padding: calc(var(--padding) * 1.5); padding: calc(var(--padding) * 1.5);
@ -131,7 +143,6 @@ body.dark .screen.dark {
/* ---- */ /* ---- */
.button { .button {
background-color: var(--color-contrast);
text-align: center; text-align: center;
padding: 25px; padding: 25px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
@ -141,6 +152,16 @@ body.dark .screen.dark {
gap: var(--padding); gap: var(--padding);
} }
.button.solid {
background-color: var(--color-contrast);
color: var(--color-background);
}
.button.phantom {
background-color: rgba(var(--comp-inverted),.05);
color: var(--color-contrast);
}
.button svg { .button svg {
pointer-events: none; pointer-events: none;
fill: var(--color-contrast); fill: var(--color-contrast);
@ -150,15 +171,7 @@ body.dark .screen.dark {
.button p { .button p {
pointer-events: none; pointer-events: none;
font-size: clamp(16px,5vw,22px); font-size: clamp(16px,5vw,22px);
color: var(--color-background); color: inherit;
}
.button.phantom {
background-color: rgba(var(--comp-contrast),.1);
}
.button.phantom p {
color: var(--color-contrast);
} }
.button.loading p { .button.loading p {

View file

@ -12,19 +12,40 @@ class Component {
export class Button extends Component { export class Button extends Component {
constructor(properties) { constructor(properties) {
super("div"); super("div");
this.properties = properties;
this.element.classList.add("button"); this.element.classList.add("button");
this.setText(properties.text); this.setText();
this.setAction(properties.action); this.setAction();
this.setType();
} }
setText(text) { setText() {
if(!this.properties.text) {
return false;
}
const textElement = document.createElement("p"); const textElement = document.createElement("p");
textElement.innerText = text; textElement.innerText = this.properties.text;
this.element.appendChild(textElement); this.element.appendChild(textElement);
} }
setAction(action) { setAction() {
this.element.setAttribute("data-action",action); if(!this.properties.action) {
return false;
}
this.element.setAttribute("data-action",this.properties.action);
}
setType() {
const types = [
"solid",
"phantom"
];
const type = types.includes(this.properties.type) ? this.properties.type : false;
if(!this.properties.type || !type) {
return false;
}
this.element.classList.add(type);
} }
} }

View file

@ -16,6 +16,8 @@ class Modal extends Interaction {
interactions = Object.assign(interactions,extendedInteractions); interactions = Object.assign(interactions,extendedInteractions);
super(interactions,element); super(interactions,element);
this.transition = 300;
this.element = this.applyTemplate(element); this.element = this.applyTemplate(element);
this.element.close = () => this.close(); // Bind close to element prototype this.element.close = () => this.close(); // Bind close to element prototype
document.body.insertAdjacentElement("afterbegin",this.element); document.body.insertAdjacentElement("afterbegin",this.element);
@ -26,7 +28,15 @@ class Modal extends Interaction {
const url = `assets/pages/${page}`; const url = `assets/pages/${page}`;
const response = await fetch(url); const response = await fetch(url);
if(!response.ok) { if(!response.ok) {
throw new Error(`Modal: Failed to fetch page "${page}"`); 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(); return response.text();
} }
@ -68,21 +78,40 @@ class Modal extends Interaction {
} }
} }
// Overlay with a slide-in animation from the bottom of the viewport export class Dialog extends Modal {
export class Card extends Modal { constructor(interactions = {}) {
constructor(interactions) {
super(interactions); super(interactions);
this.transition = 300;
this.init(); this.init();
} }
init(slim) { 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("card");
this.element.classList.add("center"); this.element.classList.add("center");
const closeButton = new Button({ const closeButton = new Button({
text: "close", text: "close",
action: "close" action: "close",
type: "phantom"
}); });
this.bind(closeButton.element); this.bind(closeButton.element);
@ -91,19 +120,22 @@ export class Card extends Modal {
error(message) { error(message) {
const oops = document.createElement("p"); const oops = document.createElement("p");
const infoButton = new Button({ const infoButton = document.createElement("p");
text: "more info"
});
oops.classList.add("error"); oops.classList.add("error");
oops.innerText = "🤯\nSomething went wrong"; oops.innerText = "🤯\nSomething went wrong";
infoButton.innerText = "more info..";
infoButton.element.addEventListener("click",() => { infoButton.addEventListener("click",() => {
oops.innerText = "📋\n" + message; const details = new Dialog();
destroy(infoButton.element);
details.insertHTML(`<h1>📄 Error report</h1><pre>${message}</pre>`);
details.open();
this.close();
}); });
this.insertElement(infoButton.element); this.insertElement(infoButton);
this.insertElement(oops); this.insertElement(oops);
} }
@ -112,6 +144,7 @@ export class Card extends Modal {
// Show a spinner while fetching // Show a spinner while fetching
const spinner = document.createElement("div"); const spinner = document.createElement("div");
spinner.classList = "logo spinner"; spinner.classList = "logo spinner";
this.element.setAttribute("data-page",page);
this.insertElement(spinner); this.insertElement(spinner);
this.open(); this.open();

View file

@ -42,30 +42,6 @@ export default class Interaction extends Logging {
} }
} }
// Set the page theme color (and the theme-color meta tag)
setThemeColor(color) {
const meta = document.head.querySelector("meta[name='theme-color']");
const style = getComputedStyle(document.body);
if(!meta || !color) {
return false;
}
// Dark mode will always use the background color
if(document.body.classList.contains("dark")) {
color = "background";
}
if(color[0] !== "#") {
// Get CSS variable if color isn't a HEX code
color = style.getPropertyValue(`--color-${color}`);
color = color.replaceAll(" ","");
}
document.body.style.setProperty("background-color",color);
meta.setAttribute("content",color);
}
// Handle click/touch interactions // Handle click/touch interactions
pointerEvent(event) { pointerEvent(event) {
const target = event.target.closest(`[${this.attribute}]`); const target = event.target.closest(`[${this.attribute}]`);
@ -77,10 +53,5 @@ export default class Interaction extends Logging {
} }
// Execute the function from the data-action attribute // Execute the function from the data-action attribute
this.interactions[action](event); this.interactions[action](event);
// The button has requested a theme-color change
if(target.hasAttribute("data-theme-color")) {
this.setThemeColor(target.getAttribute("data-theme-color"));
}
} }
} }

View file

@ -17,7 +17,7 @@ const interactions = {
const menu = document.getElementsByTagName("main")[0]; const menu = document.getElementsByTagName("main")[0];
menu.style.setProperty("transition",`${speed}ms`); menu.style.setProperty("transition",`${speed}ms`);
menu.classList.toggle("active"); document.body.classList.toggle("menuActive");
setTimeout(() => menu.style.removeProperty("transition"),speed + 1); setTimeout(() => menu.style.removeProperty("transition"),speed + 1);
}, },
openContactCard: () => { openContactCard: () => {
@ -30,6 +30,14 @@ const interactions = {
const card = new modals.Card(interactions); const card = new modals.Card(interactions);
card.openPage(service); card.openPage(service);
}); });
},
copyText: (event) => {
const memory = event.target.innerText;
event.target.classList.add("bounce");
event.target.innerText = "Copied!";
setTimeout(() => {
event.target.innerText = memory;
},this.transition);
} }
}; };
@ -52,11 +60,8 @@ function updateTheme() {
document.body.classList.add("dark"); document.body.classList.add("dark");
return; return;
} }
main.setThemeColor("background");
} }
// Set the current page theme, and listen for changes // Set the current page theme, and listen for changes
theme.addEventListener("change",updateTheme); theme.addEventListener("change",updateTheme);
updateTheme(); updateTheme();
window._debug.openContactsModal();

View file

@ -1,13 +1,15 @@
<style> <style>
.contact { .contact {
align-self: stretch;
display: grid; display: grid;
grid-template-rows: repeat(2, 1fr);
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: var(--padding); gap: var(--padding);
} }
.contact .item { .contact .item {
height: 140px; --size: 1fr;
width: var(--size);
height: var(--size);
border-radius: var(--border-radius); border-radius: var(--border-radius);
background-color: rgba(var(--comp-inverted),.05); background-color: rgba(var(--comp-inverted),.05);
flex-direction: column; flex-direction: column;
@ -23,6 +25,12 @@
.contact .item img { .contact .item img {
height: 70%; height: 70%;
} }
@media (max-width: 258px) {
.contact {
grid-template-columns: 1fr;
}
}
</style> </style>
<div class="contact"> <div class="contact">
<div class="item center" data-action="getContact" data-value="contact_signal"> <div class="item center" data-action="getContact" data-value="contact_signal">
@ -30,11 +38,7 @@
<p>Signal</p> <p>Signal</p>
</div> </div>
<div class="item center" data-action="getContact" data-value="contact_email"> <div class="item center" data-action="getContact" data-value="contact_email">
<img src="assets/img/icons/email.svg"/>
<p>E-Mail</p> <p>E-Mail</p>
</div> </div>
<div class="item center" data-action="getContact">
<p>
</div>
<div class="item center" data-action="getContact">
</div>
</div> </div>

View file

@ -1,3 +1,38 @@
<style> <style>
body:not(.dark) .modal[data-page="contact_signal"] .inner {
--comp-inverted: 255,255,255;
--comp-background: 58,118,240;
--color-background: rgb(var(--comp-background));
--color-inverted: rgb(var(--comp-inverted));
}
body:not(.dark) .modal[data-page="contact_signal"] .button.solid {
background-color: var(--color-inverted);
color: var(--color-background);
}
.modal .inner > h1,
.modal .inner > p,
.modal .button.phantom {
color: var(--color-inverted);
}
/* ---- */
#logo_signal {
width: clamp(100px,50%,200px);
}
#number {
background: black;
padding: 10px 15px;
border-radius: 6px;
}
</style> </style>
<img src="assets/img/icons/signal.svg"/> <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">
<p>copy number</p>
</div>