wip(22w6a): add glitch bg

This commit is contained in:
Victor Westerlund 2022-02-12 02:28:58 +01:00
parent 64db7544b7
commit 405fbe0f28
33 changed files with 112 additions and 416 deletions

0
.github/ISSUE_TEMPLATE/lighthouse.md vendored Normal file → Executable file
View file

0
.gitignore vendored Normal file → Executable file
View file

0
LICENSE Normal file → Executable file
View file

0
README.md Normal file → Executable file
View file

View file

@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Victor Westerlund - About</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Full-stack web developer from Stockholm, Sweden.">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
<link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<header>
<p><a href="/">victor westerlund</a></p>
</header>
<main>
<p>...</p>
</main>
<footer>
<p><a href="about">about</a></p>
<p><a href="search">search</a></p>
<p><a class="arrow" href="more">more</a></p>
</footer>
</body>
</html>

View file

@ -1,20 +0,0 @@
.button {
background-color: rgb(var(--color-contrast));
color: rgb(var(--color-background));
padding: var(--padding) calc(var(--padding) * 2);
}
/* -- Media Queries -- */
@media (pointer: fine) {
.button {
cursor: pointer;
}
}
@media (hover: hover) {
.button:hover {
background-color: rgba(var(--color-contrast),.11);
color: rgb(var(--color-contrast));
}
}

View file

@ -1,59 +0,0 @@
main {
align-self: start;
width: 100%;
max-width: 900px;
}
#search {
width: 100%;
height: 80px;
color: rgb(var(--color-background));
background-color: rgb(var(--color-contrast));
}
input[type="search"] {
width: 100%;
height: 100%;
font-size: 18px;
color: inherit;
padding: 0 calc(var(--padding) * 1.5);
background-color: transparent;
border: none;
outline: none;
}
input[type="search"]::selection {
color: rgb(var(--color-contrast));
background-color: rgb(var(--color-background));
}
input[type="search"]::placeholder {
color: rgba(var(--color-background),.4);
}
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
height: 32px;
width: 32px;
background: center no-repeat rgba(var(--color-background),.1) url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAAAXNSR0IArs4c6QAAAFRJREFUeNrlkrkNADEIBK8JunD/GVW4oLnMAViagNBkLDsS3/d4sEiiqUGy7kACmyj2DeQRavEgTRGkZ4oUuyPF7ojYBRi35ENP1+qHG7+GP9/b8QPsDLZNvX0megAAAABJRU5ErkJggg==');
cursor: pointer;
}
#results {
text-align: center;
font-size: 18px;
padding: 0 var(--padding);
}
/* -- Media Queries -- */
@media (prefers-color-scheme: dark) {
#search {
color: rgb(var(--color-contrast));
background-color: rgba(var(--color-contrast),.15);
}
input[type="search"]::placeholder {
color: rgba(var(--color-contrast),.4);
}
}

134
public/assets/css/style.css Normal file → Executable file
View file

@ -1,17 +1,16 @@
:root { :root {
--color-background: 255,255,255; --color-base: 0, 0, 0;
--color-contrast: 33,33,33; --color-: 33, 33, 33;
--color-contrast: 255, 255, 225;
--padding: 20px; --padding: 30px;
--running-height: 100px;
--footer-denom: 1;
} }
/* -- Cornerstones -- */ /* -- Cornerstones -- */
* { * {
margin: 0; margin: 0;
font-family: "Monaco","Consolas",monospace,sans-serif; font-family: "Monaco", "Consolas", monospace, sans-serif;
color: rgb(var(--color-contrast)); color: rgb(var(--color-contrast));
} }
@ -20,123 +19,74 @@
color: rgb(var(--color-background)); color: rgb(var(--color-background));
} }
a {
display: inline-block;
padding: 15px 30px;
border-radius: 100px;
border: solid 4px rgba(var(--color-contrast), .3);
text-decoration: none;
margin: var(--padding) 0;
}
html, html,
body { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow-x: hidden; overflow-x: hidden;
} background-color: rgba(var(--color-base), .8);
background-size: cover;
body { background-blend-mode: overlay;
display: grid; background-position: fixed;
grid-template-rows: var(--running-height) 1fr calc(var(--running-height) / var(--footer-denom));
background-color: rgb(var(--color-background));
place-items: center;
justify-items: center;
font-size: 21px;
}
body > * {
box-sizing: border-box;
}
p,
a {
color: inherit;
text-decoration: none;
}
a {
display: contents;
} }
/* -- Components -- */ /* -- Components -- */
main { body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--padding,30px); gap: var(--padding, 30px);
} }
.arrow { body > div {
display: inline; padding: var(--padding);
font-weight: bold; justify-items: center;
} }
.arrow::after { body > div:first-child {
content: " →"; --font-min: 20px;
--font-tar: 13vw;
--font-max: 6vh;
} }
footer { body > div:first-child :is(a, p, h1) {
justify-self: end; font-size: var(--font-min);
padding: 0 calc(var(--running-height) / (var(--footer-denom) * 2)); user-select: none;
} }
footer p:not(:last-child) { body > div:first-child p {
display: none; font-size: clamp(calc(var(--font-min) / 2), calc(var(--font-tar) / 2), calc(var(--font-max) / 2));
}
body > div:first-child h1 {
font-size: clamp(var(--font-min), var(--font-tar), var(--font-max));
} }
/* -- Media Queries -- */ /* -- Media Queries -- */
@media (prefers-color-scheme: dark) {
:root {
--color-background: 0,0,0;
--color-contrast: 255,255,255;
}
}
@media (pointer: fine) { @media (pointer: fine) {
a:hover { a:hover {
background: rgba(var(--color-contrast),.1); background: rgba(var(--color-contrast), .1);
}
}
@media print {
.arrow::after {
content: ": " attr(href);
}
}
@media (max-width: 300px) {
body > * {
justify-self: center;
text-align: center;
} }
} }
@media (min-aspect-ratio: 14/9) and (min-height: 500px) { @media (min-aspect-ratio: 14/9) and (min-height: 500px) {
:root { body {
--footer-denom: 2; display: grid;
grid-template-columns: repeat(2, 1fr);
} }
footer { body > div {
width: 100%; display: grid;
height: 100%;
gap: calc(var(--padding) * 1.5);
font-size: 19px;
color: rgb(var(--color-background));
background-color: rgb(var(--color-contrast));
display: flex;
align-items: center; align-items: center;
} }
footer p:not(:last-child) {
display: initial;
}
footer p:last-child {
margin-left: auto;
}
footer p:first-child:last-child {
margin-left: auto;
margin-right: auto;
}
}
@media (min-aspect-ratio: 14/9) and (min-height: 500px) and (prefers-color-scheme: dark) {
footer {
color: rgb(var(--color-contrast));
background-color: rgba(var(--color-contrast),.15);
}
} }

View file

@ -0,0 +1,47 @@
export default class Glitch {
constructor(image, target) {
this.image = image;
this.target = target ? target : document.body;
this.interval = {
_this: this,
_interval: null,
// Queue the next glitch
set next (timeout) {
clearTimeout(this._interval);
this._interval = setTimeout(() => this._this.glitch(), timeout);
}
}
this.interval.next = 2000;
this.setBackground();
}
// Update the target CSS background
setBackground(image = this.image) {
this.target.style.setProperty("background-image", `url(${image})`);
}
// Generate random string of length from charset
randomString(length = 2) {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let output = "";
for(let i = 0; i < length; i++) {
output += charset.charAt(Math.floor(Math.random() * charset.length));
}
return output;
}
// Genrate random int in range
randomInt(min, max) {
return Math.random() * (max - min) + min;
}
// Create a glitchy image
glitch() {
const glitched = this.image.replaceAll(this.randomString(), this.randomString());
this.setBackground(glitched);
this.interval.next = this.randomInt(100, 1500);
}
}

View file

