Refactor and fix

This commit is contained in:
schmelczerandras 2020-11-22 22:43:28 +01:00
parent 91d92f7f48
commit 4be519f052
22 changed files with 118 additions and 113 deletions

View file

@ -1,2 +1,3 @@
export const sum = (list: ArrayLike<number>): number => export const sum = (list: ArrayLike<number>): number =>
// @ts-ignore
Array.prototype.reduce.call(list, (a: number, sum: number) => a + sum, 0); Array.prototype.reduce.call(list, (a: number, sum: number) => a + sum, 0);

View file

@ -10,10 +10,12 @@
svg { svg {
stroke: var(--normal-text-color); stroke: var(--normal-text-color);
transition: stroke var(--transition-time);
} }
} }
p { p {
@include main-font();
padding-bottom: var(--small-margin); padding-bottom: var(--small-margin);
font-size: 0.9rem; font-size: 0.9rem;
font-style: italic; font-style: italic;

View file

@ -31,7 +31,7 @@ export class Image extends PageElement {
image.images image.images
.slice(0, -1) .slice(0, -1)
.map(d => `(max-width: ${d.width / Image.imageScreenRatio}px) ${d.width}px,`) .map(d => `(max-width: ${d.width / Image.imageScreenRatio}px) ${d.width}px,`)
.join('\n') + `\n${last(image.images).width}px` .join('\n') + `\n${last(image.images)!.width}px`
); );
} }
} }

View file

