Update active sidebar item dynamically on scroll (#79)

This commit is contained in:
Szymon Kin 2022-11-07 21:16:39 +01:00 committed by GitHub
parent 599c8bc479
commit 08ab03a2d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 11 deletions

View file

@ -1,4 +1,4 @@
import { useHash } from 'react-use';
import { useLocation } from 'react-use';
import { MAIN_SECTION } from '@/constants/section';
import type { Section } from '@/types/data';
@ -12,7 +12,7 @@ export interface Props {
}
const SidebarItem = ({ section, icon }: Props) => {
const [hash] = useHash();
const { hash } = useLocation();
const href = `#${section}`;
const active = hash === '' ? section === MAIN_SECTION : hash === href;

View file

@ -1,8 +1,18 @@
---
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import type { Section } from '@/types/data';
import type { ExperienceSection } from '@/types/experience-section';
export interface Props extends ExperienceSection {}
const {
config: { title },
} = Astro.props;
const section: Section = 'experience';
---
<SectionCard section="experience">Experience section</SectionCard>
<SectionCard section={section}
><Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
</SectionCard>

View file

@ -1,8 +1,18 @@
---
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import type { Section } from '@/types/data';
import type { FavoritesSection } from '@/types/favorites-section';
export interface Props extends FavoritesSection {}
const {
config: { title },
} = Astro.props;
const section: Section = 'favorites';
---
<SectionCard section="favorites">Favorites section</SectionCard>
<SectionCard section={section}
><Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
</SectionCard>

View file

@ -6,6 +6,7 @@ import IconButton from '@/atoms/icon-button.astro';
import SectionCard from '@/atoms/section-card.astro';
import Tag from '@/atoms/tag.astro';
import Typography from '@/atoms/typography.astro';
import type { Section } from '@/types/data';
import type { MainSection } from '@/types/main-section';
export interface Props extends MainSection {}
@ -20,9 +21,11 @@ const {
action: { label, url, downloadedFileName },
tags,
} = Astro.props;
const section: Section = 'main';
---
<SectionCard section="main">
<SectionCard section={section}>
<div class:list={['flex', 'gap-6', 'flex-col', 'sm:flex-row', 'items-start']}>
<div class:list={['flex', 'sm:flex-col', 'gap-4', 'items-center']}>
<Image
@ -35,7 +38,7 @@ const {
<div class:list={['w-full', 'flex', 'flex-col', 'gap-5']}>
<div class:list={['w-full', 'flex', 'flex-col', 'sm:flex-row', 'justify-between', 'gap-2']}>
<div class:list={['w-full']}>
<Typography variant="main-title">{fullName}</Typography>
<Typography variant="main-title" id={`${section}-heading`}>{fullName}</Typography>
<Typography variant="main-subtitle">{role}</Typography>
</div>
{

View file

@ -1,8 +1,18 @@
---
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import type { Section } from '@/types/data';
import type { PortfolioSection } from '@/types/portfolio-section';
export interface Props extends PortfolioSection {}
const {
config: { title },
} = Astro.props;
const section: Section = 'portfolio';
---
<SectionCard section="portfolio">Portfolio section</SectionCard>
<SectionCard section={section}
><Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
</SectionCard>

View file

@ -2,6 +2,7 @@
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import SkillSubsection from '@/organisms/skill-subsection.astro';
import type { Section } from '@/types/data';
import type { SkillsSection } from '@/types/skills-section';
export interface Props extends SkillsSection {}
@ -10,10 +11,12 @@ const {
config: { title },
skillSets,
} = Astro.props;
const section: Section = 'skills';
---
<SectionCard section="skills">
<Typography variant="section-title">{title}</Typography>
<SectionCard section={section}>
<Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
<div class:list={['flex', 'flex-col', 'gap-10']}>
{skillSets.map((skillSet) => <SkillSubsection skillSet={skillSet} />)}
</div>

View file

@ -3,6 +3,7 @@ import Divider from '@/atoms/divider.astro';
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import Testimonial from '@/organisms/testimonial.astro';
import type { Section } from '@/types/data';
import type { TestimonialsSection } from '@/types/testimonials-section';
export interface Props extends TestimonialsSection {}
@ -11,10 +12,12 @@ const {
testimonials,
config: { title },
} = Astro.props;
const section: Section = 'testimonials';
---
<SectionCard section="testimonials">
<Typography variant="section-title">{title}</Typography>
<SectionCard section={section}>
<Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
<div class:list={['flex', 'flex-col']}>
{
testimonials.map((testimonial, index) => (

View file

@ -46,4 +46,10 @@ const { seo, ...dataWithoutSeo } = data;
</main>
</div>
</body>
<script>
import updateHash from '../scripts/updateHash';
import data from '../data';
document.addEventListener('scroll', () => updateHash(data));
</script>
</html>

28
src/scripts/updateHash.ts Normal file
View file

@ -0,0 +1,28 @@
import type { Data } from '@/types/data';
const updateHash = (data: Data) => {
const { seo, ...dataWithoutSeo } = data;
const distancesToHeadingBottom = Object.keys(dataWithoutSeo)
.flatMap((section) => {
const sectionWrapper = document.getElementById(`${section}-heading`);
if (!sectionWrapper) return [];
const { bottom } = sectionWrapper.getBoundingClientRect();
return {
section,
bottom,
};
})
.filter((section) => section.bottom > 0);
const currentSection = distancesToHeadingBottom.reduce((previous, current) =>
previous.bottom < current.bottom ? previous : current
);
window.history.pushState({}, '', `${window.location.pathname}#${currentSection.section}`);
};
export default updateHash;