@ -1,96 +0,0 @@
export default class Search {
constructor(input,results) {
const self = this;
this.endpoint = new URL("api/search",window.location.href);
this.lastQuery = "";
this.throttle = null;
this.controller = null; // AbortController will be assigned here
this.results = results;
this.input = input;
this.input?.addEventListener("keyup",event => this.keyEvent(event)) ?? false;
}
// Destroy the result DOM tree
clearResults() {
while(this.results.firstChild) {
this.results.removeChild(this.results.lastChild);
}
}
// Display output as HTML
output(html) {
this.clearResults();
if(typeof html === "string") {
this.results.insertAdjacentHTML("beforeEnd",html);
return;
}
this.results.appendChild(html);
}
// Display a status message in a paragraph
status(text,classList = false) {
const element = document.createElement("p");
if(classList !== false) {
element.classList = classList;
}
element.innerText = text;
this.output(element);
}
// Fetch search results from endpoint
async search(query) {
const url = new URL(this.endpoint);
url.searchParams.set("q",query);
const timeout = new Promise(reject => setTimeout(() => reject("Request timed out"),3000));
// Fetch response from server
const api = fetch(url,{
signal: this.controller.signal,
headers: {
"Content-Type": "text/html"
}
});
const result = Promise.race([api,timeout]);
result.then(response => {
if(!response.ok) {
this.status("oh no, something went wrong","error");
throw new Error("Invalid response from server");
}
return response.text();
})
.then(html => this.output(html))
.catch(error => {});
}
// Wait until the user stops typing for a few miliseconds
queue(query) {
clearTimeout(this.throttle);
this.controller = new AbortController(); // Spawn a new AbortController for each fetch
this.throttle = setTimeout(() => this.search(query),500);
}
keyEvent(event) {
const query = event.target.value;
// Don't do the search thing if query is too weak
if(query.length < 1) {
this.controller.abort(); // Abort queued search
this.lastQuery = "";
this.status("search results will appear here as you type");
return;
}
// Pressing a modifier key (Ctrl, Shift etc.) doesn't change the query
if(query === this.lastQuery) {
return false;
}
this.lastQuery = query;
this.status("searching..");
this.queue(query);
}
}

0
public/assets/js/noscript.js Normal file → Executable file
View file

11
public/assets/js/search.mjs Normal file → Executable file
View file

@ -1,9 +1,4 @@
import { default as Search } from "./modules/Search.mjs"; import { default as Glitch } from "./modules/Glitch.mjs";
const searchBox = document.getElementById("search")?.getElementsByTagName("input")[0] ?? false; const image = "";
const resultsContainer = document.getElementById("results"); const glitch = new Glitch()
new Search(searchBox,resultsContainer);
// Set focus on searchbox when typing from anywhere
window.addEventListener("keydown",() => searchBox.focus());

1
public/assets/media/bg64.txt Executable file

File diff suppressed because one or more lines are too long

0
public/assets/media/favicon-dark.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 628 B

0
public/assets/media/favicon-light.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 638 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="81.968" height="45.389"><path d="M1.172 9.641c5.062.216 7.335 9.392 8.326 13.13 1.116 4.363 1.748 8.825 2.814 13.2.833 3.43 2.456 12.139 7.651 8.584 6-4.1 8.326-13.779 10.182-20.265a119.035 119.035 0 0 0 3.014-13.471c.425-2.573 1.815-6.794.466-9.158-2.614-4.646-6.86 1.665-7.285 4.438-1.232 8.218 2.1 18.317 5.22 25.727.733 1.74 1.773 5.828 4.1 6.369s3.9-2.173 4.712-3.822a29.121 29.121 0 0 0 1.782-5.3c.325-1.174.741-5 1.865-5.6 2.623-1.349 3.115 6.469 3.264 7.443.275 1.807.491 3.971 1.6 5.5 4.687 6.494 10.108-8.717 11.306-11.331C64.5 15.661 71.425 8.343 81.134 4.438c1.474-.591.833-3.014-.667-2.406-11.606 4.679-18.575 13.229-23.595 24.394a56.539 56.539 0 0 1-2.5 5.1 6.551 6.551 0 0 1-1.1 1.8 2.66 2.66 0 0 1-3.081-.241c-.916-1.041-.691-4.279-.916-5.712a16.236 16.236 0 0 0-1.141-4.488c-1.54-3.2-4.754-3.4-6.511-.266-1.315 2.34-1.665 5.2-2.431 7.718-.375 1.191-1.4 5.362-3.455 4.654-1.207-.416-2.539-5.67-2.9-6.661a69.05 69.05 0 0 1-2.914-10.182c-.7-3.38-2.09-8.409-1.066-11.881.316-1.082 1.99-4.163 2.681-2.29a5.7 5.7 0 0 1-.2 1.973c-.25 2.173-.608 4.338-1.007 6.494Q29.3 18.1 27.723 23.646a95.743 95.743 0 0 1-3.28 9.791c-.949 2.331-6.128 12.822-8.25 7.044-2.5-6.752-2.906-14.062-5-20.914-1.482-4.812-4.08-12.147-9.991-12.4C-.4 7.1-.4 9.6 1.206 9.666Z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Victor Westerlund - Contact</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Full-stack web developer from Stockholm, Sweden.">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
<link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<header>
<p><a href="/">victor westerlund</a></p>
</header>
<main>
<p>hello@&ZeroWidthSpace;victorwesterlund.com</p>
</main>
<footer>
<p><a href="about">about</a></p>
<p><a href="search">search</a></p>
<p><a class="arrow" href="more">more</a></p>
</footer>
</body>
</html>

0
public/error.html Normal file → Executable file
View file

29
public/index.html Normal file → Executable file
View file

@ -9,18 +9,25 @@
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)"> <link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
<link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)"> <link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
<link rel="stylesheet" href="assets/css/style.css"> <link rel="stylesheet" href="assets/css/style.css">
<style>body { grid-template-rows: 1fr calc(var(--running-height) / var(--footer-denom)); }</style>
</head> </head>
<body> <body>
<main> <div>
<p>victor westerlund</p> <div>
<p><a class="arrow" href="https://github.com/VictorWesterlund">github</a></p> <p>hello, my name is</p>
<p><a class="arrow" href="contact">contact</a></p> <h1>victor</h1>
</main> <p>I'm a</p>
<footer> <h1>full-stack</h1>
<p><a href="about">about</a></p> <h1>developer</h1>
<p><a href="search">search</a></p> <p>from Sweden</p>
<p><a class="arrow" href="more">more</a></p> <a href="#">contact me</a>
</footer> </div>
</div>
<div>
</div>
<script type="module">
import { default as Glitch } from "./assets/js/modules/Glitch.mjs";
fetch("assets/media/bg64.txt").then((resp) => resp.text().then(bg64 => new Glitch(bg64, document.body)));
</script>
</body> </body>
</html> </html>

View file

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Victor Westerlund</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Full-stack web developer from Stockholm, Sweden.">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
<link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
<link rel="stylesheet" href="assets/css/style.css">
<style>
.arrow[href="/"]::after { content: ""; }
.arrow[href="/"]::before { content: "← "; }
</style>
</head>
<body>
<header>
<p><a href="/">victor westerlund</a></p>
</header>
<main>
<p><a class="arrow" href="https://github.com/VictorWesterlund">github</a></p>
<p><a class="arrow" href="contact">contact</a></p>
<p><a class="arrow" href="about">about</a></p>
<p></p>
<p>random stuff <span style="white-space:nowrap;">--</span></p>
<p><a class="arrow" href="search">search</a></p>
<p><a class="arrow" rel="noopener" target="_blank" href="https://open.spotify.com/playlist/1NiR19Fg3AHg0XlqJhEKTF?si=c53d53f4c11f4971">megalodon</a></p>
</main>
<footer>
<p><a href="about">about</a></p>
<p><a href="search">search</a></p>
<p><a class="arrow" href="/">less</a></p>
</footer>
</body>
</html>

0
public/robots.txt Normal file → Executable file
View file

View file

@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Victor Westerlund - Search</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Full-stack web developer from Stockholm, Sweden.">
<meta name="google" content="nositelinkssearchbox">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
<link rel="icon" href="assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
<link rel="icon" href="assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/search.css">
</head>
<body>
<header>
<p><a href="/">victor westerlund</a></p>
</header>
<main>
<div id="search">
<input type="search" spellcheck="false" autocomplete="false" placeholder="start typing to search..">
</div>
<div id="results">
<p>search results will appear here as you type</p>
</div>
</main>
<footer>
<p><a href="about">about</a></p>
<p><a href="search">search</a></p>
<p><a class="arrow" href="more">more</a></p>
</footer>
<script type="module" src="assets/js/search.mjs"></script>
<script nomodule defer src="assets/js/noscript.js"></script>
</body>
</html>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://victorwesterlund.com/</loc>
<lastmod>2021-02-09T06:54:02+00:00</lastmod>
</url>
</urlset>

0
src/api.php Normal file → Executable file
View file

0
src/core/Import.php Normal file → Executable file
View file

0
src/database/Database.php Normal file → Executable file
View file

0
src/database/config.json Normal file → Executable file
View file

0
src/search/Search.php Normal file → Executable file
View file

0
src/search/templates/card_default.html Normal file → Executable file
View file

0
src/search/templates/card_error_display.html Normal file → Executable file
View file

0
src/search/templates/default.html Normal file → Executable file
View file

0
src/search/templates/message.html Normal file → Executable file
View file

0
src/search/templates/result_about.html Normal file → Executable file
View file