Refactor components to simplify them
This commit is contained in:
parent
3cf5b14913
commit
077ed9d3bf
36 changed files with 202 additions and 216 deletions
|
|
@ -1,78 +1,76 @@
|
||||||
|
import { PageBackground } from '../page/background/background';
|
||||||
|
import { Image } from '../page/basics/image/image';
|
||||||
|
import { PageFooter } from '../page/footer/footer';
|
||||||
|
import { PageHeader } from '../page/header/header';
|
||||||
|
import { PageImageViewer } from '../page/image-viewer/image-viewer';
|
||||||
|
import { Main } from '../page/main/main';
|
||||||
|
import { PageElement } from '../page/page-element';
|
||||||
|
import { PageTimeline } from '../page/timeline/timeline';
|
||||||
|
import cvEnglish from './media/cv-andras-schmelczer.pdf';
|
||||||
import meJpeg from './media/me.jpg?format=jpg';
|
import meJpeg from './media/me.jpg?format=jpg';
|
||||||
import meWebP from './media/me.jpg?format=webp';
|
import meWebP from './media/me.jpg?format=webp';
|
||||||
import cvEnglish from './media/cv-andras-schmelczer.pdf';
|
|
||||||
|
|
||||||
import { PageFooter } from '../page/footer/footer';
|
|
||||||
import { Image } from '../page/basics/image/image';
|
|
||||||
import { PageHeader } from '../page/header/header';
|
|
||||||
import { PageTimeline } from '../page/timeline/timeline';
|
|
||||||
import { PageImageViewer } from '../page/image-viewer/image-viewer';
|
|
||||||
import { PageBackground } from '../page/background/background';
|
|
||||||
import { Main } from '../page/main/main';
|
|
||||||
import { Body } from '../page/body/body';
|
|
||||||
import { declaredTimelineElement } from './projects/declared';
|
|
||||||
import { sdf2dTimelineElement } from './projects/sdf2d';
|
|
||||||
import { adAstraTimelineElement } from './projects/ad-astra';
|
import { adAstraTimelineElement } from './projects/ad-astra';
|
||||||
|
import { citySimulationTimelineElement } from './projects/city-simulation';
|
||||||
|
import { declaredTimelineElement } from './projects/declared';
|
||||||
import { forexTimelineElement } from './projects/forex';
|
import { forexTimelineElement } from './projects/forex';
|
||||||
|
import { greatAiTimelineElement } from './projects/great-ai';
|
||||||
|
import { ledsTimelineElement } from './projects/leds';
|
||||||
import { myNotesTimelineElement } from './projects/my-notes';
|
import { myNotesTimelineElement } from './projects/my-notes';
|
||||||
import { nuclearTimelineElement } from './projects/nuclear';
|
import { nuclearTimelineElement } from './projects/nuclear';
|
||||||
import { nuclearEditorTimelineElement } from './projects/nuclear-editor';
|
import { nuclearEditorTimelineElement } from './projects/nuclear-editor';
|
||||||
import { citySimulationTimelineElement } from './projects/city-simulation';
|
|
||||||
import { platformGameTimelineElement } from './projects/platform-game';
|
|
||||||
import { photosTimelineElement } from './projects/photos';
|
import { photosTimelineElement } from './projects/photos';
|
||||||
import { ledsTimelineElement } from './projects/leds';
|
import { platformGameTimelineElement } from './projects/platform-game';
|
||||||
|
import { sdf2dTimelineElement } from './projects/sdf2d';
|
||||||
import { towersTimelineElement } from './projects/towers';
|
import { towersTimelineElement } from './projects/towers';
|
||||||
import { greatAiTimelineElement } from './projects/great-ai';
|
|
||||||
|
|
||||||
export const create = () =>
|
export const create = (): Array<PageElement> => [
|
||||||
new Body(
|
new Main(
|
||||||
new Main(
|
new PageBackground(1, 1),
|
||||||
new PageBackground(1, 1),
|
new PageHeader({
|
||||||
new PageHeader({
|
name: `András Schmelczer`,
|
||||||
name: `András Schmelczer`,
|
photo: new Image(meWebP, meJpeg, `a picture of me`, false),
|
||||||
photo: new Image(meWebP, meJpeg, `a picture of me`, false),
|
about: [
|
||||||
about: [
|
`
|
||||||
`
|
|
||||||
I have always been fascinated by the engineering feats that surround us and pervade every aspect
|
I have always been fascinated by the engineering feats that surround us and pervade every aspect
|
||||||
of our lives. When I realised I might someday be able to contribute to this field, I knew that
|
of our lives. When I realised I might someday be able to contribute to this field, I knew that
|
||||||
this would become my life's ambition.
|
this would become my life's ambition.
|
||||||
As I am starting my third semester at Leiden University,
|
As I am starting my third semester at Leiden University,
|
||||||
I feel I am getting closer to my ambition every day.
|
I feel I am getting closer to my ambition every day.
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
Discover some of my more interesting projects. They are all listed below.
|
Discover some of my more interesting projects. They are all listed below.
|
||||||
Further information about me can be found at the bottom of the page.
|
Further information about me can be found at the bottom of the page.
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
new PageTimeline({
|
new PageTimeline({
|
||||||
showMoreText: `Show details`,
|
showMoreText: `Show details`,
|
||||||
showLessText: `Show less`,
|
showLessText: `Show less`,
|
||||||
elements: [
|
elements: [
|
||||||
greatAiTimelineElement,
|
greatAiTimelineElement,
|
||||||
declaredTimelineElement,
|
declaredTimelineElement,
|
||||||
sdf2dTimelineElement,
|
sdf2dTimelineElement,
|
||||||
adAstraTimelineElement,
|
adAstraTimelineElement,
|
||||||
forexTimelineElement,
|
forexTimelineElement,
|
||||||
myNotesTimelineElement,
|
myNotesTimelineElement,
|
||||||
towersTimelineElement,
|
towersTimelineElement,
|
||||||
nuclearTimelineElement,
|
nuclearTimelineElement,
|
||||||
nuclearEditorTimelineElement,
|
nuclearEditorTimelineElement,
|
||||||
citySimulationTimelineElement,
|
citySimulationTimelineElement,
|
||||||
platformGameTimelineElement,
|
platformGameTimelineElement,
|
||||||
photosTimelineElement,
|
photosTimelineElement,
|
||||||
ledsTimelineElement,
|
ledsTimelineElement,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
new PageFooter({
|
new PageFooter({
|
||||||
title: `Learn more`,
|
title: `Learn more`,
|
||||||
curriculaVitae: [{ name: `Curriculum vitae`, url: cvEnglish }],
|
curriculaVitae: [{ name: `Curriculum vitae`, url: cvEnglish }],
|
||||||
email: `andras@schmelczer.dev`,
|
email: `andras@schmelczer.dev`,
|
||||||
linkedin: `https://www.linkedin.com/in/andras-schmelczer-35487017b`,
|
linkedin: `https://www.linkedin.com/in/andras-schmelczer-35487017b`,
|
||||||
lastEditText: `Last modified on `,
|
lastEditText: `Last modified on `,
|
||||||
// @ts-ignore: injected by webpack
|
// @ts-ignore: injected by webpack
|
||||||
lastEdit: new Date(__CURRENT_DATE__),
|
lastEdit: new Date(__CURRENT_DATE__),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
new PageImageViewer()
|
new PageImageViewer(),
|
||||||
);
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Video } from '../../page/basics/video/video';
|
import { Video } from '../../page/basics/video/video';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import adAstraJpeg from '../media/ad_astra.jpg?format=jpg';
|
import adAstraJpeg from '../media/ad_astra.jpg?format=jpg';
|
||||||
import adAstraWebP from '../media/ad_astra.jpg?format=webp';
|
import adAstraWebP from '../media/ad_astra.jpg?format=webp';
|
||||||
import adAstraMp4 from '../media/mp4/ad_astra.mp4';
|
import adAstraMp4 from '../media/mp4/ad_astra.mp4';
|
||||||
|
|
@ -38,5 +38,5 @@ export const adAstraTimelineElement: TimelineElementParameters = {
|
||||||
This can also be found on GitHub along with the entire project.
|
This can also be found on GitHub along with the entire project.
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [new GitHub('https://github.com/schmelczerandras/ad_astra')],
|
links: [GitHub('https://github.com/schmelczerandras/ad_astra')],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Video } from '../../page/basics/video/video';
|
import { Video } from '../../page/basics/video/video';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import citySimulationMp4 from '../media/mp4/simulation.mp4';
|
import citySimulationMp4 from '../media/mp4/simulation.mp4';
|
||||||
import citySimulationPosterJpeg from '../media/simulation.jpg?format=jpg';
|
import citySimulationPosterJpeg from '../media/simulation.jpg?format=jpg';
|
||||||
import citySimulationPosterWebP from '../media/simulation.jpg?format=webp';
|
import citySimulationPosterWebP from '../media/simulation.jpg?format=webp';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import colourJpeg from '../media/color.jpg?format=jpg';
|
import colourJpeg from '../media/color.jpg?format=jpg';
|
||||||
import colourWebP from '../media/color.jpg?format=webp';
|
import colourWebP from '../media/color.jpg?format=webp';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
|
import { Preview } from '../../page/basics/preview/preview';
|
||||||
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import declaredJpeg from '../media/decla-red.png?format=jpg';
|
import declaredJpeg from '../media/decla-red.png?format=jpg';
|
||||||
import declaredWebP from '../media/decla-red.png?format=webp';
|
import declaredWebP from '../media/decla-red.png?format=webp';
|
||||||
import thesis from '../media/thesis-andras-schmelczer.pdf';
|
import bscThesis from '../media/sdf2d-andras-schmelczer.pdf';
|
||||||
|
import { GitHub, Open, Thesis } from '../shared';
|
||||||
import { Preview } from '../../page/basics/preview/preview';
|
|
||||||
import { GitHub, Thesis, Open } from '../shared';
|
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
|
||||||
|
|
||||||
export const declaredTimelineElement: TimelineElementParameters = {
|
export const declaredTimelineElement: TimelineElementParameters = {
|
||||||
title: `Multiplayer game`,
|
title: `Multiplayer game`,
|
||||||
|
|
@ -34,8 +33,8 @@ export const declaredTimelineElement: TimelineElementParameters = {
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [
|
links: [
|
||||||
new GitHub('https://github.com/schmelczerandras/decla.red'),
|
GitHub('https://github.com/schmelczerandras/decla.red'),
|
||||||
new Thesis(thesis),
|
Thesis(bscThesis),
|
||||||
new Open('https://decla.red'),
|
Open('https://decla.red'),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Video } from '../../page/basics/video/video';
|
import { Video } from '../../page/basics/video/video';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import forexPosterJpeg from '../media/forex.jpg?format=jpg';
|
import forexPosterJpeg from '../media/forex.jpg?format=jpg';
|
||||||
import forexPosterWebP from '../media/forex.jpg?format=webp';
|
import forexPosterWebP from '../media/forex.jpg?format=webp';
|
||||||
import forexMp4 from '../media/mp4/forex.mp4';
|
import forexMp4 from '../media/mp4/forex.mp4';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Video } from '../../page/basics/video/video';
|
import { Video } from '../../page/basics/video/video';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import ledPosterJpeg from '../media/led.jpg?format=jpg';
|
import ledPosterJpeg from '../media/led.jpg?format=jpg';
|
||||||
import ledPosterWebP from '../media/led.jpg?format=webp';
|
import ledPosterWebP from '../media/led.jpg?format=webp';
|
||||||
import ledMp4 from '../media/mp4/led.mp4';
|
import ledMp4 from '../media/mp4/led.mp4';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import myNotesJpeg from '../media/my-notes.png?format=jpg';
|
import myNotesJpeg from '../media/my-notes.png?format=jpg';
|
||||||
import myNotesWebP from '../media/my-notes.png?format=webp';
|
import myNotesWebP from '../media/my-notes.png?format=webp';
|
||||||
import { GitHub } from '../shared';
|
import { GitHub } from '../shared';
|
||||||
|
|
@ -20,5 +20,5 @@ export const myNotesTimelineElement: TimelineElementParameters = {
|
||||||
adventure.
|
adventure.
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [new GitHub('https://github.com/schmelczerandras/my-notes')],
|
links: [GitHub('https://github.com/schmelczerandras/my-notes')],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import processSimulatorInputJpeg from '../media/process-simulator-input.jpg?format=jpg';
|
import processSimulatorInputJpeg from '../media/process-simulator-input.jpg?format=jpg';
|
||||||
import processSimulatorInputWebP from '../media/process-simulator-input.jpg?format=webp';
|
import processSimulatorInputWebP from '../media/process-simulator-input.jpg?format=webp';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import processSimulatorJpeg from '../media/process-simulator.jpg?format=jpg';
|
import processSimulatorJpeg from '../media/process-simulator.jpg?format=jpg';
|
||||||
import processSimulatorWebP from '../media/process-simulator.jpg?format=webp';
|
import processSimulatorWebP from '../media/process-simulator.jpg?format=webp';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import photosJpeg from '../media/photos.jpg?format=jpg';
|
import photosJpeg from '../media/photos.jpg?format=jpg';
|
||||||
import photosWebP from '../media/photos.jpg?format=webp';
|
import photosWebP from '../media/photos.jpg?format=webp';
|
||||||
import { Open } from '../shared';
|
import { Open } from '../shared';
|
||||||
|
|
@ -20,5 +20,5 @@ export const photosTimelineElement: TimelineElementParameters = {
|
||||||
automatic resizing to multiple quality settings is also part of the pipeline.
|
automatic resizing to multiple quality settings is also part of the pipeline.
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [new Open('https://photo.schmelczer.dev')],
|
links: [Open('https://photo.schmelczer.dev')],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Video } from '../../page/basics/video/video';
|
import { Video } from '../../page/basics/video/video';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import platformMp4 from '../media/mp4/platform.mp4';
|
import platformMp4 from '../media/mp4/platform.mp4';
|
||||||
import platformPosterJpeg from '../media/platform.png?format=jpg';
|
import platformPosterJpeg from '../media/platform.png?format=jpg';
|
||||||
import platformPosterWebP from '../media/platform.png?format=webp';
|
import platformPosterWebP from '../media/platform.png?format=webp';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Preview } from '../../page/basics/preview/preview';
|
import { Preview } from '../../page/basics/preview/preview';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import sdf2dJpeg from '../media/sdf2d.png?format=jpg';
|
import sdf2dJpeg from '../media/sdf2d.png?format=jpg';
|
||||||
import sdf2dWebP from '../media/sdf2d.png?format=webp';
|
import sdf2dWebP from '../media/sdf2d.png?format=webp';
|
||||||
import { NPM, Open, Youtube } from '../shared';
|
import { NPM, Open, Youtube } from '../shared';
|
||||||
|
|
@ -34,8 +34,8 @@ export const sdf2dTimelineElement: TimelineElementParameters = {
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [
|
links: [
|
||||||
new NPM('https://www.npmjs.com/package/sdf-2d'),
|
NPM('https://www.npmjs.com/package/sdf-2d'),
|
||||||
new Youtube('https://www.youtube.com/watch?v=K3cEtnZUNR0'),
|
Youtube('https://www.youtube.com/watch?v=K3cEtnZUNR0'),
|
||||||
new Open('https://sdf2d.schmelczer.dev'),
|
Open('https://sdf2d.schmelczer.dev'),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Image } from '../../page/basics/image/image';
|
import { Image } from '../../page/basics/image/image';
|
||||||
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element';
|
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
|
||||||
import towersJpeg from '../media/towers.png?format=jpg';
|
import towersJpeg from '../media/towers.png?format=jpg';
|
||||||
import towersWebP from '../media/towers.png?format=webp';
|
import towersWebP from '../media/towers.png?format=webp';
|
||||||
import { GitHub, Open } from '../shared';
|
import { GitHub, Open } from '../shared';
|
||||||
|
|
@ -22,7 +22,7 @@ export const towersTimelineElement: TimelineElementParameters = {
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
links: [
|
links: [
|
||||||
new GitHub('https://github.com/schmelczerandras/life-towers/'),
|
GitHub('https://github.com/schmelczerandras/life-towers/'),
|
||||||
new Open('https://towers.schmelczer.dev'),
|
Open('https://towers.schmelczer.dev'),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
import { ImageAnchorFactory } from '../page/basics/image-anchor/image-anchor';
|
import cvIcon from '../../static/icons/cv.svg';
|
||||||
|
|
||||||
import githubIcon from '../../static/icons/github.svg';
|
import githubIcon from '../../static/icons/github.svg';
|
||||||
import openIcon from '../../static/icons/open.svg';
|
import openIcon from '../../static/icons/open.svg';
|
||||||
import cvIcon from '../../static/icons/cv.svg';
|
|
||||||
import packageIcon from '../../static/icons/package.svg';
|
import packageIcon from '../../static/icons/package.svg';
|
||||||
|
import pythonIcon from '../../static/icons/python.svg';
|
||||||
import youtubeIcon from '../../static/icons/youtube.svg';
|
import youtubeIcon from '../../static/icons/youtube.svg';
|
||||||
|
import { ImageAnchorFactory } from '../page/basics/image-anchor/image-anchor';
|
||||||
|
|
||||||
export const GitHub = ImageAnchorFactory(githubIcon, 'Open on GitHub');
|
export const GitHub = ImageAnchorFactory(githubIcon, 'Open on GitHub');
|
||||||
export const NPM = ImageAnchorFactory(packageIcon, 'Open on npm');
|
export const NPM = ImageAnchorFactory(packageIcon, 'Open on npm');
|
||||||
|
export const PyPi = ImageAnchorFactory(pythonIcon, 'Open on PyPi');
|
||||||
export const Open = ImageAnchorFactory(openIcon, 'Open in new tab');
|
export const Open = ImageAnchorFactory(openIcon, 'Open in new tab');
|
||||||
export const Thesis = ImageAnchorFactory(cvIcon, 'Download thesis');
|
export const Thesis = ImageAnchorFactory(cvIcon, 'Download thesis', {
|
||||||
|
shouldDownload: true,
|
||||||
|
});
|
||||||
export const Youtube = ImageAnchorFactory(youtubeIcon, 'Open on YouTube');
|
export const Youtube = ImageAnchorFactory(youtubeIcon, 'Open on YouTube');
|
||||||
|
|
|
||||||
7
src/helper/add-support-for-tab-navigation.ts
Normal file
7
src/helper/add-support-for-tab-navigation.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
export const addSupportForTabNavigation = () =>
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === ' ') {
|
||||||
|
(document.activeElement as HTMLElement)?.click();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -3,7 +3,9 @@ export class Random {
|
||||||
|
|
||||||
public get next(): number {
|
public get next(): number {
|
||||||
// result is in [0, 1)
|
// result is in [0, 1)
|
||||||
return ((2 ** 31 - 1) & (this.seed = Math.imul(48271, this.seed))) / 2 ** 31;
|
|
||||||
|
this.seed = Math.imul(48271, this.seed);
|
||||||
|
return ((2 ** 31 - 1) & this.seed) / 2 ** 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
public choose<T>(list: Array<T>): T {
|
public choose<T>(list: Array<T>): T {
|
||||||
|
|
|
||||||
4
src/helper/remove-unnecessary-outlines.ts
Normal file
4
src/helper/remove-unnecessary-outlines.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export const removeUnnecessaryOutlines = () =>
|
||||||
|
document.addEventListener('click', () =>
|
||||||
|
(document.activeElement as HTMLElement).blur?.()
|
||||||
|
);
|
||||||
6
src/helper/scroll-to-fragment.ts
Normal file
6
src/helper/scroll-to-fragment.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const scrollToFragment = () => {
|
||||||
|
// it might be necessary when the page takes too long to load
|
||||||
|
if (location.hash) {
|
||||||
|
document.getElementById(location.hash.slice(1))?.scrollIntoView();
|
||||||
|
}
|
||||||
|
};
|
||||||
33
src/index.ts
33
src/index.ts
|
|
@ -1,5 +1,3 @@
|
||||||
import '../static/no-change/og-image.jpg';
|
|
||||||
import '../static/no-change/robots.txt';
|
|
||||||
import '../static/no-change/404.html';
|
import '../static/no-change/404.html';
|
||||||
import '../static/no-change/favicons/android-chrome-192x192.png';
|
import '../static/no-change/favicons/android-chrome-192x192.png';
|
||||||
import '../static/no-change/favicons/android-chrome-512x512.png';
|
import '../static/no-change/favicons/android-chrome-512x512.png';
|
||||||
|
|
@ -8,32 +6,15 @@ import '../static/no-change/favicons/favicon-16x16.png';
|
||||||
import '../static/no-change/favicons/favicon-32x32.png';
|
import '../static/no-change/favicons/favicon-32x32.png';
|
||||||
import '../static/no-change/favicons/favicon.ico';
|
import '../static/no-change/favicons/favicon.ico';
|
||||||
import '../static/no-change/favicons/site.webmanifest';
|
import '../static/no-change/favicons/site.webmanifest';
|
||||||
|
import '../static/no-change/og-image.jpg';
|
||||||
|
import '../static/no-change/robots.txt';
|
||||||
|
import { create as createPortfolio } from './data/portfolio';
|
||||||
|
import { addSupportForTabNavigation } from './helper/add-support-for-tab-navigation';
|
||||||
|
import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines';
|
||||||
|
import { scrollToFragment } from './helper/scroll-to-fragment';
|
||||||
import './styles.scss';
|
import './styles.scss';
|
||||||
import { create } from './data/portfolio';
|
|
||||||
|
|
||||||
const addSupportForTabNavigation = () =>
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key === ' ') {
|
|
||||||
(document.activeElement as HTMLElement)?.click();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeUnnecessaryOutlines = () =>
|
|
||||||
document.addEventListener('click', () =>
|
|
||||||
(document.activeElement as HTMLElement).blur?.()
|
|
||||||
);
|
|
||||||
|
|
||||||
// it might be necessary when the page takes too long to load
|
|
||||||
const scrollToFragment = () => {
|
|
||||||
if (location.hash) {
|
|
||||||
document.getElementById(location.hash.slice(1))?.scrollIntoView();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addSupportForTabNavigation();
|
addSupportForTabNavigation();
|
||||||
removeUnnecessaryOutlines();
|
removeUnnecessaryOutlines();
|
||||||
|
createPortfolio().forEach((e) => e.attachToDOM(document.body));
|
||||||
create();
|
|
||||||
|
|
||||||
scrollToFragment();
|
scrollToFragment();
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,6 @@
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
padding: 0 8px 8px 8px;
|
padding: 0 8px 8px 8px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
import { createElement } from '../../../helper/create-element';
|
|
||||||
import { url } from '../../../types/url';
|
import { url } from '../../../types/url';
|
||||||
import { PageElement } from '../../page-element';
|
|
||||||
import { generate } from './image-anchor.html';
|
import { generate } from './image-anchor.html';
|
||||||
|
|
||||||
export const ImageAnchorFactory = (
|
export const ImageAnchorFactory =
|
||||||
svg: string,
|
(
|
||||||
title: string,
|
svg: string,
|
||||||
{ shouldDownload = false }: { shouldDownload?: boolean } = {}
|
title: string,
|
||||||
) =>
|
{ shouldDownload = false }: { shouldDownload?: boolean } = {}
|
||||||
class ImageAnchor extends PageElement {
|
) =>
|
||||||
public constructor(href: url) {
|
(href: url) =>
|
||||||
super(createElement(generate({ href, svg, title, shouldDownload })));
|
generate({ href, svg, title, shouldDownload });
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class Preview extends PageElement {
|
||||||
this.query('.start-button').addEventListener('click', this.loadContent.bind(this));
|
this.query('.start-button').addEventListener('click', this.loadContent.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public setParent(parent: PageElement) {
|
protected setParent(parent: PageElement) {
|
||||||
new IntersectionObserver((e) => {
|
new IntersectionObserver((e) => {
|
||||||
if (!e[0].isIntersecting) {
|
if (!e[0].isIntersecting) {
|
||||||
this.unloadContent();
|
this.unloadContent();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { PageElement } from '../page-element';
|
|
||||||
|
|
||||||
export class Body extends PageElement {
|
|
||||||
constructor(...children: Array<PageElement>) {
|
|
||||||
super(document.body, children);
|
|
||||||
children.forEach((c) => this.attachElement(c));
|
|
||||||
this.setParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import { html } from '../../types/html';
|
|
||||||
import './content.scss';
|
|
||||||
|
|
||||||
export const generate = (): html => `
|
|
||||||
<div class="content"></div>
|
|
||||||
`;
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
@use '../../style/mixins' as *;
|
|
||||||
|
|
||||||
.content {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { createElement } from '../../helper/create-element';
|
|
||||||
|
|
||||||
import { generate } from './content.html';
|
|
||||||
import { PageElement } from '../page-element';
|
|
||||||
|
|
||||||
export class PageContent extends PageElement {
|
|
||||||
public constructor(content: Array<string>) {
|
|
||||||
super(createElement(generate()));
|
|
||||||
content.map((t) => {
|
|
||||||
const p = createElement(`<p>${t}</p>`);
|
|
||||||
this.htmlRoot.appendChild(p);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
import { html } from '../../types/html';
|
import { html } from '../../types/html';
|
||||||
import './header.scss';
|
import './header.scss';
|
||||||
|
|
||||||
export const generate = (name: string): html => `
|
export const generate = ({
|
||||||
|
name,
|
||||||
|
about,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
about: Array<string>;
|
||||||
|
}): html => `
|
||||||
<section id="about">
|
<section id="about">
|
||||||
<div class="picture"></div>
|
<div class="picture"></div>
|
||||||
<div class="placeholder"></div>
|
<div class="placeholder"></div>
|
||||||
<h1>${name}</h1>
|
<h1>${name}</h1>
|
||||||
|
${about.map((t) => `<p>${t}</p>`).join('\n')}
|
||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
import { createElement } from '../../helper/create-element';
|
import { createElement } from '../../helper/create-element';
|
||||||
import { Image } from '../basics/image/image';
|
import { Image } from '../basics/image/image';
|
||||||
import { PageContent } from '../content/content';
|
|
||||||
import { PageElement } from '../page-element';
|
import { PageElement } from '../page-element';
|
||||||
import { PageThemeSwitcher } from '../theme-switcher/theme-switcher';
|
import { PageThemeSwitcher } from '../theme-switcher/theme-switcher';
|
||||||
import { generate } from './header.html';
|
import { generate } from './header.html';
|
||||||
|
|
||||||
export class PageHeader extends PageElement {
|
export class PageHeader extends PageElement {
|
||||||
public constructor(header: { name: string; photo: Image; about: Array<string> }) {
|
public constructor({
|
||||||
super(createElement(generate(header.name)));
|
name,
|
||||||
|
photo,
|
||||||
|
about,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
photo: Image;
|
||||||
|
about: Array<string>;
|
||||||
|
}) {
|
||||||
|
super(createElement(generate({ name, about })));
|
||||||
|
|
||||||
this.attachElementByReplacing('.picture', header.photo);
|
this.attachElementByReplacing('.picture', photo);
|
||||||
this.attachElement(new PageContent(header.about));
|
|
||||||
this.attachElement(new PageThemeSwitcher());
|
this.attachElement(new PageThemeSwitcher());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { createElement } from '../../helper/create-element';
|
||||||
import { PageElement } from '../page-element';
|
import { PageElement } from '../page-element';
|
||||||
import { generate } from './image-viewer.html';
|
import { generate } from './image-viewer.html';
|
||||||
import { createElement } from '../../helper/create-element';
|
|
||||||
|
|
||||||
export class PageImageViewer extends PageElement {
|
export class PageImageViewer extends PageElement {
|
||||||
public constructor() {
|
public constructor() {
|
||||||
|
|
@ -9,7 +9,7 @@ export class PageImageViewer extends PageElement {
|
||||||
document.body.addEventListener('click', (event: MouseEvent) => {
|
document.body.addEventListener('click', (event: MouseEvent) => {
|
||||||
if (
|
if (
|
||||||
event.target instanceof HTMLImageElement &&
|
event.target instanceof HTMLImageElement &&
|
||||||
!event.target.attributes['image-viewer-ignore']
|
!(event.target.attributes['image-viewer-ignore'] as boolean | undefined)
|
||||||
) {
|
) {
|
||||||
this.showImage(event.target);
|
this.showImage(event.target);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,11 @@ export abstract class PageElement {
|
||||||
protected children: Array<PageElement> = []
|
protected children: Array<PageElement> = []
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public attachToDOM(target: HTMLElement) {
|
||||||
|
target.appendChild(this.htmlRoot);
|
||||||
|
this.setParent(null);
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
protected setParent(parent?: PageElement | null): void {
|
protected setParent(parent?: PageElement | null): void {
|
||||||
this.children.forEach((c) => c.setParent(this));
|
this.children.forEach((c) => c.setParent(this));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { html } from '../../../types/html';
|
||||||
|
import { Image } from '../../basics/image/image';
|
||||||
|
import { Preview } from '../../basics/preview/preview';
|
||||||
|
import { Video } from '../../basics/video/video';
|
||||||
|
|
||||||
|
export interface TimelineElementParameters {
|
||||||
|
date: string;
|
||||||
|
figure: Image | Video | Preview;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
more: Array<string>;
|
||||||
|
links: Array<html>;
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import info from '../../../../static/icons/info.svg';
|
import info from '../../../../static/icons/info.svg';
|
||||||
import { titleToFragment } from '../../../helper/title-to-fragment';
|
import { titleToFragment } from '../../../helper/title-to-fragment';
|
||||||
import { html } from '../../../types/html';
|
import { html } from '../../../types/html';
|
||||||
import { TimelineElementParameters } from './timeline-element';
|
import { TimelineElementParameters } from './timeline-element-parameters';
|
||||||
import './timeline-element.scss';
|
import './timeline-element.scss';
|
||||||
|
|
||||||
export const generate = (
|
export const generate = (
|
||||||
{ date, title, description, more }: TimelineElementParameters,
|
{ date, title, description, more, links }: TimelineElementParameters,
|
||||||
showMore: string
|
showMore: string
|
||||||
): html => `
|
): html => `
|
||||||
<section id="${titleToFragment(title)}" class="timeline-element">
|
<section id="${titleToFragment(title)}" class="timeline-element">
|
||||||
|
|
@ -22,7 +22,14 @@ export const generate = (
|
||||||
|
|
||||||
<p class="description">${description}</p>
|
<p class="description">${description}</p>
|
||||||
|
|
||||||
${more ? '<div class="more"></div>' : ''}
|
${
|
||||||
|
more
|
||||||
|
? `
|
||||||
|
<div class="more">
|
||||||
|
${more.map((t) => `<p>${t}</p>`).join('\n')}
|
||||||
|
</div>`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
${
|
${
|
||||||
|
|
@ -32,6 +39,7 @@ export const generate = (
|
||||||
<p>${showMore}</p>
|
<p>${showMore}</p>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
${links.join('')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
text-align: center;
|
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
@ -108,27 +107,31 @@
|
||||||
margin-top: var(--small-margin);
|
margin-top: var(--small-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 > a {
|
h2 {
|
||||||
@include sub-title-font();
|
text-align: center;
|
||||||
text-decoration: none;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:before {
|
> a {
|
||||||
content: '#';
|
@include sub-title-font();
|
||||||
position: absolute;
|
text-decoration: none;
|
||||||
left: -0.5ch;
|
position: relative;
|
||||||
top: 0;
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-100%);
|
|
||||||
transition: opacity var(--transition-time);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover:before {
|
&:before {
|
||||||
opacity: 0.5;
|
content: '#';
|
||||||
|
position: absolute;
|
||||||
|
left: -0.5ch;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: opacity var(--transition-time);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:before {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > p {
|
.description {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +141,7 @@
|
||||||
height: 0;
|
height: 0;
|
||||||
transition: height var(--transition-time);
|
transition: height var(--transition-time);
|
||||||
|
|
||||||
.content p {
|
> p {
|
||||||
margin-top: var(--line-height);
|
margin-top: var(--line-height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,8 @@
|
||||||
import { createElement } from '../../../helper/create-element';
|
import { createElement } from '../../../helper/create-element';
|
||||||
import { Image } from '../../basics/image/image';
|
|
||||||
import { Preview } from '../../basics/preview/preview';
|
|
||||||
import { Video } from '../../basics/video/video';
|
|
||||||
import { PageContent } from '../../content/content';
|
|
||||||
import { PageElement } from '../../page-element';
|
import { PageElement } from '../../page-element';
|
||||||
|
import { TimelineElementParameters } from './timeline-element-parameters';
|
||||||
import { generate } from './timeline-element.html';
|
import { generate } from './timeline-element.html';
|
||||||
|
|
||||||
export interface TimelineElementParameters {
|
|
||||||
date: string;
|
|
||||||
figure: Image | Video | Preview;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
more: Array<string>;
|
|
||||||
links: Array<PageElement>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PageTimelineElement extends PageElement {
|
export class PageTimelineElement extends PageElement {
|
||||||
private isOpen = false;
|
private isOpen = false;
|
||||||
private more: HTMLElement;
|
private more: HTMLElement;
|
||||||
|
|
@ -25,17 +13,12 @@ export class PageTimelineElement extends PageElement {
|
||||||
private readonly showLess: string
|
private readonly showLess: string
|
||||||
) {
|
) {
|
||||||
super(createElement(generate(timelineElement, showMore)));
|
super(createElement(generate(timelineElement, showMore)));
|
||||||
const content = new PageContent(timelineElement.more);
|
|
||||||
this.children = [content];
|
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.more = this.query('.more');
|
this.more = this.query('.more');
|
||||||
this.more.appendChild(content.htmlRoot);
|
|
||||||
addEventListener('resize', this.handleResize.bind(this));
|
addEventListener('resize', this.handleResize.bind(this));
|
||||||
|
|
||||||
this.query('.info-button').addEventListener('click', this.toggleOpen.bind(this));
|
this.query('.info-button').addEventListener('click', this.toggleOpen.bind(this));
|
||||||
this.attachElementByReplacing('.figure', timelineElement.figure);
|
this.attachElementByReplacing('.figure', timelineElement.figure);
|
||||||
timelineElement.links.forEach((l) => this.attachElementAsChildOf('.buttons', l));
|
|
||||||
|
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import { createElement } from '../../helper/create-element';
|
import { createElement } from '../../helper/create-element';
|
||||||
import { PageElement } from '../page-element';
|
import { PageElement } from '../page-element';
|
||||||
import {
|
import { PageTimelineElement } from './timeline-element/timeline-element';
|
||||||
PageTimelineElement,
|
import { TimelineElementParameters } from './timeline-element/timeline-element-parameters';
|
||||||
TimelineElementParameters,
|
|
||||||
} from './timeline-element/timeline-element';
|
|
||||||
import { generate } from './timeline.html';
|
import { generate } from './timeline.html';
|
||||||
|
|
||||||
export class PageTimeline extends PageElement {
|
export class PageTimeline extends PageElement {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue