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; left: 0;
width: 100vw; width: 100vw;
height: 100%; height: 100%;
z-index: 1; z-index: 10;
pointer-events: none; pointer-events: none;
box-sizing: border-box; box-sizing: border-box;
background-color: rgba(var(--comp-inverted),0); background-color: rgba(var(--palette-inverted),0);
padding: var(--padding); padding: var(--padding);
} }
.modal.active { .modal.active {
pointer-events: all; pointer-events: all;
background-color: rgba(var(--comp-inverted),.4); background-color: rgba(var(--palette-inverted),.4);
} }
.modal .button { .modal .button {
@ -41,7 +41,7 @@ body .modal.active ~ main .screen {
.modal .inner { .modal .inner {
transition: var(--transition) transform, var(--transition) opacity; transition: var(--transition) transform, var(--transition) opacity;
position: relative; position: relative;
background-color: var(--color-background); background-color: var(--swatch-background);
width: calc(100vw - var(--padding)); width: calc(100vw - var(--padding));
max-width: 500px; max-width: 500px;
max-height: 100%; max-height: 100%;
@ -50,6 +50,7 @@ body .modal.active ~ main .screen {
box-sizing: border-box; box-sizing: border-box;
padding: var(--padding); padding: var(--padding);
border-radius: var(--border-radius); border-radius: var(--border-radius);
box-shadow: 0 3px 30px 0 rgba(var(--palette-contrast),.2);
opacity: 0; opacity: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -70,7 +71,7 @@ body .modal.active ~ main .screen {
/* ---- */ /* ---- */
.spinner.logo { .spinner.logo {
--size: 10vw; --size: clamp(30px,5vw,60px);
--anim-speed: 1s; --anim-speed: 1s;
align-self: center; align-self: center;
margin-top: var(--padding); margin-top: var(--padding);
@ -84,7 +85,7 @@ body .modal.active ~ main .screen {
} }
.error:first-line { .error:first-line {
font-size: 15vw; font-size: 50px;
} }
@keyframes logoSpinner { @keyframes logoSpinner {
@ -132,3 +133,34 @@ body .modal.active ~ main .screen {
.modal.dialog.active .inner { .modal.dialog.active .inner {
transform: scale(1); 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! 😲 */ /* Copyright © Victor Westerlund - No libraries! 😲 */
:root { :root {
--comp-background: 255,255,255; /* Component colors */
--comp-inverted: 0,0,0; --palette-background: 255,255,255;
--comp-contrast: 33,33,33; --palette-inverted: 0,0,0;
--comp-accent: 22,183,255; --palette-contrast: 33,33,33;
--palette-accent: 22,183,255;
--color-background: rgb(var(--comp-background)); /* Compiled colors */
--color-inverted: rgb(var(--comp-inverted)); --swatch-background: rgb(var(--palette-background));
--color-contrast: rgb(var(--comp-contrast)); --swatch-inverted: rgb(var(--palette-inverted));
--color-accent: rgb(var(--comp-accent)); --swatch-contrast: rgb(var(--palette-contrast));
--swatch-accent: rgb(var(--palette-accent));
/* Default styles */
--padding: 20px; --padding: 20px;
--border-radius: 10px; --border-radius: 10px;
--header-height: 100px; --header-height: 100px;
@ -18,15 +21,19 @@
} }
.dark { .dark {
--comp-background: 33,33,33; --palette-background: 33,33,33;
--comp-inverted: 255,255,255; --palette-inverted: 255,255,255;
--comp-contrast: 255,255,255; --palette-contrast: 255,255,255;
--comp-accent: 255,255,255; --palette-accent: 255,255,255;
--color-background: rgb(var(--comp-background)); --swatch-background: rgb(var(--palette-background));
--color-inverted: rgb(var(--comp-inverted)); --swatch-inverted: rgb(var(--palette-inverted));
--color-contrast: rgb(var(--comp-contrast)); --swatch-contrast: rgb(var(--palette-contrast));
--color-accent: rgb(var(--comp-accent)); --swatch-accent: rgb(var(--palette-accent));
}
.wide {
display: none; /* Hide wide-screen elements */
} }
@font-face { @font-face {
@ -52,12 +59,12 @@
* { * {
margin: 0; margin: 0;
font-family: "Roboto Mono","Arial",sans-serif; font-family: "Roboto Mono","Arial",sans-serif;
color: var(--color-contrast); color: var(--swatch-contrast);
} }
*::selection { *::selection {
background-color: var(--color-highlight); background-color: var(--swatch-highlight);
color: var(--color-accent); color: var(--swatch-accent);
} }
picture { picture {
@ -79,7 +86,7 @@ main {
} }
body.menuActive { body.menuActive {
background-color: var(--color-contrast); background-color: var(--swatch-contrast);
} }
body.dark.menuActive { body.dark.menuActive {
@ -93,8 +100,13 @@ body.menuActive main {
/* ---- */ /* ---- */
.screen { .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; width: 100vw;
background-color: var(--color-background); background-color: var(--swatch-background);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@ -108,6 +120,7 @@ body.dark .screen.dark {
} }
.screen .content { .screen .content {
position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: calc(var(--padding) * 1.5); padding: calc(var(--padding) * 1.5);
padding-top: 0; padding-top: 0;
@ -131,13 +144,13 @@ body.dark .screen.dark {
width: 0; width: 0;
height: 0; height: 0;
border: var(--skew) solid transparent; border: var(--skew) solid transparent;
border-top: var(--size) solid var(--color-accent); border-top: var(--size) solid var(--swatch-accent);
} }
.logo::after { .logo::after {
content: ""; content: "";
border: var(--skew) solid transparent; 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; text-align: center;
padding: 25px; padding: 25px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
font-size: clamp(16px,5vw,22px);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -153,24 +167,26 @@ body.dark .screen.dark {
} }
.button.solid { .button.solid {
background-color: var(--color-contrast); background-color: var(--swatch-contrast);
color: var(--color-background); color: var(--swatch-background);
fill: var(--swatch-background);
} }
.button.phantom { .button.phantom {
background-color: rgba(var(--comp-inverted),.05); background-color: rgba(var(--palette-inverted),.05);
color: var(--color-contrast); color: var(--swatch-contrast);
fill: var(--swatch-contrast);
} }
.button svg { .button svg {
pointer-events: none; pointer-events: none;
fill: var(--color-contrast); fill: inherit;
transform: scale(1.2); transform: scale(1.2);
} }
.button p { .button p {
pointer-events: none; pointer-events: none;
font-size: clamp(16px,5vw,22px); font-size: inherit;
color: inherit; color: inherit;
} }
@ -215,13 +231,13 @@ header .hamburger {
header .hamburger div { header .hamburger div {
width: 100%; width: 100%;
height: 2px; height: 2px;
background: var(--color-contrast); background: var(--swatch-contrast);
box-shadow: 0 -10px 0 0 var(--color-contrast), 0 10px 0 0 var(--color-contrast); box-shadow: 0 -10px 0 0 var(--swatch-contrast), 0 10px 0 0 var(--swatch-contrast);
} }
header .hamburger svg { header .hamburger svg {
fill: none; fill: none;
stroke: var(--color-contrast); stroke: var(--swatch-contrast);
stroke-linecap: round; stroke-linecap: round;
stroke-width: 2; stroke-width: 2;
} }
@ -229,13 +245,17 @@ header .hamburger svg {
header .spacer { header .spacer {
width: 1px; width: 1px;
height: 80%; height: 80%;
background-color: rgba(var(--comp-contrast),.2); background-color: rgba(var(--palette-contrast),.2);
} }
.dark header .spacer { .dark header .spacer {
background-color: black; background-color: black;
} }
body.dark .dark header .spacer {
background-color: rgba(var(--palette-contrast),.2);
}
header .logo { header .logo {
--size: 25px; --size: 25px;
margin-top: calc(var(--size) / 2); margin-top: calc(var(--size) / 2);
@ -244,13 +264,20 @@ header .logo {
/* -- Screen > Landingpage -- */ /* -- Screen > Landingpage -- */
.screen.landingpage {
background: var(--background-pattern);
background-size: var(--background-pattern-size);
}
.screen.landingpage .content { .screen.landingpage .content {
padding-bottom: 0; padding-bottom: 0;
} }
.screen.landingpage img { .screen.landingpage img {
position: relative;
width: clamp(100px,80vw,40vh); width: clamp(100px,80vw,40vh);
align-self: flex-end; align-self: flex-end;
z-index: 1;
} }
.screen.landingpage .pattern { .screen.landingpage .pattern {
@ -268,7 +295,7 @@ header .logo {
width: 0; width: 0;
height: 0; height: 0;
border: solid var(--size) transparent; 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-origin: 50% 75%;
transform: rotate(20deg); transform: rotate(20deg);
} }
@ -292,6 +319,50 @@ header .logo {
margin-top: auto; 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) { @media (max-width: 300px) {
.button svg:not(.hidden) ~ p, .button svg:not(.hidden) ~ p,
header .logo { header .logo {
@ -299,6 +370,7 @@ header .logo {
} }
} }
/* Super-narrow display */
@media (max-width: 230px) { @media (max-width: 230px) {
header { header {
justify-content: center; justify-content: center;
@ -309,3 +381,21 @@ header .logo {
display: none; 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 = [ const functions = [
"list", "list",
"toggleMenu", "toggleMenu",
"openContactsModal" "openContactsModal",
"invalidCard",
"infiniteLoadingCard"
]; ];
console.log("Available functions:",functions.map(f => `window._debug.${f}();`)); console.log("Available functions:",functions.map(f => `window._debug.${f}();`));
} }
@ -52,6 +54,18 @@ class Debug {
card.openPage("invalid_card"); 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(); export default window._debug = new Debug();

View file

@ -19,7 +19,7 @@ class Modal extends Interaction {
this.transition = 300; 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 modal close to element prototype
document.body.insertAdjacentElement("afterbegin",this.element); document.body.insertAdjacentElement("afterbegin",this.element);
} }
@ -124,8 +124,8 @@ export class Card extends Modal {
oops.classList.add("error"); oops.classList.add("error");
oops.innerText = "🤯\nSomething went wrong"; oops.innerText = "🤯\nSomething went wrong";
infoButton.innerText = "more info..";
infoButton.innerText = "more info..";
infoButton.addEventListener("click",() => { infoButton.addEventListener("click",() => {
const details = new Dialog(); const details = new Dialog();
@ -153,7 +153,22 @@ export class Card extends Modal {
this.insertHTML(html); this.insertHTML(html);
this.bindAll(this.inner); 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)); .finally(() => destroy(spinner));
} }
} }

View file

@ -1,24 +1,37 @@
// Copyright © Victor Westerlund - No libraries! 😲 // Copyright © Victor Westerlund - No libraries! 😲
import { default as Preload } from "./modules/Preload.mjs"; import { default as Preload } from "./modules/Preload.mjs";
import { default as Interaction } from "./modules/UI.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) // Load these assets when the DOM is ready (not needed right away)
const preload = new Preload([ new Preload([
"modules/Modals.mjs", "modules/Modals.mjs",
"modules/Components.mjs", "modules/Components.mjs",
"modal.css" "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 // All default interactions
const interactions = { const interactions = {
toggleMenu: () => { toggleMenu: () => {
const speed = 200; const transition = 200;
const menu = document.getElementsByTagName("main")[0]; 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"); 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: () => { openContactCard: () => {
const module = import("./modules/Modals.mjs"); const module = import("./modules/Modals.mjs");
@ -34,10 +47,10 @@ const interactions = {
copyText: (event) => { copyText: (event) => {
const memory = event.target.innerText; const memory = event.target.innerText;
event.target.classList.add("bounce"); event.target.classList.add("bounce");
event.target.innerText = "Copied!"; event.target.innerText = "copied!";
setTimeout(() => { setTimeout(() => {
event.target.innerText = memory; event.target.innerText = memory;
},this.transition); },1000);
} }
}; };
@ -45,23 +58,16 @@ const interactions = {
const card = new modals.Card(interactions); const card = new modals.Card(interactions);
card.openPage("contact"); card.openPage("contact");
}); });
} },
} openSearch: () => {
const module = import("./modules/Search.mjs");
const theme = window.matchMedia("(prefers-color-scheme: dark)"); document.body.classList.add("searchActive");
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;
} }
} }
// Set the current page theme, and listen for changes // Set the current page theme, and listen for changes
const theme = window.matchMedia("(prefers-color-scheme: dark)");
theme.addEventListener("change",updateTheme); theme.addEventListener("change",updateTheme);
new Interaction(interactions,document.body);
updateTheme(); updateTheme();

View file

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

View file

@ -1,21 +1,21 @@
<style> <style>
body:not(.dark) .modal[data-page="contact_signal"] .inner { body:not(.dark) .modal[data-page="contact_signal"] .inner {
--comp-inverted: 255,255,255; --palette-inverted: 255,255,255;
--comp-background: 58,118,240; --palette-background: 58,118,240;
--color-background: rgb(var(--comp-background)); --swatch-background: rgb(var(--palette-background));
--color-inverted: rgb(var(--comp-inverted)); --swatch-inverted: rgb(var(--palette-inverted));
} }
body:not(.dark) .modal[data-page="contact_signal"] .button.solid { body:not(.dark) .modal[data-page="contact_signal"] .button.solid {
background-color: var(--color-inverted); background-color: var(--swatch-inverted);
color: var(--color-background); color: var(--swatch-background);
} }
.modal .inner > h1, .modal .inner > h1,
.modal .inner > p, .modal .inner > p,
.modal .button.phantom { .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="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Full-stack web developer from Stockholm, Sweden."> <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 rel="icon" href="assets/img/favicon.png">
<link href="assets/css/style.css" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css">
</head> </head>
<body> <body>
<main> <main>
@ -46,19 +44,17 @@
<div class="logo"></div> <div class="logo"></div>
<p>victor westerlund</p> <p>victor westerlund</p>
</header> </header>
<div class="wide">
<h1>victor westerlund</h1>
</div>
<div class="content"> <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"> <div class="button phantom" data-action="openContactCard">
<p>contact me</p> <p>contact me</p>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
<script src="assets/js/script.js" type="module"></script> <script type="module" src="assets/js/script.js"></script>
<script src="assets/js/nomodule.js" nomodule></script> <script nomodule src="assets/js/nomodule.js"></script>
</body> </body>
</html> </html>