diff --git a/src/app/components/Contacts.tsx b/src/app/components/Contacts.tsx index 52c4af9..ee09a8a 100644 --- a/src/app/components/Contacts.tsx +++ b/src/app/components/Contacts.tsx @@ -1,7 +1,6 @@ import React, { ReactNode } from 'react' import { usePersonContext } from '../hooks/PersonContext' import Container from 'react-bootstrap/esm/Container' -import { useAutoFocus } from '../hooks/FocusedElement' import { Col, Row } from 'react-bootstrap' export function Contact(props: {icon?: string, text: string}) { @@ -30,9 +29,8 @@ export function Contact(props: {icon?: string, text: string}) { export function Contacts() { const person = usePersonContext() - const focus = useAutoFocus('contacts') return ( - +

Contacts

diff --git a/src/app/components/TagCloud.tsx b/src/app/components/TagCloud.tsx index 556051c..10c2d8a 100644 --- a/src/app/components/TagCloud.tsx +++ b/src/app/components/TagCloud.tsx @@ -1,6 +1,5 @@ import React from 'react'; import Container from 'react-bootstrap/Container'; -import { useAutoFocus } from '../hooks/FocusedElement'; import Tag from './Tag'; export type Props = { @@ -11,10 +10,9 @@ export type Props = { } export default function TagCloud(props: Props) { - const focusRef = useAutoFocus('tags ' + props.title) const containerClasses = ['tag-cloud', 'cloud-' + (props.style || 'standard')] return ( - +

{props.icon && ( )}{props.title}

{props.tags.map((tag: string) => () )} diff --git a/src/app/components/job/JobCard.tsx b/src/app/components/job/JobCard.tsx index 3e46d1e..1caccf3 100644 --- a/src/app/components/job/JobCard.tsx +++ b/src/app/components/job/JobCard.tsx @@ -1,8 +1,7 @@ import React from 'react'; import Card from 'react-bootstrap/Card'; -import { useAutoFocus } from '../../hooks/FocusedElement'; import { Placeholder } from 'react-bootstrap'; -import JobTags, { focusKeyPlaceholder } from './JobTags'; +import JobTags from './JobTags'; import { Job } from '@/PersonalDataTypes'; import md from '../Markdown'; @@ -25,9 +24,8 @@ export function JobCardPlaceholder() { } export default function JobCard(props: Props) { - const focusRef = useAutoFocus([props.position, props.company, props.timerange].join(' - ')) return ( - + {props.heading && ( {props.heading} )} diff --git a/src/app/components/job/JobsAccordion.tsx b/src/app/components/job/JobsAccordion.tsx index 38e84ca..9a6879c 100644 --- a/src/app/components/job/JobsAccordion.tsx +++ b/src/app/components/job/JobsAccordion.tsx @@ -1,11 +1,34 @@ import React from 'react'; import { Job } from '@/PersonalDataTypes'; -import { Accordion, Row } from 'react-bootstrap'; +import { Accordion } from 'react-bootstrap'; import { JobListProps } from './types'; import JobTags from './JobTags'; import md from '../Markdown'; +function JobTitle(props: {job: Job, heading?: string}) { + const {job, heading} = props + return ( +
+
{job.position}
+
{[job.company, job.timerange].filter(x => x).join(', ')}
+ {heading && (
({heading})
)} +
+ ) +} + +function AccordionJobItem(props: {job: Job, eventKey: string, heading?: string}) { + const {job, eventKey} = props + return ( + + + + {md(job.description)} + {job.tags && } + + + ) +} export type Props = { heading: string, @@ -19,36 +42,10 @@ const defaultProps = { export default function JobsAccordion(props: JobListProps) { const {jobs} = props const config = {...defaultProps, ...props} - function JobTitle(props: {job: Job, heading?: string}) { - const {job, heading} = props - return ( -
-
{job.position}
-
{[job.company, job.timerange].filter(x => x).join(', ')}
- {heading && (
({heading})
)} -
- ) - } return ( - {jobs.current && ( - - - - {md(jobs.current.description)} - {jobs.current.tags && } - - - )} - {jobs.previous?.map((job, index) => ( - - - - {md(job.description)} - {job.tags && } - - - ))} + {jobs.current && } + {jobs.previous?.map((job, index) => )} ) } diff --git a/src/app/hooks/FocusedElement.tsx b/src/app/hooks/FocusedElement.tsx deleted file mode 100644 index fc9edfb..0000000 --- a/src/app/hooks/FocusedElement.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState, useRef, useEffect, useCallback } from "react"; - -const focusUrlParamName = 'focus' -const focusChangedEventName = "focus-changed" -const focusedElementClassName = 'focused-element' - -function triggerElementFocused(elementKey?: string) { - const url = new URL(window.location.href); - if (elementKey) { - url.searchParams.set(focusUrlParamName, elementKey) - } else { - url.searchParams.delete(focusUrlParamName) - } - const focusChangeEvent = new Event(focusChangedEventName) - history.pushState({}, "", url); - window.dispatchEvent(focusChangeEvent) -} - -export function useFocusedElement(elementKey: string) { - const [isFocusedElement, setFocusedElement] = useState(false) - const focusedClass = isFocusedElement ? focusedElementClassName : '' - const elementRef = useRef(null) - - const focusElement = useCallback(() => { - triggerElementFocused(isFocusedElement ? undefined : elementKey) - }, [isFocusedElement, elementKey]) - - useEffect(() => { - function updateFocusedState() { - const params = new URLSearchParams(window.location.search) - const focusedElement = params.get(focusUrlParamName) - const focused: boolean = focusedElement && focusedElement == elementKey || false - setFocusedElement(focused) - } - - updateFocusedState() - addEventListener(focusChangedEventName, updateFocusedState) - return () => { - removeEventListener(focusChangedEventName, updateFocusedState) - } - }, [elementKey, setFocusedElement, focusElement]) - - isFocusedElement && elementRef.current?.scrollIntoView() - - return {isFocusedElement, focusedClass, elementRef, focusElement} -} - -export function useAutoFocus(elementKey: string) { - const {elementRef, focusedClass, focusElement} = useFocusedElement(elementKey); - - useEffect(() => { - let cleanup = () => {} - if (elementRef.current) { - const elem = elementRef.current - elem.onclick = (evt) => { - evt.stopPropagation() - focusElement() - } - const classNameBackup = elem.className - elem.className += ' focusable ' + focusedClass - cleanup = () => { - elem.className = classNameBackup - } - } - return cleanup - }, [elementRef, focusedClass, focusElement]) - - return elementRef -} diff --git a/src/app/utils.ts b/src/app/utils.ts deleted file mode 100644 index 8947d3a..0000000 --- a/src/app/utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function partition(array: T[]|undefined, entriesPerRow: number): T[][] { - return array ? array.reduce((accumulator: T[][], current: T, index) => { - if (index % entriesPerRow == 0) { - accumulator[accumulator.length] = [current] - } else { - accumulator[accumulator.length - 1] - } - return accumulator - }, []) : [] - } diff --git a/src/index.html b/src/index.html deleted file mode 100644 index 30dce77..0000000 --- a/src/index.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - Bootstrap w/ Webpack - - -
-
-

- - - - - - Webpack - -

- View on GitHub -
- -

Build Bootstrap with Webpack

-
-

You've successfully loaded the Bootstrap + Webpack example! It's loaded up with Bootstrap 5 and uses Webpack to compile and bundle our Sass and JavaScript. It also includes Autoprefixer.

-

If this button appears blue and the link appears purple, you've done it!

-
- - - Example popover - -
-
-
Offcanvas
- -
-
-
- Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc. -
- -
-
- -
- -

Guides

-

Read more detailed instructions and documentation on using or contributing to Bootstrap.

- - -
- -

Created and open sourced by the Bootstrap team. Licensed MIT.

-
- -