@ -32,10 +32,15 @@
} }
} }
.loading, .loading {
.loading > svg {
@include square(var(--large-icon-size)); @include square(var(--large-icon-size));
@include absolute-center; @include absolute-center;
visibility: hidden;
& > svg {
@include square(var(--large-icon-size));
@include absolute-center;
}
} }
iframe { iframe {
@ -52,9 +57,6 @@
.load-button { .load-button {
visibility: hidden; visibility: hidden;
} }
}
&.waiting {
.loading { .loading {
visibility: visible; visibility: visible;
} }

View file

@ -3,7 +3,6 @@ import { createElement } from '../../../helper/create-element';
import { generate } from './preview.html'; import { generate } from './preview.html';
import { Image } from '../image/image'; import { Image } from '../image/image';
import { ResponsiveImage } from '../../../types/responsive-image'; import { ResponsiveImage } from '../../../types/responsive-image';
import { OnLoadEvent } from '../../../events/concrete-events/on-load-event';
export class Preview extends PageElement { export class Preview extends PageElement {
public constructor( public constructor(
@ -18,14 +17,14 @@ export class Preview extends PageElement {
this.query('.load-button').addEventListener('click', this.loadContent.bind(this)); this.query('.load-button').addEventListener('click', this.loadContent.bind(this));
} }
public handleOnLoadEvent(event: OnLoadEvent): OnLoadEvent { public setParent(parent: PageElement) {
new IntersectionObserver(e => { new IntersectionObserver(e => {
if (!e[0].isIntersecting) { if (!e[0].isIntersecting) {
this.unloadContent(); this.unloadContent();
} }
}).observe(this.htmlRoot.parentElement); }).observe(this.htmlRoot.parentElement!);
return event; super.setParent(parent);
} }
public loadContent() { public loadContent() {

View file

@ -2,5 +2,5 @@ import './text.scss';
import { html } from '../../../types/html'; import { html } from '../../../types/html';
export const generate = (text: string): html => ` export const generate = (text: string): html => `
<p class="primitive-text">${text}</p> <p class="text">${text}</p>
`; `;

View file

@ -1,3 +1,6 @@
.primitive-text { @use '../../../style/mixins' as *;
.text {
@include main-font();
text-align: left; text-align: left;
} }

View file

@ -9,16 +9,16 @@ export const generate = ({
mp4, mp4,
container, container,
}: { }: {
poster: url; poster?: url;
options: string; options?: string;
webm: url; webm: url;
mp4: url; mp4: url;
container: boolean; container?: boolean;
}): html => ` }): html => `
${container ? `<div class="figure-container">` : ''} ${container === undefined || container ? `<div class="figure-container">` : ''}
<video loading="lazy" ${options} ${poster ? `poster="${poster}` : ''}" > <video loading="lazy" ${options} ${poster ? `poster="${poster}` : ''}" >
<source src="${webm}" type="video/webm"/> <source src="${webm}" type="video/webm"/>
<source src="${mp4}" type="video/mp4"/> <source src="${mp4}" type="video/mp4"/>
</video> </video>
${container ? `</div>` : ''} ${container === undefined || container ? `</div>` : ''}
`; `;

View file

@ -4,13 +4,13 @@ import { generate } from './video.html';
import { url } from '../../../types/url'; import { url } from '../../../types/url';
export class Video extends PageElement { export class Video extends PageElement {
public constructor( public constructor(options: {
poster: url, poster?: url;
mp4: url, mp4: url;
webm: url, webm: url;
options?: string, options?: string;
container = true container?: boolean;
) { }) {
super(createElement(generate({ poster, mp4, webm, options, container }))); super(createElement(generate(options)));
} }
} }

View file

@ -11,7 +11,7 @@ export const generate = ({
lastEditText, lastEditText,
lastEdit, lastEdit,
}: Footer): html => ` }: Footer): html => `
<footer id="page-footer"> <footer id="footer">
<h2>${title}</h2> <h2>${title}</h2>
<ul> <ul>
${curriculaVitae ${curriculaVitae

View file

@ -1,6 +1,6 @@
@use '../../style/mixins' as *; @use '../../style/mixins' as *;
footer#page-footer { #footer {
text-align: center; text-align: center;
margin-top: var(--large-margin); margin-top: var(--large-margin);
@ -30,7 +30,8 @@ footer#page-footer {
img, img,
svg { svg {
@include max-square(var(--icon-size)); max-width: var(--icon-size);
max-height: var(--icon-size);
margin-right: calc(var(--small-margin) / 2); margin-right: calc(var(--small-margin) / 2);
stroke: var(--normal-text-color); stroke: var(--normal-text-color);
} }

View file

@ -1,11 +1,17 @@
@use '../../style/mixins' as *; @use '../../style/mixins' as *;
section#about { #about {
@include card-base(); text-align: center;
box-shadow: var(--shadow);
padding: var(--normal-margin); padding: var(--normal-margin);
background-color: var(--accent-color); background-color: var(--accent-color);
font-size: 0; font-size: 0;
::selection {
background-color: var(--very-light-text-color);
color: var(--accent-color);
}
$img-size: 125px; $img-size: 125px;
h1, h1,
img, img,

View file

@ -5,7 +5,7 @@ import { html } from '../../types/html';
export const generate = (): html => ` export const generate = (): html => `
<section id="image-viewer"> <section id="image-viewer">
<div id="container"></div> <img image-viewer-ignore />
<div tabindex="0" id="cancel">${cancel}</div> <div tabindex="0" id="cancel">${cancel}</div>
</section> </section>
`; `;

View file

@ -1,20 +1,18 @@
@use '../../style/mixins' as *; @use '../../style/mixins' as *;
section#image-viewer { #image-viewer {
@include center-children(); @include center-children();
display: none; @include blurred-background();
visibility: hidden;
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0;
z-index: 2;
background-color: rgba(0, 0, 0, 0.85);
#container > * { img {
width: auto; @include square(auto);
height: auto;
@include on-large-screen { @include on-large-screen {
max-width: 80vw; max-width: 80vw;
@ -22,17 +20,20 @@ section#image-viewer {
} }
@include on-small-screen { @include on-small-screen {
max-width: 95vw; max-width: 92.5vw;
max-height: 95vh; max-height: 92.5vh;
} }
} }
#cancel { #cancel {
@include image-button(var(--large-icon-size));
@include square(calc(var(--large-icon-size) + var(--normal-margin) * 2)); @include square(calc(var(--large-icon-size) + var(--normal-margin) * 2));
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
@include image-button(var(--large-icon-size)); svg {
stroke: var(--normal-text-color);
}
} }
} }

View file

@ -1,48 +1,36 @@
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'; import { createElement } from '../../helper/create-element';
import { OnLoadEvent } from '../../events/concrete-events/on-load-event';
import { OptionalEvent } from '../../events/optional-event';
export class PageImageViewer extends PageElement { export class PageImageViewer extends PageElement {
public constructor() { public constructor() {
super(createElement(generate())); super(createElement(generate()));
this.htmlRoot.onclick = () => PageImageViewer.hide(this.htmlRoot);
document.body.addEventListener('click', (event: MouseEvent) => {
if (
event.target instanceof HTMLImageElement &&
!event.target.attributes['image-viewer-ignore']
) {
this.showImage(event.target);
}
});
document.body.addEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === 'Escape') {
this.hideImage();
}
});
this.htmlRoot.addEventListener('click', this.hideImage.bind(this));
} }
public handleOnLoadEvent(event: OnLoadEvent): OptionalEvent { private showImage(source: HTMLImageElement) {
document.body.addEventListener('keydown', this.handleKeydown.bind(this)); const image = this.query('img') as HTMLImageElement;
image.src = source.src;
const media = Array.prototype.slice.call(document.querySelectorAll('img')); this.htmlRoot.style.visibility = 'visible';
media
.filter((e: HTMLElement) => !e.attributes['image-viewer-ignore'])
.forEach((e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this)));
return super.handleOnLoadEvent(event);
} }
private handleClick(event: Event) { private hideImage() {
const container = this.query('#container'); this.htmlRoot.style.visibility = 'hidden';
container.firstElementChild?.remove();
const element: HTMLImageElement = new Image();
element.src = (event.target as HTMLImageElement).src;
container.appendChild(element);
PageImageViewer.show(this.htmlRoot);
}
private handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
PageImageViewer.hide(this.htmlRoot);
}
}
private static show(e: HTMLElement) {
e.style.display = 'flex';
}
private static hide(e: HTMLElement) {
e.style.display = 'none';
} }
} }

View file

@ -7,9 +7,6 @@ import {
turnOnLightMode, turnOnLightMode,
} from '../../style/dark-mode/dark-mode'; } from '../../style/dark-mode/dark-mode';
import { turnOffAnimations, turnOnAnimations } from '../../style/animations/animations'; import { turnOffAnimations, turnOnAnimations } from '../../style/animations/animations';
import { OnLoadEvent } from '../../events/concrete-events/on-load-event';
import { OptionalEvent } from '../../events/optional-event';
import { OnPageThemeChangedEvent } from '../../events/concrete-events/on-page-theme-changed-event';
export class PageThemeSwitcher extends PageElement { export class PageThemeSwitcher extends PageElement {
private static readonly localStorageKey = 'dark-mode'; private static readonly localStorageKey = 'dark-mode';
@ -28,12 +25,10 @@ export class PageThemeSwitcher extends PageElement {
} else { } else {
turnOnLightMode(); turnOnLightMode();
} }
this.htmlRoot.onchange = this.handleThemeChange.bind(this);
}
public handleOnLoadEvent(event: OnLoadEvent): OptionalEvent { this.htmlRoot.onchange = this.handleThemeChange.bind(this);
this.handleThemeChange(); this.handleThemeChange();
return super.handleOnLoadEvent(event);
} }
private handleThemeChange() { private handleThemeChange() {
@ -44,7 +39,6 @@ export class PageThemeSwitcher extends PageElement {
turnOnLightMode(); turnOnLightMode();
} }
this.eventBroadcaster.broadcastEvent(new OnPageThemeChangedEvent(isDark));
PageThemeSwitcher.saveToLocalStorage(isDark); PageThemeSwitcher.saveToLocalStorage(isDark);
} }
@ -57,7 +51,7 @@ export class PageThemeSwitcher extends PageElement {
private static loadFromLocalStorage(): boolean | null { private static loadFromLocalStorage(): boolean | null {
try { try {
return JSON.parse(localStorage?.getItem(PageThemeSwitcher.localStorageKey)); return JSON.parse(localStorage!.getItem(PageThemeSwitcher.localStorageKey)!);
} catch { } catch {
return null; return null;
} }

View file

@ -16,7 +16,7 @@
} }
} }
section.timeline-element { .timeline-element {
display: flex; display: flex;
width: var(--body-width); width: var(--body-width);
margin: auto; margin: auto;
@ -85,14 +85,14 @@ section.timeline-element {
} }
.card { .card {
@include card-base(); text-align: center;
box-shadow: var(--shadow);
border-radius: var(--border-radius); border-radius: var(--border-radius);
background-color: var(--blurred-card-color); background-color: var(--blurred-card-color);
backdrop-filter: blur(var(--blur-radius)); transition: background-color var(--transition-time);
@supports not (backdrop-filter: blur(var(--blur-radius))) {
background-color: var(--card-color); @include blurred-background();
}
img, img,
video, video,
@ -131,12 +131,15 @@ section.timeline-element {
display: flex; display: flex;
justify-content: center; justify-content: center;
border-top: $border-width solid var(--normal-text-color); border-top: $border-width solid var(--normal-text-color);
transition: border-color var(--transition-time);
margin: 0; margin: 0;
padding: 0; padding: 0;
margin-top: var(--small-margin); margin-top: var(--small-margin);
.info-button { .info-button {
@include image-button(var(--icon-size)); @include image-button(var(--icon-size));
@include main-font();
.svgContainer { .svgContainer {
position: relative; position: relative;
@ -145,10 +148,12 @@ section.timeline-element {
svg { svg {
stroke: var(--normal-text-color); stroke: var(--normal-text-color);
transition: stroke var(--transition-time);
} }
} }
p { p {
@include main-font();
padding-bottom: var(--small-margin); padding-bottom: var(--small-margin);
font-size: 0.9rem; font-size: 0.9rem;
font-style: italic; font-style: italic;
@ -162,6 +167,7 @@ section.timeline-element {
padding-top: var(--small-margin); padding-top: var(--small-margin);
&:not(:last-child) { &:not(:last-child) {
border-right: $border-width solid var(--normal-text-color); border-right: $border-width solid var(--normal-text-color);
transition: border-color var(--transition-time);
} }
} }
} }

View file

@ -6,7 +6,7 @@ import { createElement } from '../../../helper/create-element';
export class PageTimelineElement extends PageElement { export class PageTimelineElement extends PageElement {
private isOpen: boolean; private isOpen: boolean;
private more: HTMLElement; private more?: HTMLElement;
private showMore: string; private showMore: string;
private showLess: string; private showLess: string;
@ -22,7 +22,7 @@ export class PageTimelineElement extends PageElement {
super(root); super(root);
this.children = [content]; this.children = [content];
this.isOpen = false; this.isOpen = false;
this.more = root.querySelector('.more'); this.more = this.query('.more');
this.more.appendChild(content.htmlRoot); this.more.appendChild(content.htmlRoot);
addEventListener('resize', this.handleResize.bind(this)); addEventListener('resize', this.handleResize.bind(this));
@ -35,6 +35,7 @@ export class PageTimelineElement extends PageElement {
this.showMore = showMore; this.showMore = showMore;
this.showLess = showLess; this.showLess = showLess;
this.isOpen = false;
} }
private toggleOpen() { private toggleOpen() {
@ -50,17 +51,17 @@ export class PageTimelineElement extends PageElement {
} }
private openMore() { private openMore() {
const deltaHeight = this.more.scrollHeight; const deltaHeight = this.more!.scrollHeight;
this.more.style.height = `${deltaHeight.toString()}px`; this.more!.style.height = `${deltaHeight.toString()}px`;
} }
private closeMore() { private closeMore() {
this.more.style.height = '0'; this.more!.style.height = '0';
} }
private handleResize() { private handleResize() {
if (this.isOpen) { if (this.isOpen) {
this.more.style.height = 'auto'; this.more!.style.height = 'auto';
this.openMore.bind(this); this.openMore.bind(this);
} }
} }

View file

@ -1,7 +1,7 @@
@use '../../style/mixins' as *; @use '../../style/mixins' as *;
@include on-large-screen { @include on-large-screen {
div#timeline > :first-child { #timeline > :first-child {
margin-top: var(--large-margin); margin-top: var(--large-margin);
} }
} }

View file

@ -1,5 +1,5 @@
export const turnOnAnimations = () => export const turnOnAnimations = () =>
document.body.parentElement.setAttribute('animations', 'on'); document.documentElement.setAttribute('animations', 'on');
export const turnOffAnimations = () => export const turnOffAnimations = () =>
document.body.parentElement.setAttribute('animations', 'off'); document.documentElement.setAttribute('animations', 'off');

View file

@ -2,7 +2,7 @@ export const isSystemLevelDarkModeEnabled = (): boolean =>
matchMedia && matchMedia('(prefers-color-scheme: dark)').matches; matchMedia && matchMedia('(prefers-color-scheme: dark)').matches;
export const turnOnDarkMode = () => export const turnOnDarkMode = () =>
document.body.parentElement.setAttribute('theme', 'dark'); document.documentElement.setAttribute('theme', 'dark');
export const turnOnLightMode = () => export const turnOnLightMode = () =>
document.body.parentElement.setAttribute('theme', 'light'); document.documentElement.setAttribute('theme', 'light');

View file

@ -43,11 +43,11 @@ $breakpoint-width: 925px !default;
transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%);
} }
@mixin card-base() { @mixin blurred-background() {
text-align: center; backdrop-filter: blur(var(--blur-radius));
box-shadow: var(--shadow); @supports not (backdrop-filter: blur(var(--blur-radius))) {
z-index: 1; background-color: var(--card-color);
width: 100%; }
} }
@mixin square($size) { @mixin square($size) {
@ -55,16 +55,12 @@ $breakpoint-width: 925px !default;
height: $size; height: $size;
} }
@mixin max-square($size) {
max-width: $size;
max-height: $size;
}
@mixin title-font() { @mixin title-font() {
font: 400 3rem 'Comfortaa', serif; font: 400 3rem 'Comfortaa', serif;
font-style: normal; font-style: normal;
color: var(--normal-text-color); color: var(--normal-text-color);
line-height: 1; line-height: 1;
transition: color var(--transition-time);
@include on-small-screen { @include on-small-screen {
font-size: 3rem; font-size: 3rem;
@ -76,18 +72,23 @@ $breakpoint-width: 925px !default;
font: 400 1.75rem 'Comfortaa', serif; font: 400 1.75rem 'Comfortaa', serif;
color: var(--normal-text-color); color: var(--normal-text-color);
font-style: normal; font-style: normal;
hyphens: auto;
transition: color var(--transition-time);
} }
@mixin main-font() { @mixin main-font() {
font: 400 1.1rem 'Open Sans', sans-serif; font: 400 1.1rem 'Open Sans', sans-serif;
color: var(--normal-text-color); color: var(--normal-text-color);
line-height: 1.8; line-height: 1.8;
hyphens: auto;
transition: color var(--transition-time);
} }
@mixin special-text-font() { @mixin special-text-font() {
font: 400 1rem 'Open Sans', sans-serif; font: 400 1rem 'Open Sans', sans-serif;
color: var(--special-text-color); color: var(--special-text-color);
font-style: italic; font-style: italic;
transition: color var(--transition-time);
} }
@mixin link { @mixin link {