Skip to content

Instantly share code, notes, and snippets.

@KoljaL
Created October 17, 2022 10:24
Show Gist options
  • Save KoljaL/a862ff68481e01d0fc2fa4d0d0ceeaab to your computer and use it in GitHub Desktop.
Save KoljaL/a862ff68481e01d0fc2fa4d0d0ceeaab to your computer and use it in GitHub Desktop.
My navigation in svelte will not work (isActive()) as a SPA
<script lang="ts">
import { onMount } from 'svelte';
import { base } from '$app/paths';
import { page } from '$app/stores';
// array for register tabs
const ABC = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
// called by every link of tabregister to set it active
$: isActive = (cat: string) => {
// get path as array
const pathArray = $page.url.pathname.split('/');
// article route /a*
// pathArray has exact two items, the fist is empty and the second is the article slug
// the first character of the slug has to be the same like the cat
if (pathArray.length === 2 && cat === pathArray[1][0]) {
// async call for scrolling
setTimeout(scrollTabIntoView, 100);
return true;
}
// categories route cat/a
// if the second [1] item is 'cat' and the third the same like cat its a category link
if (pathArray[1] === 'cat' && cat === pathArray[2]) {
// async call for scrolling
setTimeout(scrollTabIntoView, 100);
return true;
}
};
// let the active tab scroll into the view
function scrollTabIntoView() {
const activeLink = document.querySelector('nav a.active') as HTMLLinkElement;
console.log('activeLink');
if (activeLink && !isInViewport(activeLink)) {
activeLink.scrollIntoView({ block: 'center', behavior: 'smooth' });
}
}
// check if element is inside the viewport
function isInViewport(element: HTMLElement) {
const rect = element.getBoundingClientRect();
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
}
onMount(() => {
setHeights();
scrollTabIntoView();
window.addEventListener('resize', () => {
setTimeout(() => {
setHeights();
}, 300);
});
});
/**
*
* defines the height of the register tabs
* and after that the height of the main element
*
*/
function setHeights() {
// const NavHeadElement = document.querySelector('.nav-head');
const NavContentElement = document.querySelector('.nav-content') as HTMLElement;
const alphabetNavElements = document.querySelectorAll('.nav-content a') as NodeListOf<HTMLElement>;
let newRegisterCount;
// get height of nav-head element
// let navHeadElementHeight = NavHeadElement.offsetHeight;
// // console.log('navHeadElementHeight', navHeadElementHeight);
// get height of nav-content element
let currentNavContentHeight = NavContentElement.offsetHeight;
// console.log('currentNavContentHeight', currentNavContentHeight);
// get height of the first register element (they all has the same height)
let curtrentRegisterHeight = alphabetNavElements[0].offsetHeight;
// console.log('curtrentRegisterHeight', curtrentRegisterHeight):
// get visible register count
let registerCount: number = currentNavContentHeight / curtrentRegisterHeight;
// console.log('registerCount', registerCount)
// round registerCount to get an integer value
let registerCountRound = Math.round(registerCount);
// console.log('registerCountRound', registerCountRound)
// parse registerCount to integer value
let registerCountInt = Math.floor(registerCount);
// console.log('registerCountInt', registerCountInt)
// set newRegisterCount from rounded (bigger) or parseInt (smaller) value
if (registerCountInt === registerCountRound) {
newRegisterCount = registerCountInt;
} else {
newRegisterCount = registerCountRound;
}
// console.log('newRegisterCount', newRegisterCount)
// calculate newRegisterHeight
let newRegisterHeight = currentNavContentHeight / newRegisterCount;
// console.log('newRegisterHeight', newRegisterHeight)
// set newRegisterHeight to all elements
for (const el of alphabetNavElements) {
el.style.height = newRegisterHeight + 'px';
}
}
</script>
<nav>
<div class="nav-head">
<a href="{base}/" class="icon home">
<svg xmlns="http://www.w3.org/2000/svg" stroke="#4A5568" viewBox="0 0 512 512" version="1.1" width="24" height="24" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M 34.5,-0.5 C 181.833,-0.5 329.167,-0.5 476.5,-0.5C 494.5,4.83333 506.167,16.5 511.5,34.5C 511.5,181.833 511.5,329.167 511.5,476.5C 506.167,494.5 494.5,506.167 476.5,511.5C 329.167,511.5 181.833,511.5 34.5,511.5C 16.5,506.167 4.83333,494.5 -0.5,476.5C -0.5,329.167 -0.5,181.833 -0.5,34.5C 4.83333,16.5 16.5,4.83333 34.5,-0.5 Z M 44.5,29.5 C 139.833,29.5 235.167,29.5 330.5,29.5C 330.5,59.5 330.5,89.5 330.5,119.5C 230.167,119.5 129.833,119.5 29.5,119.5C 29.3334,94.4978 29.5,69.4978 30,44.5C 31.0117,35.6566 35.8451,30.6566 44.5,29.5 Z M 360.5,29.5 C 395.835,29.3333 431.168,29.5 466.5,30C 475.333,30.8333 480.167,35.6667 481,44.5C 481.5,69.4978 481.667,94.4978 481.5,119.5C 441.167,119.5 400.833,119.5 360.5,119.5C 360.5,89.5 360.5,59.5 360.5,29.5 Z M 29.5,149.5 C 180.167,149.5 330.833,149.5 481.5,149.5C 481.667,255.167 481.5,360.834 481,466.5C 480.167,475.333 475.333,480.167 466.5,481C 325.833,481.667 185.167,481.667 44.5,481C 35.6667,480.167 30.8333,475.333 30,466.5C 29.5,360.834 29.3333,255.167 29.5,149.5 Z" />
<path d="M 68.5,59.5 C 82.8372,59.3334 97.1705,59.5001 111.5,60C 119.915,64.3476 122.748,71.1809 120,80.5C 118.5,84.6667 115.667,87.5 111.5,89C 97.1667,89.6667 82.8333,89.6667 68.5,89C 59.5253,83.8483 57.0253,76.3483 61,66.5C 63.0147,63.5883 65.5147,61.255 68.5,59.5 Z" />
<path d="M 159.5,59.5 C 173.504,59.3334 187.504,59.5001 201.5,60C 209.915,64.3476 212.748,71.1809 210,80.5C 208.5,84.6667 205.667,87.5 201.5,89C 187.5,89.6667 173.5,89.6667 159.5,89C 150.525,83.8483 148.025,76.3483 152,66.5C 154.015,63.5883 156.515,61.255 159.5,59.5 Z" />
<path d="M 249.5,59.5 C 263.504,59.3334 277.504,59.5001 291.5,60C 299.915,64.3476 302.748,71.1809 300,80.5C 298.5,84.6667 295.667,87.5 291.5,89C 277.5,89.6667 263.5,89.6667 249.5,89C 240.525,83.8483 238.025,76.3483 242,66.5C 244.015,63.5883 246.515,61.255 249.5,59.5 Z" />
<path d="M 99.5,210.5 C 124.256,210.019 148.923,210.519 173.5,212C 176.473,213.765 178.64,216.265 180,219.5C 181.982,236.301 174.482,243.301 157.5,240.5C 169.565,278.696 182.232,316.696 195.5,354.5C 208.768,316.696 221.435,278.696 233.5,240.5C 216.518,243.301 209.018,236.301 211,219.5C 212.5,215.333 215.333,212.5 219.5,211C 243.5,210.333 267.5,210.333 291.5,211C 299.915,215.348 302.748,222.181 300,231.5C 298.5,235.667 295.667,238.5 291.5,240C 286.845,240.499 282.179,240.666 277.5,240.5C 289.565,278.696 302.232,316.696 315.5,354.5C 328.768,316.696 341.435,278.696 353.5,240.5C 336.518,243.301 329.018,236.301 331,219.5C 332.5,215.333 335.333,212.5 339.5,211C 363.5,210.333 387.5,210.333 411.5,211C 419.915,215.348 422.748,222.181 420,231.5C 418.64,234.735 416.473,237.235 413.5,239C 404.608,240.443 395.608,240.943 386.5,240.5C 367.975,297.575 349.142,354.575 330,411.5C 325.554,419.92 318.72,422.754 309.5,420C 306,417.833 303.167,415 301,411.5C 286.127,366.379 270.96,321.379 255.5,276.5C 240.04,321.379 224.873,366.379 210,411.5C 204.191,420.863 196.358,423.03 186.5,418C 184.291,416.127 182.458,413.96 181,411.5C 161.858,354.575 143.025,297.575 124.5,240.5C 116.16,240.666 107.827,240.5 99.5,240C 91.0851,235.652 88.2517,228.819 91,219.5C 92.6878,215.315 95.5212,212.315 99.5,210.5 Z" />
</svg>
</a>
<a href="{base}/search" class="icon search">
<svg width="24" height="24" viewBox="0 0 24 24" stroke="#4A5568" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 21L15 15M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" />
</svg>
</a>
</div>
<div class="nav-content">
{#each ABC as link}
<a href="{base}/cat/{link}" class={link} class:active={isActive(link)}>{link.toUpperCase()}</a>
{/each}
</div>
</nav>
<style>
/* NAVIGATION */
nav {
flex-shrink: 1;
display: flex;
flex-direction: column;
}
nav .nav-head {
position: absolute;
z-index: 10;
}
nav .nav-head > a {
height: var(--nav-head-element-height);
}
nav .nav-content {
position: relative;
/* padding-top: .5rem; */
top: calc(2 * var(--nav-head-element-height) - 1px);
height: calc(100% - 2 * var(--nav-head-element-height) + 1px);
overflow-y: auto;
scroll-snap-type: y mandatory;
}
nav .nav-content > a {
height: var(--nav-content-element-height);
}
/* TRY let the nav-content scroll a little higher than the previous tab to avoud sharp edges */
/* nav .nav-content a:first-of-type {margin-top: 5px;position: relative;top: .5rem;} */
/* NAVIGATION REGISTER LINKS */
nav a {
display: flex;
align-items: center;
justify-content: start;
width: var(--register-width);
padding-left: 35%;
font-family: 'Courier New', Courier, monospace;
font-size: 1.5rem;
background-color: var(--bg-tab);
border: 1px solid var(--border-color-sec);
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
border-top: none;
scroll-snap-stop: normal;
scroll-snap-align: start;
/* transition: all 0.5s; */
transition: var(--color-transition);
}
nav a:first-of-type {
border-top: 1px solid var(--border-color-sec);
transition: var(--color-transition);
}
nav a svg {
stroke: var(--text-color);
margin-left: -5px;
pointer-events: none;
transition: var(--color-transition);
}
nav a.active {
border-right: none;
background-color: var(--bg-content);
color: var(--bg-header);
transition: var(--color-transition);
}
nav a.active svg {
stroke: var(--bg-header);
transition: var(--color-transition);
}
nav a:not(.active):hover {
opacity: 0.5;
transition: opacity 0.5s;
}
nav a:not(.active):hover svg {
stroke: var(--text-hover-color);
transition: var(--color-transition);
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment