|
<!-- SCROLL TO THE BOTTOM OF THE GIST TO SEE README --> |
|
<!DOCTYPE html> |
|
<html lang='en'> |
|
<head> |
|
<meta charset='UTF-8' /> |
|
<meta name='viewport' content='width=device-width, initial-scale=1.0' /> |
|
<meta http-equiv='X-UA-Compatible' content='ie-edge' /> |
|
|
|
<title>startpage</title> |
|
|
|
<!-- {{{ user config --> |
|
<script> |
|
const autojump = true; |
|
const links = [ |
|
{ |
|
title: 'school', |
|
links: [ |
|
{ name: 'gcal', url: 'https://calendar.google.com/calendar/u/0/r/week' }, |
|
{ name: 'gmail', url: 'https://gmail.com/' }, |
|
{ name: 'outlook', url: 'https://webmail.student.ubc.ca/owa/' }, |
|
{ name: 'canvas', url: 'https://canvas.ubc.ca/' }, |
|
], |
|
}, |
|
{ |
|
title: 'util', |
|
links: [ |
|
{ name: 'github inbox', url: 'https://github.com/notifications' }, |
|
{ name: 'nix search', url: 'https://search.nixos.org/packages' }, |
|
{ name: 'syncthing', url: 'http://127.0.0.1:8384/' }, |
|
{ name: 'org-roam', url: 'http://localhost:35901/' }, |
|
], |
|
}, |
|
{ |
|
title: 'social', |
|
links: [ |
|
{ name: 'discord', url: 'https://discord.com/app' }, |
|
{ name: 'twitter', url: 'https://x.com/' }, |
|
{ name: 'youtube', url: 'https://www.youtube.com/' }, |
|
{ name: 'instagram', url: 'https://www.instagram.com/direct/inbox/' }, |
|
], |
|
}, |
|
{ |
|
title: 'other', |
|
links: [ |
|
{ name: 'monkeytype', url: 'https://monkeytype.com/' }, |
|
{ name: 'wikispeedrun', url: 'https://wikispeedrun.org' }, |
|
{ name: 'mynoise', url: 'https://mynoise.net/noiseMachines.php' }, |
|
{ name: 'rain sounds', url: 'https://mynoise.net/NoiseMachines/whiteRainNoiseGenerator.php?l=53474337374040454849&a=1&am=s&title=White%20Rain' }, |
|
], |
|
}, |
|
]; |
|
</script> |
|
<!-- }}} --> |
|
|
|
<!-- {{{ css --> |
|
<style> |
|
:root { |
|
--font: 'IBM Plex Sans', monospace; |
|
|
|
--bg1: #2b3339; |
|
--bg2: #323c41; |
|
--fg1: #d3c6aa; |
|
--fg2: #859289; |
|
--dim: #607279; |
|
--accent1: #a7c080; |
|
--accent2: #e67e80; |
|
--accent3: #7fbbb3; |
|
} |
|
|
|
body { |
|
background-color: var(--bg1); |
|
margin: 0px; |
|
} |
|
|
|
.container { |
|
width: 100%; |
|
height: 100vh; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
flex-direction: column; |
|
} |
|
|
|
#clock-time { |
|
text-align: center; |
|
font-family: sans-serif; |
|
font-size: 3.5rem; |
|
font-weight: 600; |
|
font-family: var(--font); |
|
color: var(--fg1); |
|
margin-bottom: 0.1em; |
|
} |
|
|
|
#clock-date { |
|
text-align: center; |
|
font-family: sans-serif; |
|
font-size: 1.2rem; |
|
font-weight: 600; |
|
font-family: var(--font); |
|
color: var(--fg2); |
|
margin-bottom: -0.1em; |
|
} |
|
|
|
.inline { |
|
color: var(--accent2); |
|
display: inline-block; |
|
} |
|
|
|
#bookmark-container { |
|
display: flex; |
|
flex-wrap: wrap; |
|
flex-direction: grid; |
|
justify-content: center; |
|
width: 50%; |
|
margin: 1em 1em; |
|
} |
|
|
|
@media only screen and (max-width: 960px) { |
|
.container { |
|
height: auto; |
|
} |
|
#clock { |
|
margin-top: 1em; |
|
} |
|
.container > .bookmark-container { |
|
flex-direction: column; |
|
width: 60%; |
|
} |
|
.bookmark-container > .bookmark-set { |
|
width: auto; |
|
margin: 1em 0em; |
|
} |
|
} |
|
|
|
.bookmark-set { |
|
padding: 1em; |
|
background-color: var(--bg2); |
|
border-radius: 3px; |
|
font-family: var(--font); |
|
font-size: 0.85rem; |
|
width: 14em; |
|
height: 12em; |
|
margin: 0.5em; |
|
box-sizing: border-box; |
|
} |
|
|
|
.bookmark-inner-container { |
|
overflow-y: scroll; |
|
height: 80%; |
|
vertical-align: top; |
|
padding-right: 6px; |
|
box-sizing: border-box; |
|
scrollbar-width: thin; |
|
scrollbar-color: var(--dim) #ffffff00; |
|
} |
|
|
|
.bookmark-inner-container::-webkit-scrollbar { |
|
width: 6px; |
|
} |
|
.bookmark-inner-container::-webkit-scrollbar-track { |
|
background: #ffffff00; |
|
} |
|
.bookmark-inner-container::-webkit-scrollbar-thumb { |
|
background-color: var(--dim); |
|
border-radius: 6px; |
|
border: 3px solid #ffffff00; |
|
} |
|
|
|
.bookmark-title { |
|
color: var(--accent1) !important; |
|
font-size: 1.1rem; |
|
font-weight: 600; |
|
color: var(--fg1); |
|
margin: 0em 0em 0.35em 0em; |
|
} |
|
|
|
.bm-highlight { |
|
color: var(--accent3) !important; |
|
font-weight: bold !important; |
|
} |
|
.bm-bright { |
|
color: var(--fg1) !important; |
|
} |
|
.bm-selected { |
|
font-weight: bold; |
|
} |
|
|
|
.bookmark { |
|
text-decoration: none; |
|
color: var(--fg2); |
|
display: block; |
|
margin: 0.5em 0em; |
|
transition: 0.3s color; |
|
transition: 0.3s font-weight; |
|
} |
|
.bookmark:hover { |
|
color: var(--accent3); |
|
font-weight: 600; |
|
transition: 0.3s color; |
|
transition: 0.3s font-weight; |
|
} |
|
|
|
@media only screen and (max-width: 446px) { |
|
#clock-time, |
|
#clock-date { |
|
text-align: center; |
|
font-family: sans-serif; |
|
font-size: 1.5rem; |
|
font-weight: 600; |
|
font-family: var(--font); |
|
color: var(--fg1); |
|
margin-bottom: 0.25em; |
|
} |
|
} |
|
</style> |
|
<!-- }}} --> |
|
</head> |
|
|
|
<body> |
|
<div class='container'> |
|
<input type='text' id='search' style='opacity: 0; position: absolute' autocomplete='off' /> |
|
<div id='clock-time'></div> |
|
<div id='clock-date'></div> |
|
<div id='bookmark-container'></div> |
|
</div> |
|
|
|
<!-- {{{ setup --> |
|
<script> |
|
const clockTime = document.getElementById('clock-time'); |
|
const clockDate = document.getElementById('clock-date'); |
|
const bookmarkC = document.getElementById('bookmark-container'); |
|
const search = document.getElementById('search'); |
|
|
|
// {{{ update time elements |
|
function time() { |
|
let date = new Date(), |
|
M = date.getMinutes(), |
|
H = date.getHours(), |
|
d = date.getDate(), |
|
m = date.getMonth() + 1, |
|
Y = date.getFullYear(); |
|
|
|
clockTime.innerHTML = `${H < 10 ? '0' : ''}${H}:${M < 10 ? '0' : ''}${M}`; |
|
clockDate.innerHTML = `${Y}.${m < 10 ? '0' : ''}${m}.${d < 10 ? '0' : ''}${d}`; |
|
} |
|
// }}} |
|
|
|
// {{{ set up bookmark containers |
|
function setupBookmarks() { |
|
bookmarkC.innerHTML = links |
|
.map(b => { |
|
const html = ["<div class='bookmark-set'>"]; |
|
html.push(`<div class='bookmark-title'>${b.title}</div>`); |
|
html.push("<div class='bookmark-inner-container'>"); |
|
html.push(...b.links.map(l => `<a class='bookmark' href='${l.url}'>${l.name}</a>`)); |
|
html.push('</div></div>'); |
|
return html.join(''); |
|
}) |
|
.join(''); |
|
}; |
|
// }}} |
|
|
|
window.onload = () => { |
|
// set up bookmarks |
|
setupBookmarks(); |
|
|
|
// update time every 0.1s |
|
time(); setInterval(time, 100); |
|
|
|
// {{{ handle bookmark filtering |
|
const bookmarks = Array.from(document.getElementsByClassName('bookmark')) |
|
let filtered = []; |
|
let sel = 0; |
|
|
|
function filterBookmarks() { |
|
let matched = false; |
|
|
|
// clear filtered links |
|
filtered = []; |
|
sel = 0; |
|
|
|
bookmarks.forEach(l => { |
|
let name = l.innerText || l.innerHTML.replace(/<\/?span( class='bm-highlight')?>/g, ''); |
|
|
|
// check match |
|
if (search.value && name.toLowerCase().startsWith(search.value.toLowerCase())) { |
|
// {{{ matched |
|
// highlight |
|
l.classList.add('bm-bright') |
|
matched || l.classList.add('bm-selected') |
|
|
|
filtered.push({ el: l, name: name }); |
|
matched = true; |
|
|
|
// remove match prefix |
|
name = name.replace(new RegExp(`^${search.value}`), ''); |
|
l.innerText = ''; |
|
l.innerHTML = `<span class='bm-highlight'>${search.value}</span>${name}`; |
|
// }}} |
|
} else { |
|
// {{{ no match |
|
// unhighlight |
|
l.classList.remove('bm-bright') |
|
l.classList.remove('bm-selected') |
|
|
|
// reset |
|
l.innerHTML = name; |
|
// }}} |
|
} |
|
}); |
|
|
|
// clear search field if no matches |
|
if (!matched) { search.value = ''; return; } |
|
|
|
// highlight selected bookmark |
|
filtered[sel]?.el.classList.add('bm-selected') |
|
|
|
// autojump to bookmark (if enabled) |
|
if (autojump && filtered.length == 1) { window.location.href = filtered[0].el.href; return } |
|
} |
|
// }}} |
|
|
|
// set up search field |
|
search.focus() |
|
search.onblur = search.focus // always focused |
|
search.addEventListener('input', filterBookmarks); |
|
|
|
// {{{ handle keybinds |
|
document.addEventListener('keydown', evt => { |
|
let prevent = false; |
|
if (evt.keyCode == 27) { |
|
// ESC: clear search field |
|
search.value = ''; |
|
filterBookmarks(); |
|
|
|
prevent = true; |
|
} else if (evt.keyCode == 9) { |
|
// {{{ TAB/SHIFT-TAB: navigate up/down bookmarks |
|
// unhighlight previous |
|
filtered[sel]?.el.classList.remove('bm-selected') |
|
|
|
// navigate up/down |
|
sel += evt.shiftKey ? -1 : +1; |
|
|
|
if (sel < 0) { |
|
sel = filtered.length - 1; |
|
} else if (sel >= filtered.length) { |
|
sel = 0; |
|
} |
|
|
|
// highlight selected bookmark |
|
filtered[sel]?.el.classList.add('bm-selected') |
|
// }}} |
|
|
|
prevent = true; |
|
} else if (evt.keyCode == 13) { |
|
// ENTER: jump to link |
|
if (filtered[sel] !== undefined) { |
|
window.location.href = filtered[sel]?.el.href; |
|
prevent = true; |
|
} |
|
} |
|
|
|
if (prevent) { |
|
evt.preventDefault(); |
|
evt.stopPropagation(); |
|
} |
|
}) |
|
// }}} |
|
} |
|
</script> |
|
<!-- }}} --> |
|
</body> |
|
</html> |