Refactor components to simplify them

This commit is contained in:
Andras Schmelczer 2022-09-21 14:40:44 +02:00
parent 3cf5b14913
commit 077ed9d3bf
No known key found for this signature in database
GPG key ID: 0EA1BC97D0AB076E
36 changed files with 202 additions and 216 deletions

View file

@ -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(),
); ];

View file

@ -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')],
}; };

View file

@ -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';

View file

@ -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';

View file

@ -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'),
], ],
}; };

View file

@ -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';

View file

@ -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';

View file

@ -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')],
}; };

View file

@ -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';

View file

@ -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';

View file

@ -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')],
}; };

View file

@ -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';

View file

@ -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'),
], ],
}; };

View file

@ -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'),
], ],
}; };

View file

@ -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');

View file

@ -0,0 +1,7 @@
export const addSupportForTabNavigation = () =>
document.addEventListener('keydown', (e) => {
if (e.key === ' ') {
(document.activeElement as HTMLElement)?.click();
e.preventDefault();
}
});

View file

@ -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 {

View file

@ -0,0 +1,4 @@
export const removeUnnecessaryOutlines = () =>
document.addEventListener('click', () =>
(document.activeElement as HTMLElement).blur?.()
);

View 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();
}
};

View file

@ -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();

View file

@ -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;
} }
} }

View file

@ -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 });
}
};

View file

@ -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();

View file

@ -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();
}
}

View file

@ -1,6 +0,0 @@
import { html } from '../../types/html';
import './content.scss';
export const generate = (): html => `
<div class="content"></div>
`;

View file

@ -1,5 +0,0 @@
@use '../../style/mixins' as *;
.content {
text-align: left;
}

View file

@ -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);
});
}
}

View file

@ -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>
`; `;

View file

@ -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());
} }
} }

View file

@ -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);
} }

View file

@ -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));

View file

@ -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>;
}

View file

@ -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>

View file

@ -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);
} }
} }

View file

@ -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;
} }

View file

@ -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 {