Compare commits

..

12 Commits

Author SHA1 Message Date
63d769ca13 small changes 2024-09-27 18:58:16 +02:00
ff33edc7cf made footer links customizable 2024-09-05 14:02:50 +02:00
301a0e8fdf autofocus search 2024-08-29 19:28:06 +02:00
5dbd5fbcdf changed and implemented a lot 2024-08-29 19:12:40 +02:00
4893ac5a2f changes 2024-08-27 21:50:30 +02:00
c131d89a45 more design changes 2024-08-25 20:46:40 +02:00
7d0abea1dd round buttons; bigger icons 2024-08-25 19:53:45 +02:00
a313368352 changed title 2024-08-25 19:42:46 +02:00
54b10e19a0 changed link look 2024-08-25 19:42:04 +02:00
c4d831fa68 default links css 2024-08-24 23:21:20 +02:00
b0355500c1 changed border radius for buttons 2024-08-24 22:56:39 +02:00
38402498f2 changed default to non rainbow 2024-08-24 22:45:28 +02:00
10 changed files with 584 additions and 230 deletions

View File

@ -56,7 +56,7 @@
}, },
{ {
"name": "Matrix", "name": "Matrix",
"href": "https://brulijam.com/mtrx/#/@brulijam:brulijam.com?web-instance[element.io]=app.element.io&client=element.io", "href": "https://brulijam.com/mtrx/#/@brulijam:brulijam.com?web-instance[element.io]=app.element.io",
"icon": "https://simpleicons.org/icons/matrix.svg", "icon": "https://simpleicons.org/icons/matrix.svg",
"group": 1 "group": 1
}, },
@ -116,7 +116,7 @@
}, },
{ {
"name": "Telegram", "name": "Telegram",
"href": "https://t.me/julian_brammer", "href": "https://t.me/brulijam",
"icon": "https://simpleicons.org/icons/telegram.svg", "icon": "https://simpleicons.org/icons/telegram.svg",
"group": 1 "group": 1
}, },
@ -125,12 +125,37 @@
"href": "https://youtube.com/@brulijam", "href": "https://youtube.com/@brulijam",
"icon": "https://simpleicons.org/icons/youtube.svg", "icon": "https://simpleicons.org/icons/youtube.svg",
"group": 2 "group": 2
},
{
"name": "source code",
"href": "https://git.brulijam.com/brulijam/introduction-website",
"group": "footer"
},
{
"name": "links json",
"href": "content/links.json",
"group": "footer"
},
{
"name": "status",
"href": "https://status.brulijam.com/status/brulijam",
"group": "footer"
},
{
"name": "files",
"href": "https://brulijam.com/files",
"group": "footer"
},
{
"name": "music",
"href": "https://brulijam.com/music",
"group": "footer"
} }
], ],
"groupNames": { "groupNames": {
"1": "Social", "1": "social",
"2": "Content", "2": "stuff",
"3": "Games", "3": "games",
"4": "Other" "4": "other"
} }
} }

View File

@ -1,183 +1,260 @@
/* Root Variables */
:root { :root {
--bg-color: rgb(16, 16, 16); --bg-color: rgb(15, 15, 15);
--primary: rgb(240, 240, 240); --primary: rgb(240, 240, 240);
--secondary-color: hsl(210, 80%, 80%);
--secondary-color: hsl(200, 60%, 60%); --secondary-color2: hsl(210, 60%, 40%);
/*--secondary-color: rgb(0, 138, 216);*/ --secondary-color-bg: hsl(210, 40%, 5%);
--hue-rotation: 0; --font-weight: 350;
--font-weight: 400;
--font-family: "Lucida Console"; --font-family: "Lucida Console";
--bigger-font-weight: 700;
--link-font-weight: 1000; --link-border-radius: 1000px;
--link-border-radius: 10px; --page-max-width: 700px;
--page-max-width: 800px;
} }
/* General */ /* General Styles */
body { body {
background-color: var(--bg-color); background-color: var(--secondary-color-bg);
color: var(--primary); color: var(--primary);
/*color: var(--primary);*/
font-family: var(--font-family), monospace; font-family: var(--font-family), monospace;
font-weight: var(--font-weight); font-weight: var(--font-weight);
overflow-x: hidden; overflow-x: hidden;
margin: 20px;
& a {
color: var(--secondary-color);
}
& a:hover {
text-decoration: none;
}
& h1, p {
margin: 0; margin: 0;
position: relative;
height: 100%;
} }
h1, p {
margin: 0;
} }
main { main {
position: relative;
z-index: 1;
max-width: var(--page-max-width); max-width: var(--page-max-width);
margin: 0 auto; margin: 0 auto;
padding: 20px;
filter: drop-shadow(0 0 2px var(--secondary-color)) brightness(1);
} }
/* Header*/ ::selection {
color: var(--bg-color);
background: var(--secondary-color);
}
/* Header Styles */
header { header {
text-align: center; text-align: center;
width: max-content; width: max-content;
margin: 0 auto; margin: 0 auto;
}
& .names { header .names {
/*margin: 0 auto;*/
width: min-content; width: min-content;
white-space: nowrap; white-space: nowrap;
}
& h1, p { header h1, header p {
text-align: left; text-align: left;
color: var(--secondary-color); color: var(--secondary-color);
} }
}
& img { header img {
border-radius: 50%; border-radius: 50%;
max-width: 300px; max-width: 300px;
padding: 0; padding: 0;
} }
}
.links {
/* if wide */
/*@media only screen and (min-width: 480px) {*/
display: flex;
flex-wrap: wrap;
/*}*/
}
.linkGroup {
min-width: min-content;
margin: 20px auto;
}
.link {
font-size: large;
margin: 10px 20px;
}
/* Links Styles */
h2 { h2 {
margin: 10px 20px; width: 100%;
font-size: larger; margin: 0;
@media only screen and (max-width: 480px) {
text-align: center; /* slim */
margin: 10px auto;
} }
/*!* Links *!*/ @media only screen and (min-width: 480px) {
/*.linkGroup {*/ text-align: left; /* wide */
/* margin: auto;*/ margin: 0;
/* box-sizing: border-box;*/ }
}
/* !* if wide *!*/ .text-link::before {
/* @media only screen and (min-width: 480px) {*/ content: "[";
/* display: flex;*/ }
/* flex-wrap: wrap;*/
/* }*/
/* & .link {*/ .text-link::after {
/* height: fit-content;*/ content: "]";
/* position: relative;*/ }
/* top: 0;*/
/* transition: top ease 100ms;*/
/* !* if slim *!*/ .text-link {
/* @media only screen and (max-width: 480px) {*/ color: var(--secondary-color);
/* margin-bottom: 10px;*/ text-decoration: none;
/* margin-left: 10%;*/ position: relative;
/* margin-right: 10%;*/ padding: 5px;
/* }*/ white-space: nowrap;
display: inline-block;
}
/* !* if wide *!*/ .text-link:hover {
/* @media only screen and (min-width: 480px) {*/ filter: drop-shadow(0 0 5px var(--secondary-color2)) brightness(1.02);
/* padding: 5px;*/ top: -2px;
/* }*/ }
/* }*/
/*}*/
/* Links Container */
.links {
padding: 0 10px;
}
/*.linkButton {*/ /* Link Group */
/* font-weight: var(--link-font-weight);*/ .linkGroup {
/* font-size: 25px;*/ margin: auto;
/* line-height: 30px;*/
/* text-align: center;*/
/* text-decoration: none;*/
/* color: rgb(0, 0, 0);*/ @media only screen and (min-width: 480px) {
/* background-color: var(--secondary-color);*/ display: flex;
flex-wrap: wrap; /* wide */
}
}
/* display: block;*/ /* Link Styles */
/* box-sizing: border-box;*/ .link {
/* padding: 10px 20px;*/ height: fit-content;
/* border-radius: var(--link-border-radius);*/ position: relative;
transition: top 100ms ease, filter 100ms ease; /* Added filter transition */
/* !* if slim *!*/ @media only screen and (max-width: 480px) {
/* @media only screen and (max-width: 480px) {*/ margin: 10px 5%; /* slim */
/* width: 100%;*/ }
/* }*/
/* & .icon {*/ @media only screen and (min-width: 480px) {
/* width: 20px;*/ padding: 5px; /* wide */
/* height: 20px;*/ }
/* padding-right: 10px;*/ }
/* padding-bottom: 4px;*/
/* vertical-align: middle;*/
/* }*/
/*}*/
/*.link:hover {*/ /* Button Styles */
/* filter: drop-shadow(0px 0px 5px var(--secondary-color)) brightness(1.05);*/ .linkButton {
/* top: -2px;*/ font-weight: var(--bigger-font-weight);
/*}*/ font-size: 25px;
line-height: 25px;
text-align: center;
text-decoration: none;
text-transform: lowercase;
color: var(--bg-color);
background-color: var(--secondary-color);
display: block;
box-sizing: border-box;
padding: 10px 20px;
border-radius: var(--link-border-radius);
width: 100%; /* slim */
/*.links:hover .link:not(:hover) a {*/ @media only screen and (min-width: 480px) {
/* filter: brightness(0.8);*/ width: auto; /* wide */
/*}*/ }
}
/*.linkButton:active {*/ .linkButton .icon {
/* transform: scale(0.95); top: +2px;*/ width: 25px;
/* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);*/ height: 25px;
/*}*/ padding-right: 10px;
padding-bottom: 2px;
vertical-align: middle;
}
/* Links minimal WIP */ /* Default Hover Effect */
.icon { .hoverHighlight:hover {
@media only screen and (min-width: 480px) {
filter: drop-shadow(0 0 8px var(--secondary-color)) brightness(1.1);
top: -2px;
}
}
.links:hover .hoverHighlight:not(:hover) {
@media only screen and (min-width: 480px) {
filter: brightness(0.8);
}
}
/* Search Highlighting */
.highlightSearch {
filter: drop-shadow(0 0 8px var(--secondary-color)) brightness(1.1);
z-index: 1;
@media only screen and (min-width: 480px) {
top: -2px;
}
}
.notHighlightSearch {
filter: brightness(0.5);
@media only screen and (max-width: 480px) {
display: none; display: none;
} }
}
.linkButton:active {
transform: scale(0.95);
top: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
/* Search Input Field Styles */
.fuzzysearch {
margin: 10px auto;
text-align: center;
max-width: var(--page-max-width);
}
#link-search {
background-color: var(--secondary-color2);
color: var(--secondary-color);
border: 2px solid var(--secondary-color2);
border-radius: 50px;
padding: 10px 15px;
font-size: 16px;
text-align: center;
font-weight: var(--bigger-font-weight);
width: 100%;
max-width: 400px; /* Adjust width as needed */
/*box-shadow: 0 0 5px var(--secondary-color2);*/
transition: background-color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
}
#link-search::placeholder {
color: var(--secondary-color);
opacity: 0.9; /* Placeholder text opacity */
}
#link-search:focus::placeholder {
color: var(--secondary-color);
opacity: 0.9; /* Placeholder text opacity */
}
#link-search:focus {
outline: none;
background-color: var(--secondary-color-bg);
box-shadow: 0 0 10px var(--secondary-color);
border-color: var(--secondary-color2);
color: var(--secondary-color);
}
/* Timers */
.timer p {
/* if slim */
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
margin-bottom: 20px; #link-search {
padding: 8px 12px;
max-width: 90%; /* Responsive width for small screens */
}
}
@media only screen and (min-width: 480px) {
#link-search {
padding: 10px 15px;
}
}
/* Timers Styles */
.timer p {
@media only screen and (max-width: 480px) {
margin-bottom: 20px; /* slim */
} }
} }
@ -186,11 +263,7 @@ h2 {
text-decoration: none; text-decoration: none;
} }
/* Footer */ /* Footer Styles */
footer { footer {
text-align: center; text-align: center;
& a {
padding: 0 2px;
}
} }

