changed and implemented a lot
This commit is contained in:
parent
4893ac5a2f
commit
5dbd5fbcdf
222
src/css/main.css
222
src/css/main.css
@ -1,50 +1,41 @@
|
||||
/* Root Variables */
|
||||
:root {
|
||||
--bg-color: rgb(15, 15, 15);
|
||||
--primary: rgb(240, 240, 240);
|
||||
|
||||
--secondary-color: hsl(210, 80%, 60%);
|
||||
--secondary-color2: hsl(210, 20%, 20%);
|
||||
|
||||
--font-weight: 300;
|
||||
--secondary-color: hsl(210, 80%, 80%);
|
||||
--secondary-color2: hsl(210, 60%, 40%);
|
||||
--secondary-color-bg: hsl(210, 40%, 5%);
|
||||
--font-weight: 350;
|
||||
--font-family: "Lucida Console";
|
||||
|
||||
--link-font-weight: 700;
|
||||
--bigger-font-weight: 700;
|
||||
--link-border-radius: 1000px;
|
||||
|
||||
--page-max-width: 600px;
|
||||
--page-max-width: 700px;
|
||||
}
|
||||
|
||||
/* General */
|
||||
/* General Styles */
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
background-color: var(--secondary-color-bg);
|
||||
color: var(--primary);
|
||||
/*color: var(--primary);*/
|
||||
font-family: var(--font-family), monospace;
|
||||
font-weight: var(--font-weight);
|
||||
overflow-x: hidden;
|
||||
|
||||
|
||||
/* if slim */
|
||||
@media only screen and (max-width: 480px) {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
/* if wide */
|
||||
@media only screen and (min-width: 480px) {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
& h1, p {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
h1, p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: var(--page-max-width);
|
||||
margin: 0 auto;
|
||||
/*border: 1px solid var(--secondary-color);*/
|
||||
/*border-radius: 5px;*/
|
||||
padding: 20px;
|
||||
filter: drop-shadow(0px 0px 1px var(--secondary-color)) brightness(1);
|
||||
filter: drop-shadow(0 0 2px var(--secondary-color)) brightness(1);
|
||||
}
|
||||
|
||||
::selection {
|
||||
@ -52,148 +43,209 @@ main {
|
||||
background: var(--secondary-color);
|
||||
}
|
||||
|
||||
/* Header*/
|
||||
/* Header Styles */
|
||||
header {
|
||||
text-align: center;
|
||||
width: max-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
& .names {
|
||||
/*margin: 0 auto;*/
|
||||
header .names {
|
||||
width: min-content;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
& h1, p {
|
||||
|
||||
header h1, header p {
|
||||
text-align: left;
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& img {
|
||||
header img {
|
||||
border-radius: 50%;
|
||||
max-width: 300px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Links */
|
||||
/* Links Styles */
|
||||
h2 {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
/* if slim */
|
||||
@media only screen and (max-width: 480px) {
|
||||
text-align: center;
|
||||
text-align: center; /* slim */
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 480px) {
|
||||
text-align: left; /* wide */
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: var(--secondary-color);
|
||||
text-decoration: underline solid var(--secondary-color2) 1px;
|
||||
top: 0;
|
||||
position: relative;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.text-link:hover {
|
||||
text-decoration: underline solid var(--secondary-color) 1px;
|
||||
filter: drop-shadow(0px 0px 5px var(--secondary-color2)) brightness(1.02);
|
||||
filter: drop-shadow(0 0 5px var(--secondary-color2)) brightness(1.02);
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
/* Links Container */
|
||||
.links {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--secondary-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Link Group */
|
||||
.linkGroup {
|
||||
margin: auto;
|
||||
|
||||
/* if wide */
|
||||
@media only screen and (min-width: 480px) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
& .link {
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
top: 0;
|
||||
transition: top ease 100ms;
|
||||
|
||||
/* if slim */
|
||||
@media only screen and (max-width: 480px) {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
/* if wide */
|
||||
@media only screen and (min-width: 480px) {
|
||||
padding: 5px;
|
||||
}
|
||||
flex-wrap: wrap; /* wide */
|
||||
}
|
||||
}
|
||||
|
||||
/* Link Styles */
|
||||
.link {
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
transition: top 100ms ease, filter 100ms ease; /* Added filter transition */
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
margin: 10px 5%; /* slim */
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 480px) {
|
||||
padding: 5px; /* wide */
|
||||
}
|
||||
}
|
||||
|
||||
/* Button Styles */
|
||||
.linkButton {
|
||||
font-weight: var(--link-font-weight);
|
||||
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 */
|
||||
|
||||
/* if slim */
|
||||
@media only screen and (max-width: 480px) {
|
||||
width: 100%;
|
||||
@media only screen and (min-width: 480px) {
|
||||
width: auto; /* wide */
|
||||
}
|
||||
}
|
||||
|
||||
& .icon {
|
||||
.linkButton .icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
filter: drop-shadow(0px 0px 5px var(--secondary-color)) brightness(1.05);
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.links:hover .link:not(:hover) a {
|
||||
/* if wide */
|
||||
/* Default Hover Effect */
|
||||
.hoverHighlight:hover {
|
||||
@media only screen and (min-width: 480px) {
|
||||
filter: brightness(0.8);
|
||||
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.5);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
.linkButton:active {
|
||||
transform: scale(0.95);
|
||||
top: +2px;
|
||||
top: 2px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Search Input Field Styles */
|
||||
.fuzzysearch {
|
||||
margin: 0 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;
|
||||
}
|
||||
|
||||
/* Timers */
|
||||
#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);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
#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 {
|
||||
/* if slim */
|
||||
@media only screen and (max-width: 480px) {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px; /* slim */
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,7 +254,7 @@ h2 {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
/* Footer Styles */
|
||||
footer {
|
||||
text-align: center;
|
||||
}
|
@ -3,10 +3,12 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>julian brammer</title>
|
||||
<title>Julian Brammer</title>
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<link rel="me" href="https://social.brulijam.com/@brulijam">
|
||||
<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>
|
||||
</head>
|
||||
<body>
|
||||
@ -14,12 +16,13 @@
|
||||
<header>
|
||||
<!-- <img src="https://brulijam.com/assets/img/1_1713277032.jpga" alt="<profile picture>"></img>-->
|
||||
<div class="names">
|
||||
<h1>julian brammer</h1>
|
||||
<h1>Julian Brammer</h1>
|
||||
<p>@brulijam</p>
|
||||
</div>
|
||||
</header>
|
||||
<br>
|
||||
<section class="description">
|
||||
<p>css is pain and I used way too much math to implement that fuzzy search.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et
|
||||
dolore magna aliquyam erat, sed diam
|
||||
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
|
||||
@ -30,8 +33,10 @@
|
||||
takimata sanctus est Lorem ipsum dolor sit
|
||||
amet.</p>
|
||||
</section>
|
||||
<br>
|
||||
<script src="js/links.js"></script>
|
||||
<br><br>
|
||||
<section class="fuzzysearch">
|
||||
<input type="text" id="link-search" placeholder="fuzzy search">
|
||||
</section>
|
||||
<section class="links">
|
||||
<noscript>
|
||||
<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>
|
||||
|
70
src/js/distance.js
Normal file
70
src/js/distance.js
Normal 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);
|
||||
}
|
126
src/js/fuzzysearch.js
Normal file
126
src/js/fuzzysearch.js
Normal file
@ -0,0 +1,126 @@
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
@ -1,6 +1,7 @@
|
||||
function createLinkDiv(link) {
|
||||
const linkDiv = document.createElement('div');
|
||||
linkDiv.className = 'link';
|
||||
linkDiv.classList.add('hoverHighlight');
|
||||
|
||||
const anchor = document.createElement('a');
|
||||
anchor.className = 'linkButton';
|
||||
|
@ -1,34 +1,12 @@
|
||||
// const secondaryColors = [
|
||||
// // "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 = Math.floor(Math.random() * 360);
|
||||
|
||||
|
||||
let hue = 210;
|
||||
const colorChangeInterval = 50;
|
||||
const colorChangeInterval = 100;
|
||||
|
||||
function setRainbowColor() {
|
||||
const color = `hsl(${hue}, 80%, 80%)`;
|
||||
document.documentElement.style.setProperty('--secondary-color', color);
|
||||
document.documentElement.style.setProperty('--secondary-color2', `hsl(${hue}, 40%, 40%)`);
|
||||
document.documentElement.style.setProperty('--secondary-color-bg', `hsl(${hue}, 40%, 5%)`);
|
||||
hue = (hue + 1) % 360;
|
||||
}
|
||||
|
||||
|
60
src/js/redirect.js
Normal file
60
src/js/redirect.js
Normal 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>';
|
||||
}
|
@ -34,7 +34,7 @@ function calculateTime() {
|
||||
employedSinceTenthOfASecond = employedSinceTenthOfASecond.toString().padStart(2, "0");
|
||||
const employedSinceS = Math.floor(employedSinceMs / 1000);
|
||||
|
||||
// Update Document
|
||||
// update Document
|
||||
updateDocument("timer-alive-since-s", `${formatNumber(aliveSinceS)}`)
|
||||
updateDocument("timer-alive-since-ms", `.${formatNumber(aliveSinceTenthOfASecond)}`)
|
||||
updateDocument("timer-until-birthday-s", `${formatNumber(nextBirthdayS)}`)
|
||||
|
13
src/redirect.html
Normal file
13
src/redirect.html
Normal 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>
|
Loading…
Reference in New Issue
Block a user