const loadedScripts = []; let selectedButtonId = 'button-home'; const changeSelected = (buttonId) => { A(`#${selectedButtonId}`).removeClass('button-selected'); A(`#${buttonId}`).addClass('button-selected'); selectedButtonId = buttonId; }; const stripTrailingSlash = (str) => { return str.endsWith('/') ? str.slice(0, -1) : str; }; const loadBlogScripts = async () => { await loadScript('https://cdn.jsdelivr.net/npm/marked/marked.min.js'); await loadScript('/res/blog.js'); } const peformRouteAction = async (pathname) => { const route = stripTrailingSlash(pathname); switch (route) { case '': { A('#content-container').load('/pages/home.html'); A('meta[name="description"]').attr('content', "Hippoz's homepage on hippoz.xyz with a file server, a git server, an about page, a contact page, and a blog."); break; } case '/blog': { A('meta[name="description"]').attr('content', "hippoz's blog"); await loadBlogScripts(); await A('#content-container').load('/pages/blog/blog.html'); blogPopulateArticleList('articlelist'); break; } case '/upload': { A('meta[name="description"]').attr('content', "hippoz's upload server"); A('#content-container').load('/pages/upload.html'); break; } case '/git': { window.location.href = 'https://git.hippoz.xyz/'; break; } case '/about': { A('meta[name="description"]').attr('content', "hippoz's about page. i'm hippoz"); A('#content-container').load('/pages/about.html'); break; } case '/contact': { A('meta[name="description"]').attr('content', "you can contact hippoz"); A('#content-container').load('/pages/contact.html'); break; } case '/404': {} default: { A('#content-container').html('

page not found

i think

'); break; } } }; const buttonMap = { 'button-home': '/', 'button-blog': '/blog', 'button-file-server': '/upload', 'button-git-server': '/git', 'button-about-me': '/about', 'button-contact-me': '/contact', '__NOT_FOUND': '/404' } const dynamicRoutesActions = { '/article': async (arg) => { await loadBlogScripts(); const desc = blogArticles[arg]; if (!desc) { peformRouteAction('/404'); return; } changeSelected(getButtonFromPathname('/blog')); blogVisitArticle(arg, desc); } }; const onButtonClick = (buttonId) => { // The condition after && is kinda of a hack, the reason I do this is because I want users to be able to click the blog button and return to the article list to continue reading when they are already on an article. if (selectedButtonId === buttonId && buttonId !== 'button-blog') { return; } changeSelected(buttonId); let route = buttonMap[buttonId]; if (!route) { route = buttonMap['__NOT_FOUND']; } peformRouteAction(route); history.pushState({ route }, '', route); }; const getButtonFromPathname = (pathname) => { let button = 'button-home'; for (const [k, v] of Object.entries(buttonMap)) { if (v === pathname) { button = k; break; } } return button; } const updateFromCurrentPathname = () => { let pathname = window.location.pathname; if (!pathname || pathname === '' || pathname === ' ') { pathname = '/'; } for (const [route, action] of Object.entries(dynamicRoutesActions)) { if (pathname.startsWith(route)) { const arg = stripTrailingSlash(pathname).split('/')[2]; action(arg); break; } } const buttonId = getButtonFromPathname(pathname); changeSelected(buttonId); peformRouteAction(pathname); } const loadScript = (src) => { if (loadedScripts.includes(src)) { return; } return new Promise((resolve, reject) => { const script = document.createElement('script'); script.onload = () => { loadedScripts.push(src); resolve(); }; script.onerror = reject; script.src = src; document.head.appendChild(script); }); } A(() => { A('.navigation-buttons .button-default').each((el) => { A(el).on('click', () => { onButtonClick(el.id); }); }); updateFromCurrentPathname(); });