View File

@ -3,10 +3,12 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brulijam</title> <title>Julian Brammer</title>
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<link rel="me" href="https://social.brulijam.com/@brulijam"> <link rel="me" href="https://social.brulijam.com/@brulijam">
<script src="js/main.js"></script> <script src="js/main.js"></script>
<script src="js/fuzzysearch.js" type="module"></script>
<script src="js/links.js"></script>
<script src="js/timer.js"></script> <script src="js/timer.js"></script>
</head> </head>
<body> <body>
@ -20,34 +22,30 @@
</header> </header>
<br> <br>
<section class="description"> <section class="description">
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et <p>css is pain and I used way too much math to implement that fuzzy search.</p>
dolore magna aliquyam erat, sed diam <p>One day I will write something meaningful in this paragraph.</p>
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea </section>
takimata sanctus est Lorem ipsum dolor sit <br>
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut <section class="fuzzysearch">
labore et dolore magna aliquyam erat, sed <input type="text" id="link-search" placeholder="fuzzy search">
diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit
amet.</p>
</section> </section>
<br> <br>
<script src="js/links.js"></script>
<section class="links"> <section class="links">
<noscript> <noscript>
<p>javascript is not available. You can still see a list of my links <a href="content/links.json">here</a>.</p> <p>javascript is not available. You can still see a list of my links <a class="text-link" href="content/links.json">here</a>.</p>
</noscript> </noscript>
</section> </section>
<br> <br>
<section class="timer"> <section class="timer">
<p class="js-required">alive for <span id="timer-alive-since-s"></span><span id="timer-alive-since-ms"></span> seconds.</p> <p class="js-required">alive for <span id="timer-alive-since-s"></span><span id="timer-alive-since-ms"></span> seconds.</p>
<p class="js-required">next birthday in <span id="timer-until-birthday-s"></span><span id="timer-until-birthday-ms"></span> seconds.</p> <p class="js-required">next birthday in <span id="timer-until-birthday-s"></span><span id="timer-until-birthday-ms"></span> seconds.</p>
<p class="js-required">employed at <a href="https://subshell.com/">subshell</a> for <span id="timer-employed-since-s"></span><span <p class="js-required">employed at <a class="text-link" href="https://subshell.com/">subshell</a> for <span id="timer-employed-since-s"></span><span
id="timer-employed-since-ms"></span> id="timer-employed-since-ms"></span>
seconds. seconds.
</p> </p>
<noscript> <noscript>
<p>alive since <span>1999-07-20T00:00:00</span>.</p> <p>alive since <span>1999-07-20T00:00:00</span>.</p>
<p>working at <a href="https://subshell.com/">subshell</a> since <span>2024-05-02T09:00:00</span>.</p> <p>working at <a class="text-link" href="https://subshell.com/">subshell</a> since <span>2024-05-02T09:00:00</span>.</p>
<style> <style>
.js-required { .js-required {
display: none; display: none;
@ -56,13 +54,7 @@
</noscript> </noscript>
</section> </section>
<br> <br>
<footer> <footer></footer>
<a href="https://git.brulijam.com/brulijam/introduction-website" target="_blank">source code</a>
<a href="content/links.json" target="_blank">links.json</a>
<a href="https://status.brulijam.com/status/brulijam">status</a>
<a href="https://brulijam.com/files" target="_blank">files</a>
<a href="https://brulijam.com/music" target="_blank">music</a>
</footer>
</main> </main>
</body> </body>
</html> </html>

70
src/js/distance.js Normal file
View File

@ -0,0 +1,70 @@
function levenshtein(a, b) {
const m = a.length;
const n = b.length;
const d = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
for (let i = 0; i <= m; i++) d[i][0] = i;
for (let j = 0; j <= n; j++) d[0][j] = j;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
d[i][j] = Math.min(
d[i - 1][j] + 1,
d[i][j - 1] + 1,
d[i - 1][j - 1] + cost
);
}
}
return d[m][n];
}
function jaroWinkler(s1, s2) {
if (s1 === s2) return 1;
const len1 = s1.length;
const len2 = s2.length;
const maxDist = Math.floor(Math.max(len1, len2) / 2) - 1;
const s1Matches = Array(len1).fill(false);
const s2Matches = Array(len2).fill(false);
let matches = 0;
let transpositions = 0;
for (let i = 0; i < len1; i++) {
const start = Math.max(0, i - maxDist);
const end = Math.min(len2, i + maxDist + 1);
for (let j = start; j < end; j++) {
if (s2Matches[j]) continue;
if (s1[i] !== s2[j]) continue;
s1Matches[i] = true;
s2Matches[j] = true;
matches++;
break;
}
}
if (matches === 0) return 0;
let k = 0;
for (let i = 0; i < len1; i++) {
if (!s1Matches[i]) continue;
while (!s2Matches[k]) k++;
if (s1[i] !== s2[k]) transpositions++;
k++;
}
transpositions /= 2;
return (matches / len1 + matches / len2 + (matches - transpositions) / matches) / 3;
}
export function calculateSimilarityScore(query, linkName) {
const levenshteinDistance = levenshtein(query.toLowerCase(), linkName.toLowerCase());
const jaroWinklerScore = jaroWinkler(query.toLowerCase(), linkName.toLowerCase());
return jaroWinklerScore - levenshteinDistance / Math.max(query.length, linkName.length);
}

128
src/js/fuzzysearch.js Normal file
View File

@ -0,0 +1,128 @@
import { calculateSimilarityScore } from './distance.js';
function applyFuzzySearch(linksData) {
const searchInput = document.getElementById("link-search");
searchInput.addEventListener("input", function () {
const query = searchInput.value.toLowerCase().trim();
if (query === "") {
clearHighlights();
return;
}
searchInput.scrollIntoView({ behavior: 'auto', block: 'start' });
const allLinks = linksData.links;
const scores = allLinks.map(link => ({
link: link,
score: calculateSimilarityScore(query, link.name)
}));
// Sort scores in descending order
scores.sort((a, b) => b.score - a.score);
const highestScore = scores[0].score;
const threshold = Math.max(0.01, highestScore * 0.5) - 0.1; // Adjust as needed
const matchingLinks = scores
.filter(entry => entry.score >= threshold)
.map(entry => entry.link);
highlightLinks(matchingLinks);
});
searchInput.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
const matchingLinksCount = document.querySelectorAll(".links .link.highlightSearch").length;
if (matchingLinksCount === 1) {
const bestMatch = document.querySelector(".links .link.highlightSearch .linkButton");
if (bestMatch) {
bestMatch.click();
}
}
} else if (event.key === "Escape") {
searchInput.value = '';
clearHighlights();
}
});
}
function highlightLinks(matchingLinks) {
clearHighlights();
const allLinks = document.querySelectorAll(".links .link");
allLinks.forEach(linkDiv => {
const link = linkDiv.querySelector('a');
const linkHref = link.getAttribute('href');
const isMatching = matchingLinks.some(matchingLink => matchingLink.href === linkHref);
if (isMatching) {
linkDiv.classList.add('highlightSearch');
linkDiv.classList.remove('notHighlightSearch');
linkDiv.classList.remove('hoverHighlight');
} else {
linkDiv.classList.add('notHighlightSearch');
linkDiv.classList.remove('highlightSearch');
linkDiv.classList.remove('hoverHighlight');
}
});
// Add or remove notHighlightSearch
const groupContainers = document.querySelectorAll('.linkGroup');
groupContainers.forEach(groupContainer => {
const hasHighlightedLink = groupContainer.querySelector('.link.highlightSearch');
const groupHeader = groupContainer.querySelector('h2');
if (hasHighlightedLink) {
groupHeader.classList.remove('notHighlightSearch');
} else {
groupHeader.classList.add('notHighlightSearch');
}
});
document.querySelector('.links').classList.remove('hoverHighlight');
}
function clearHighlights() {
const linkDivs = document.querySelectorAll(".links .link");
linkDivs.forEach(linkDiv => {
linkDiv.classList.remove('highlightSearch');
linkDiv.classList.remove('notHighlightSearch');
linkDiv.classList.add('hoverHighlight');
});
const groupHeaders = document.querySelectorAll('.linkGroup h2');
groupHeaders.forEach(header => {
header.classList.remove('notHighlightSearch');
});
}
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('link-search');
if (searchInput) {
searchInput.value = '';
}
});
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById("link-search");
if (searchInput) {
searchInput.value = '';
document.addEventListener('keydown', function (event) {
const key = event.key;
if (key.length === 1) {
searchInput.focus();
}
});
}
});
fetch('content/links.json')
.then(response => response.json())
.then(data => {
applyFuzzySearch(data);
})
.catch(error => console.error('Error fetching links:', error));

View File

@ -1,6 +1,7 @@
function createLinkDiv(link) { function createLinkDiv(link) {
const linkDiv = document.createElement('div'); const linkDiv = document.createElement('div');
linkDiv.className = 'link'; linkDiv.className = 'link';
linkDiv.classList.add('hoverHighlight');
const anchor = document.createElement('a'); const anchor = document.createElement('a');
anchor.className = 'linkButton'; anchor.className = 'linkButton';
@ -12,23 +13,38 @@ function createLinkDiv(link) {
return linkDiv; return linkDiv;
} }
function createFooterLink(link) {
const footerLink = document.createElement('a');
footerLink.className = 'text-link';
footerLink.href = link.href;
footerLink.target = '_blank';
footerLink.textContent = link.name;
return footerLink;
}
function createGroups(linksData, groupNames) { function createGroups(linksData, groupNames) {
const container = document.querySelector('.links'); const container = document.querySelector('.links');
const footer = document.querySelector('footer');
// Extract unique groups and sort them
const groups = [...new Set(linksData.map(link => link.group))].sort((a, b) => a - b); const groups = [...new Set(linksData.map(link => link.group))].sort((a, b) => a - b);
groups.forEach((group, index) => { groups.forEach((group, index) => {
// Create a container for the group if (group === "footer") {
linksData
.filter(link => link.group === "footer")
.forEach(link => {
const footerLink = createFooterLink(link);
footer.appendChild(footerLink);
});
} else {
// Handle regular links
const groupContainer = document.createElement('div'); const groupContainer = document.createElement('div');
groupContainer.className = 'linkGroup'; groupContainer.className = 'linkGroup';
// Create and append the group header
const groupHeader = document.createElement('h2'); const groupHeader = document.createElement('h2');
groupHeader.textContent = `${groupNames[group]}`; // Display numeric identifier and name groupHeader.textContent = `${groupNames[group]}`;
groupContainer.appendChild(groupHeader); groupContainer.appendChild(groupHeader);
// Filter links that belong to this group and create link elements
linksData linksData
.filter(link => link.group === group) .filter(link => link.group === group)
.forEach(link => { .forEach(link => {
@ -36,14 +52,13 @@ function createGroups(linksData, groupNames) {
groupContainer.appendChild(linkElement); groupContainer.appendChild(linkElement);
}); });
// Append the group container to the main container
container.appendChild(groupContainer); container.appendChild(groupContainer);
// Optionally add a line break between groups
if (index < groups.length - 1) { if (index < groups.length - 1) {
const br = document.createElement('br'); const br = document.createElement('br');
container.appendChild(br); container.appendChild(br);
} }
}
}); });
} }

View File

@ -1,34 +1,12 @@
// const secondaryColors = [ let hue = Math.floor(Math.random() * 360);
// // "rgb(240, 240, 240)",
// // "rgb(136, 139, 141)",
// "rgb(224, 231, 34)",
// "rgb(255, 173, 0)",
// "rgb(244,54,76)",
// // "rgb(219, 62, 177)",
// "rgb(250, 150, 250)",
// "rgb(250, 150, 150)",
// "rgb(242, 172, 185)",
// "rgb(0, 138, 216)",
// "rgb(0, 178, 169)",
// "rgb(88, 188, 64)",
// "rgb(173, 223, 179)"
// ];
//
// function setRandomSecondaryColor() {
// const randomColor = secondaryColors[Math.floor(Math.random() * secondaryColors.length)];
// document.documentElement.style.setProperty('--secondary-color', randomColor);
// }
//
// setRandomSecondaryColor();
let hue = 200;
const colorChangeInterval = 150; const colorChangeInterval = 150;
function setRainbowColor() { function setRainbowColor() {
const color = `hsl(${hue}, 60%, 60%)`; const color = `hsl(${hue}, 80%, 80%)`;
document.documentElement.style.setProperty('--secondary-color', color); document.documentElement.style.setProperty('--secondary-color', color);
document.documentElement.style.setProperty('--hue-rotation', `${hue}deg`); document.documentElement.style.setProperty('--secondary-color2', `hsl(${hue}, 40%, 40%)`);
document.documentElement.style.setProperty('--secondary-color-bg', `hsl(${hue}, 20%, 5%)`);
hue = (hue + 1) % 360; hue = (hue + 1) % 360;
} }

60
src/js/redirect.js Normal file
View File

@ -0,0 +1,60 @@
import {calculateSimilarityScore} from './distance.js';
document.addEventListener("DOMContentLoaded", function() {
handleRedirection();
});
function handleRedirection() {
let path = window.location.pathname.substring(1).toLowerCase();
if (path === "") {
window.location.href = "/";
return;
}
fetch('/content/links.json')
.then(response => response.json())
.then(data => {
const bestMatch = findBestMatch(path, data.links);
if (bestMatch) {
window.location.href = bestMatch.href;
} else {
displayNotFound();
}
})
.catch(error => {
console.error('Error fetching links.json:', error);
displayError();
});
}
function findBestMatch(path, links) {
let bestMatch = null;
let highestScore = -Infinity;
const threshold = 0.5;
for (let item of links) {
const itemName = item.name.toLowerCase();
const score = calculateSimilarityScore(path, itemName);
if (score > highestScore) {
highestScore = score;
bestMatch = item;
}
}
if (highestScore < threshold) {
window.location.href = "/";
return null;
}
return bestMatch;
}
function displayNotFound() {
document.body.innerHTML = '<h1>Not Found</h1><p>The requested page could not be found.</p>';
}
function displayError() {
document.body.innerHTML = '<h1>Error</h1><p>There was an error retrieving the redirection data.</p>';
}

View File

@ -34,7 +34,7 @@ function calculateTime() {
employedSinceTenthOfASecond = employedSinceTenthOfASecond.toString().padStart(2, "0"); employedSinceTenthOfASecond = employedSinceTenthOfASecond.toString().padStart(2, "0");
const employedSinceS = Math.floor(employedSinceMs / 1000); const employedSinceS = Math.floor(employedSinceMs / 1000);
// Update Document // update Document
updateDocument("timer-alive-since-s", `${formatNumber(aliveSinceS)}`) updateDocument("timer-alive-since-s", `${formatNumber(aliveSinceS)}`)
updateDocument("timer-alive-since-ms", `.${formatNumber(aliveSinceTenthOfASecond)}`) updateDocument("timer-alive-since-ms", `.${formatNumber(aliveSinceTenthOfASecond)}`)
updateDocument("timer-until-birthday-s", `${formatNumber(nextBirthdayS)}`) updateDocument("timer-until-birthday-s", `${formatNumber(nextBirthdayS)}`)

13
src/redirect.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Redirecting...</title>
<link rel="stylesheet" href="css/main.css">
<script src="js/redirect.js" type="module"></script>
</head>
<body>
<h1>Redirecting...</h1>
</body>
</html>