dev21w36e

This commit is contained in:
Victor Westerlund 2021-09-12 12:14:10 +02:00
parent 9641533b24
commit b05c451f11
10 changed files with 243 additions and 88 deletions

View file

@ -22,16 +22,16 @@ body .modal.active ~ main .screen {
left: 0;
width: 100vw;
height: 100%;
z-index: 1;
z-index: 10;
pointer-events: none;
box-sizing: border-box;
background-color: rgba(var(--comp-inverted),0);
background-color: rgba(var(--palette-inverted),0);
padding: var(--padding);
}
.modal.active {
pointer-events: all;
background-color: rgba(var(--comp-inverted),.4);
background-color: rgba(var(--palette-inverted),.4);
}
.modal .button {
@ -41,7 +41,7 @@ body .modal.active ~ main .screen {
.modal .inner {
transition: var(--transition) transform, var(--transition) opacity;
position: relative;
background-color: var(--color-background);
background-color: var(--swatch-background);
width: calc(100vw - var(--padding));
max-width: 500px;
max-height: 100%;
@ -50,6 +50,7 @@ body .modal.active ~ main .screen {
box-sizing: border-box;
padding: var(--padding);
border-radius: var(--border-radius);
box-shadow: 0 3px 30px 0 rgba(var(--palette-contrast),.2);
opacity: 0;
display: flex;
flex-direction: column;
@ -70,7 +71,7 @@ body .modal.active ~ main .screen {
/* ---- */
.spinner.logo {
--size: 10vw;
--size: clamp(30px,5vw,60px);
--anim-speed: 1s;
align-self: center;
margin-top: var(--padding);
@ -84,7 +85,7 @@ body .modal.active ~ main .screen {
}
.error:first-line {
font-size: 15vw;
font-size: 50px;
}
@keyframes logoSpinner {
@ -131,4 +132,35 @@ body .modal.active ~ main .screen {
.modal.dialog.active .inner {
transform: scale(1);
}
@media (min-aspect-ratio: 14/9) {
/* -- Transition overrides -- */
body main .screen {
transition: unset;
}
body .modal.active ~ main .screen {
transition: unset;
transform: unset;
opacity: unset;
}
body .modal {
transition: var(--transition);
transition-delay: calc(var(--transition) / 2);
backdrop-filter: blur(0);
}
body .modal.active {
transition-delay: 1ms;
backdrop-filter: blur(10px);
}
/* -- Boilerplate -- */
.modal.card .inner {
align-self: unset;
}
}

View file

@ -1,16 +1,19 @@
/* Copyright © Victor Westerlund - No libraries! 😲 */
:root {
--comp-background: 255,255,255;
--comp-inverted: 0,0,0;
--comp-contrast: 33,33,33;
--comp-accent: 22,183,255;
/* Component colors */
--palette-background: 255,255,255;
--palette-inverted: 0,0,0;
--palette-contrast: 33,33,33;
--palette-accent: 22,183,255;
--color-background: rgb(var(--comp-background));
--color-inverted: rgb(var(--comp-inverted));
--color-contrast: rgb(var(--comp-contrast));
--color-accent: rgb(var(--comp-accent));
/* 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;
@ -18,15 +21,19 @@
}
.dark {
--comp-background: 33,33,33;
--comp-inverted: 255,255,255;
--comp-contrast: 255,255,255;
--comp-accent: 255,255,255;
--palette-background: 33,33,33;
--palette-inverted: 255,255,255;
--palette-contrast: 255,255,255;
--palette-accent: 255,255,255;
--color-background: rgb(var(--comp-background));
--color-inverted: rgb(var(--comp-inverted));
--color-contrast: rgb(var(--comp-contrast));
--color-accent: rgb(var(--comp-accent));
--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 {
@ -52,12 +59,12 @@
* {
margin: 0;
font-family: "Roboto Mono","Arial",sans-serif;
color: var(--color-contrast);
color: var(--swatch-contrast);
}
*::selection {
background-color: var(--color-highlight);
color: var(--color-accent);
background-color: var(--swatch-highlight);
color: var(--swatch-accent);
}
picture {
@ -79,7 +86,7 @@ main {
}
body.menuActive {
background-color: var(--color-contrast);
background-color: var(--swatch-contrast);
}
body.dark.menuActive {
@ -93,8 +100,13 @@ body.menuActive main {
/* ---- */
.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-accent);
--background-pattern-size: calc(var(--padding) + 2px) calc(var(--padding) + 2px);
width: 100vw;
background-color: var(--color-background);
background-color: var(--swatch-background);
display: flex;
flex-direction: column;
}
@ -108,6 +120,7 @@ body.dark .screen.dark {
}
.screen .content {
position: relative;
box-sizing: border-box;
padding: calc(var(--padding) * 1.5);
padding-top: 0;
@ -131,13 +144,13 @@ body.dark .screen.dark {
width: 0;
height: 0;
border: var(--skew) solid transparent;
border-top: var(--size) solid var(--color-accent);
border-top: var(--size) solid var(--swatch-accent);
}
.logo::after {
content: "";
border: var(--skew) solid transparent;
border-top: var(--size) solid rgba(var(--comp-accent),.3);
border-top: var(--size) solid rgba(var(--palette-accent),.3);
}
/* ---- */
@ -146,6 +159,7 @@ body.dark .screen.dark {
text-align: center;
padding: 25px;
border-radius: var(--border-radius);
font-size: clamp(16px,5vw,22px);
display: flex;
justify-content: center;
align-items: center;
@ -153,24 +167,26 @@ body.dark .screen.dark {
}
.button.solid {
background-color: var(--color-contrast);
color: var(--color-background);
background-color: var(--swatch-contrast);
color: var(--swatch-background);
fill: var(--swatch-background);
}
.button.phantom {
background-color: rgba(var(--comp-inverted),.05);
color: var(--color-contrast);
background-color: rgba(var(--palette-inverted),.05);
color: var(--swatch-contrast);
fill: var(--swatch-contrast);
}
.button svg {
pointer-events: none;
fill: var(--color-contrast);
fill: inherit;
transform: scale(1.2);
}
.button p {
pointer-events: none;
font-size: clamp(16px,5vw,22px);
font-size: inherit;
color: inherit;
}
@ -215,13 +231,13 @@ header .hamburger {
header .hamburger div {
width: 100%;
height: 2px;
background: var(--color-contrast);
box-shadow: 0 -10px 0 0 var(--color-contrast), 0 10px 0 0 var(--color-contrast);
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(--color-contrast);
stroke: var(--swatch-contrast);
stroke-linecap: round;
stroke-width: 2;
}
@ -229,13 +245,17 @@ header .hamburger svg {
header .spacer {
width: 1px;
height: 80%;
background-color: rgba(var(--comp-contrast),.2);
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);
@ -244,13 +264,20 @@ header .logo {
/* -- 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 {
@ -268,7 +295,7 @@ header .logo {
width: 0;
height: 0;
border: solid var(--size) transparent;
border-bottom: solid calc(var(--size) * 2) rgba(var(--comp-accent),.1);
border-bottom: solid calc(var(--size) * 2) rgba(var(--palette-accent),.1);
transform-origin: 50% 75%;
transform: rotate(20deg);
}
@ -292,6 +319,50 @@ header .logo {
margin-top: auto;
}
/* -- Media queries -- */
/* Wide-screen */
@media (min-aspect-ratio: 14/9) {
/* -- Cornerstones -- */
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 {
width: 50vw;
flex-direction: row;
}
body.dark .screen {
--swatch-background: black;
}
/* -- Screens > Menu -- */
.screen.menu .content {
padding-top: calc(var(--padding) * 1.5);
}
}
/* Narrow display */
@media (max-width: 300px) {
.button svg:not(.hidden) ~ p,
header .logo {
@ -299,6 +370,7 @@ header .logo {
}
}
/* Super-narrow display */
@media (max-width: 230px) {
header {
justify-content: center;
@ -308,4 +380,22 @@ header .logo {
header p {
display: none;
}
}
/* -- Media queries > Media features -- */
@media (pointer: fine) {
.button {
cursor: pointer;
}
}
@media (any-hover: hover) {
.button {
transition: var(--transition) background-color;
}
.button.phantom:hover {
background-color: rgba(var(--palette-inverted),.2);
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0l-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z"/></svg>

After

Width:  |  Height:  |  Size: 274 B

View file

@ -0,0 +1 @@
<svg version="1.1" id="katman_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1024 1024" xml:space="preserve"><style>.st0{fill:#3a76f0}</style><path class="st0" d="M28.4 241.6v540.7c0 117.7 95.5 213.2 213.2 213.2h540.7c117.7 0 213.2-95.5 213.2-213.2V241.6c0-117.7-95.5-213.2-213.2-213.2H241.6c-117.7 0-213.2 95.5-213.2 213.2z"/><path d="M430.1 180.9l7.7 31c-30.2 7.4-59.1 19.4-85.7 35.4L335.7 220c29.3-17.7 61.2-30.9 94.4-39.1zm163.8 0l-7.7 31c30.2 7.4 59.1 19.4 85.7 35.4l16.5-27.4c-29.4-17.6-61.2-30.8-94.5-39zM220 335.7c-17.7 29.3-30.9 61.2-39.1 94.4l31 7.7c7.4-30.2 19.4-59.1 35.4-85.7L220 335.7zM202.9 512c0-15.5 1.1-31 3.5-46.3l-31.6-4.8c-5.1 33.9-5.1 68.3 0 102.2l31.6-4.8c-2.3-15.3-3.5-30.8-3.5-46.3zm485.4 292l-16.4-27.4c-26.6 16.1-55.4 28-85.6 35.4l7.7 31c33.2-8.2 65-21.3 94.3-39zm132.8-292c0 15.5-1.1 31-3.5 46.3l31.6 4.8c5.1-33.9 5.1-68.3 0-102.2l-31.6 4.8c2.3 15.3 3.5 30.8 3.5 46.3zm22 81.8l-31-7.7c-7.4 30.2-19.4 59.1-35.4 85.7l27.4 16.5c17.6-29.3 30.8-61.2 39-94.5zM558.3 817.6c-30.7 4.6-61.9 4.6-92.6 0l-4.8 31.6c33.9 5.1 68.3 5.1 102.2 0l-4.8-31.6zm202.5-122.3c-18.4 25-40.5 47-65.5 65.4l19 25.7c27.6-20.3 51.9-44.5 72.3-72l-25.8-19.1zm-65.5-432.1c25 18.4 47.1 40.5 65.5 65.5l25.7-19.2c-20.3-27.5-44.6-51.8-72-72l-19.2 25.7zm-432.1 65.5c18.4-25 40.5-47.1 65.5-65.5l-19.2-25.7c-27.5 20.3-51.8 44.6-72 72l25.7 19.2zm540.8 7l-27.4 16.4c16.1 26.6 28 55.4 35.4 85.6l31-7.7c-8.1-33.2-21.3-65-39-94.3zM465.7 206.4c30.7-4.6 61.9-4.6 92.6 0l4.8-31.6c-33.9-5.1-68.3-5.1-102.2 0l4.8 31.6zM279.6 795l-66 15.4 15.4-66-31.1-7.3-15.4 66c-2.5 10.8.7 22.1 8.5 29.9s19.1 11 29.9 8.5l66-15.1-7.3-31.4zm-75.1-86.5l31.1 7.2 10.7-45.8c-15.5-26.1-27.1-54.4-34.4-83.9l-31 7.7c7 28.3 17.5 55.5 31.4 81l-7.8 33.8zm149.2 69.3L308 788.5l7.2 31.1 33.7-7.8c25.6 13.9 52.8 24.5 81.1 31.4l7.7-31c-29.4-7.3-57.6-19-83.7-34.6l-.3.2zM512 234.9c-100.8.1-193.7 54.9-242.4 143.1s-45.7 196 8 281.4L251 773.1l113.7-26.6c99.7 62.8 228.2 55.7 320.4-17.7S812.9 531.7 774 420.5c-39.2-111.3-144.2-185.7-262-185.6z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -9,7 +9,9 @@ class Debug {
const functions = [
"list",
"toggleMenu",
"openContactsModal"
"openContactsModal",
"invalidCard",
"infiniteLoadingCard"
];
console.log("Available functions:",functions.map(f => `window._debug.${f}();`));
}
@ -52,6 +54,18 @@ class Debug {
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();

View file

@ -19,7 +19,7 @@ class Modal extends Interaction {
this.transition = 300;
this.element = this.applyTemplate(element);
this.element.close = () => this.close(); // Bind close to element prototype
this.element.close = () => this.close(); // Bind modal close to element prototype
document.body.insertAdjacentElement("afterbegin",this.element);
}
@ -124,8 +124,8 @@ export class Card extends Modal {
oops.classList.add("error");
oops.innerText = "🤯\nSomething went wrong";
infoButton.innerText = "more info..";
infoButton.innerText = "more info..";
infoButton.addEventListener("click",() => {
const details = new Dialog();
@ -153,7 +153,22 @@ export class Card extends Modal {
this.insertHTML(html);
this.bindAll(this.inner);
})
.catch(error => this.error(error))
.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,24 +1,37 @@
// 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";
import "./modules/Debugging.mjs";
// Load these assets when the DOM is ready (not needed right away)
const preload = new Preload([
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 speed = 200;
const transition = 200;
const menu = document.getElementsByTagName("main")[0];
menu.style.setProperty("transition",`${speed}ms`);
// Animate menu state change
menu.style.setProperty("transition",`${transition}ms`);
document.body.classList.toggle("menuActive");
setTimeout(() => menu.style.removeProperty("transition"),speed + 1);
// Remove transition CSS when finished. Wonky resize effects otherwise
setTimeout(() => menu.style.removeProperty("transition"),transition + 1);
},
openContactCard: () => {
const module = import("./modules/Modals.mjs");
@ -34,10 +47,10 @@ const interactions = {
copyText: (event) => {
const memory = event.target.innerText;
event.target.classList.add("bounce");
event.target.innerText = "Copied!";
event.target.innerText = "copied!";
setTimeout(() => {
event.target.innerText = memory;
},this.transition);
},1000);
}
};
@ -45,23 +58,16 @@ const interactions = {
const card = new modals.Card(interactions);
card.openPage("contact");
});
}
}
const theme = window.matchMedia("(prefers-color-scheme: dark)");
const main = new Interaction(interactions,document.body);
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;
},
openSearch: () => {
const module = import("./modules/Search.mjs");
document.body.classList.add("searchActive");
}
}
// 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);
updateTheme();

View file

@ -11,7 +11,7 @@
width: var(--size);
height: var(--size);
border-radius: var(--border-radius);
background-color: rgba(var(--comp-inverted),.05);
background-color: rgba(var(--palette-inverted),.05);
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
@ -23,21 +23,21 @@
}
.contact .item img {
height: 70%;
height: 10vh;
}
@media (max-width: 258px) {
@media (max-width: 300px) {
.contact {
grid-template-columns: 1fr;
}
}
</style>
<div class="contact">
<div class="item center" data-action="getContact" data-value="contact_signal">
<div class="item button phantom" 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">
<div class="item button phantom" data-action="getContact" data-value="contact_email">
<img src="assets/img/icons/email.svg"/>
<p>E-Mail</p>
</div>

View file

@ -1,21 +1,21 @@
<style>
body:not(.dark) .modal[data-page="contact_signal"] .inner {
--comp-inverted: 255,255,255;
--comp-background: 58,118,240;
--palette-inverted: 255,255,255;
--palette-background: 58,118,240;
--color-background: rgb(var(--comp-background));
--color-inverted: rgb(var(--comp-inverted));
--swatch-background: rgb(var(--palette-background));
--swatch-inverted: rgb(var(--palette-inverted));
}
body:not(.dark) .modal[data-page="contact_signal"] .button.solid {
background-color: var(--color-inverted);
color: var(--color-background);
background-color: var(--swatch-inverted);
color: var(--swatch-background);
}
.modal .inner > h1,
.modal .inner > p,
.modal .button.phantom {
color: var(--color-inverted);
color: var(--swatch-inverted);
}
/* ---- */

View file

@ -7,11 +7,9 @@
<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="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">
<link rel="icon" href="assets/img/favicon.png">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<main>
@ -46,19 +44,17 @@
<div class="logo"></div>
<p>victor westerlund</p>
</header>
<div class="wide">
<h1>victor westerlund</h1>
</div>
<div class="content">
<div class="button phantom">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
<p>search stuff..</p>
</div>
<div class="spacer"></div>
<div class="button phantom" data-action="openContactCard">
<p>contact me</p>
</div>
</div>
</div>
</main>
<script src="assets/js/script.js" type="module"></script>
<script src="assets/js/nomodule.js" nomodule></script>
<script type="module" src="assets/js/script.js"></script>
<script nomodule src="assets/js/nomodule.js"></script>
</body>
</html>