Remove "framework"

This commit is contained in:
schmelczerandras 2020-11-17 20:52:59 +01:00
parent b45bdb18a0
commit dc86d30eb2
72 changed files with 359 additions and 333 deletions

View file

@ -1,11 +1,11 @@
import { Header } from '../../model/portfolio';
import { html } from '../../framework/model/misc';
import { Header } from '../../types/portfolio';
import './about.scss';
import { html } from '../../types/html';
export const generate = ({ name, picture }: Header): html => `
export const generate = ({ name }: Header): html => `
<section id="about">
${picture.toHTML()}
<div class="picture"></div>
<div class="placeholder"></div>
<h1>${name}</h1>
</section>

View file

@ -1,16 +1,16 @@
import { PageContent } from '../content/content';
import { Header } from '../../model/portfolio';
import { Header } from '../../types/portfolio';
import { generate } from './about.html';
import { createElement } from '../../framework/helper/create-element';
import { ContainerPage } from '../../framework/container-page';
import { createElement } from '../../helper/create-element';
import { PageThemeSwitcher } from '../theme-switcher/theme-switcher';
import { PageElement } from '../page-element';
export class PageHeader extends ContainerPage {
export class PageHeader extends PageElement {
public constructor(header: Header) {
super(createElement(generate(header)), [
new PageContent(header.about),
new PageThemeSwitcher(),
]);
super(createElement(generate(header)));
this.attachElementByReplacing('.picture', header.picture);
this.attachElement(new PageContent(header.about));
this.attachElement(new PageThemeSwitcher());
}
}

View file

@ -1,6 +1,5 @@
import { html } from '../../framework/model/misc';
import './background.scss';
import { html } from '../../types/html';
export const generate = (): html => `
<canvas id="background"></canvas>

View file

@ -1,16 +1,16 @@
import { PageElement } from '../../framework/page-element';
import { PageElement } from '../page-element';
import { Blob } from './blob';
import { generate } from './background.html';
import { Animation } from './animation';
import { Vec3 } from './vec3';
import { Vec2 } from './vec2';
import { createElement } from '../../framework/helper/create-element';
import { sum } from '../../framework/helper/sum';
import { getHeight } from '../../framework/helper/get-height';
import { OnLoadEvent } from '../../framework/events/concrete-events/on-load-event';
import { OnBodyDimensionsChangedEvent } from '../../framework/events/concrete-events/on-body-dimensions-changed-event';
import { OnPageThemeChangedEvent } from '../../framework/events/concrete-events/on-page-theme-changed-event';
import { OptionalEvent } from '../../framework/events/optional-event';
import { createElement } from '../../helper/create-element';
import { sum } from '../../helper/sum';
import { getHeight } from '../../helper/get-height';
import { OnLoadEvent } from '../../events/concrete-events/on-load-event';
import { OptionalEvent } from '../../events/optional-event';
import { OnBodyDimensionsChangedEvent } from '../../events/concrete-events/on-body-dimensions-changed-event';
import { OnPageThemeChangedEvent } from '../../events/concrete-events/on-page-theme-changed-event';
export class PageBackground extends PageElement {
public static readonly BLOB_SPACING = 325;
@ -34,7 +34,7 @@ export class PageBackground extends PageElement {
private readonly end: PageElement
) {
super(createElement(generate()));
this.canvas = this.element as HTMLCanvasElement;
this.canvas = this.htmlRoot as HTMLCanvasElement;
this.ctx = this.canvas.getContext('2d');
}
@ -89,7 +89,7 @@ export class PageBackground extends PageElement {
}
private resizeBackground(heightChange?: number) {
const targetWidth = this.parent.element.clientWidth;
const targetWidth = this.parent.htmlRoot.clientWidth;
const siblings: Array<HTMLElement> = this.getSiblings();
let targetHeight = sum(siblings.map(getHeight));
@ -116,11 +116,10 @@ export class PageBackground extends PageElement {
offset *
q
);
const topOffset = variableOffset(getHeight(this.start.element), 1);
const topOffset = variableOffset(getHeight(this.start.htmlRoot), 1);
const topLeft = this.convertFrom2Dto3D(new Vec2(0, topOffset), blob.z);
const bottomOffset = variableOffset(getHeight(this.end.element), 0.2);
const bottomOffset = variableOffset(getHeight(this.end.htmlRoot), 0.2);
const bottomRight = this.convertFrom2Dto3D(
new Vec2(this.canvas.width, this.canvas.height - bottomOffset),
blob.z,
@ -134,7 +133,7 @@ export class PageBackground extends PageElement {
}
private getSiblings(): Array<HTMLElement> {
return [this.start, ...this.inBetween, this.end].map(e => e.element);
return [this.start, ...this.inBetween, this.end].map(e => e.htmlRoot);
}
private redraw(timestamp: DOMHighResTimeStamp) {
@ -144,7 +143,7 @@ export class PageBackground extends PageElement {
this.backgroundSize.step(deltaTime);
this.blobs.forEach(b => b.step(deltaTime));
this.scrollPosition = this.parent.element.scrollTop;
this.scrollPosition = this.parent.htmlRoot.scrollTop;
this.blobs.sort((b1, b2) => b2.z - b1.z);

View file

@ -1,7 +1,7 @@
import { Vec2 } from './vec2';
import { Vec3 } from './vec3';
import { mixColors } from '../../framework/helper/mix-colors';
import { Random } from '../../framework/helper/random';
import { mixColors } from '../../helper/mix-colors';
import { Random } from '../../helper/random';
import { Animation } from './animation';
import { PageBackground } from './background';

View file

@ -0,0 +1,10 @@
import './anchor.scss';
import { html } from '../../../types/html';
export const generate = ({ href, text }: { href: string; text: string }): html => `
<a class="primitive-anchor"
href="${href}"
target="_blank"
>${text}</a>
<br/>
`;

View file

@ -0,0 +1,3 @@
.primitive-anchor {
margin-top: var(--line-height);
}

View file

@ -0,0 +1,10 @@
import { PageElement } from '../../page-element';
import { createElement } from '../../../helper/create-element';
import { generate } from './anchor.html';
import { url } from '../../../types/url';
export class Anchor extends PageElement {
public constructor(href: url, text: string) {
super(createElement(generate({ href, text })));
}
}

View file

@ -0,0 +1,25 @@
import './image.scss';
import { last } from '../../../helper/last';
import { ResponsiveImage } from '../../../types/responsive-image';
import { html } from '../../../types/html';
export const generate = ({
sizes,
image,
alt,
container,
}: {
sizes: string;
image: ResponsiveImage;
alt: string;
container: boolean;
}): html => `
${container ? `<div class="figure-container">` : ''}
<img tabindex="0"
srcset="${image.srcSet}"
sizes="${sizes}"
src="${last(image.images)?.path}"
alt="${alt}"
/>
${container ? `</div>` : ''}
`;

View file

View file

@ -0,0 +1,24 @@
import { PageElement } from '../../page-element';
import { createElement } from '../../../helper/create-element';
import { generate } from './image.html';
import { last } from '../../../helper/last';
import { ResponsiveImage } from '../../../types/responsive-image';
export class Image extends PageElement {
private static readonly imageScreenRatio = 0.8;
public constructor(image: ResponsiveImage, alt: string, container = true) {
super(
createElement(generate({ image, alt, container, sizes: Image.getSizes(image) }))
);
}
private static getSizes(image: ResponsiveImage): string {
return (
image.images
.slice(0, -1)
.map(d => `(max-width: ${d.width / Image.imageScreenRatio}px) ${d.width}px,`)
.join('\n') + `\n${last(image.images).width}px`
);
}
}

View file

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

View file

@ -0,0 +1,4 @@
.primitive-text {
text-align: left;
margin-top: var(--line-height);
}

View file

@ -0,0 +1,9 @@
import { PageElement } from '../../page-element';
import { createElement } from '../../../helper/create-element';
import { generate } from './text.html';
export class Text extends PageElement {
public constructor(text: string) {
super(createElement(generate(text)));
}
}

View file

@ -0,0 +1,24 @@
import './video.scss';
import { url } from '../../../types/url';
import { html } from '../../../types/html';
export const generate = ({
poster,
options,
webm,
mp4,
container,
}: {
poster: url;
options: string;
webm: url;
mp4: url;
container: boolean;
}): html => `
${container ? `<div class="figure-container">` : ''}
<video ${options} ${poster ? `poster="${poster}` : ''}" >
<source src="${webm}" type="video/webm"/>
<source src="${mp4}" type="video/mp4"/>
</video>
${container ? `</div>` : ''}
`;

View file

View file

@ -0,0 +1,16 @@
import { PageElement } from '../../page-element';
import { createElement } from '../../../helper/create-element';
import { generate } from './video.html';
import { url } from '../../../types/url';
export class Video extends PageElement {
public constructor(
poster: url,
mp4: url,
webm: url,
options?: string,
container = true
) {
super(createElement(generate({ poster, mp4, webm, options, container })));
}
}

13
src/page/body/body.ts Normal file
View file

@ -0,0 +1,13 @@
import { PageElement } from '../page-element';
import { OnLoadEvent } from '../../events/concrete-events/on-load-event';
import { OnEventBroadcasterChangedEvent } from '../../events/concrete-events/on-event-broadcaster-changed-event';
export class Body extends PageElement {
constructor(root: HTMLElement, children: Array<PageElement>) {
super(root);
children.forEach(c => this.attachElement(c));
this.broadcastEvent(new OnEventBroadcasterChangedEvent(this));
this.broadcastEvent(new OnLoadEvent(this));
}
}

View file

@ -1,10 +1,6 @@
import { Content } from '../../model/portfolio';
import { html } from '../../framework/model/misc';
import './content.scss';
import { html } from '../../types/html';
export const generate = (content: Content): html => `
<div class="content">
${content.map(element => element.toHTML()).join('\n')}
</div>
export const generate = (): html => `
<div class="content"></div>
`;

View file

@ -1,10 +1,11 @@
import { PageElement } from '../../framework/page-element';
import { createElement } from '../../framework/helper/create-element';
import { Content } from '../../model/portfolio';
import { createElement } from '../../helper/create-element';
import { Content } from '../../types/portfolio';
import { generate } from './content.html';
import { PageElement } from '../page-element';
export class PageContent extends PageElement {
public constructor(content: Content) {
super(createElement(generate(content)));
super(createElement(generate()));
content.forEach(c => this.attachElement(c));
}
}

View file

@ -1,7 +1,7 @@
import { Footer } from '../../model/portfolio';
import { html } from '../../framework/model/misc';
import { Footer } from '../../types/portfolio';
import './footer.scss';
import { html } from '../../types/html';
export const generate = ({
title,

View file

@ -1,8 +1,8 @@
import { Footer } from '../../model/portfolio';
import { PageElement } from '../../framework/page-element';
import { Footer } from '../../types/portfolio';
import { PageElement } from '../page-element';
import { generate } from './footer.html';
import { createElement } from '../../framework/helper/create-element';
import { createElement } from '../../helper/create-element';
export class PageFooter extends PageElement {
constructor(footer: Footer) {

View file

@ -1,7 +1,7 @@
import { html } from '../../framework/model/misc';
import cancel from '../../static/icons/cancel.svg';
import './image-viewer.scss';
import { html } from '../../types/html';
export const generate = (): html => `
<section id="image-viewer">

View file

@ -1,14 +1,14 @@
import { PageElement } from '../../framework/page-element';
import { PageElement } from '../page-element';
import { generate } from './image-viewer.html';
import { createElement } from '../../framework/helper/create-element';
import { OnLoadEvent } from '../../framework/events/concrete-events/on-load-event';
import { OptionalEvent } from '../../framework/events/optional-event';
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 {
public constructor() {
super(createElement(generate()));
this.element.onclick = () => PageImageViewer.hide(this.element);
this.htmlRoot.onclick = () => PageImageViewer.hide(this.htmlRoot);
}
public handleOnLoadEvent(event: OnLoadEvent): OptionalEvent {
@ -17,7 +17,7 @@ export class PageImageViewer extends PageElement {
const media = Array.prototype.slice.call(document.querySelectorAll('img'));
media
.filter((e: HTMLElement) => e.parentElement !== this.element)
.filter((e: HTMLElement) => e.parentElement !== this.htmlRoot)
.forEach((e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this)));
return super.handleOnLoadEvent(event);
}
@ -29,12 +29,12 @@ export class PageImageViewer extends PageElement {
const element: HTMLImageElement = new Image();
element.src = (event.target as HTMLImageElement).src;
container.appendChild(element);
PageImageViewer.show(this.element);
PageImageViewer.show(this.htmlRoot);
}
private handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
PageImageViewer.hide(this.element);
PageImageViewer.hide(this.htmlRoot);
}
}

51
src/page/page-element.ts Normal file
View file

@ -0,0 +1,51 @@
import { EventHandler } from '../events/event-handler';
import { EventBroadcaster } from '../events/event-broadcaster';
import { OnEventBroadcasterChangedEvent } from '../events/concrete-events/on-event-broadcaster-changed-event';
import { OptionalEvent } from '../events/optional-event';
import { Event } from '../events/event';
import { OnLoadEvent } from '../events/concrete-events/on-load-event';
export abstract class PageElement extends EventHandler implements EventBroadcaster {
protected eventBroadcaster: EventBroadcaster;
public constructor(
public readonly htmlRoot?: HTMLElement,
protected children: Array<PageElement> = []
) {
super();
}
public broadcastEvent(event: Event) {
event = this.handle(event);
if (event) {
this.children.forEach(c => c.broadcastEvent(event));
}
}
public handleOnEventBroadcasterChangedEvent(
event: OnEventBroadcasterChangedEvent
): OptionalEvent {
this.eventBroadcaster = event.broadcaster;
return super.handleOnEventBroadcasterChangedEvent(event);
}
public handleOnLoadEvent(_: OnLoadEvent): OptionalEvent {
return super.handleOnLoadEvent(new OnLoadEvent(this));
}
protected query(query: string): HTMLElement | null {
return this.htmlRoot?.querySelector(query);
}
protected attachElementByReplacing(query: string, element: PageElement) {
const old = this.query(query);
old.parentElement.replaceChild(element.htmlRoot, old);
this.children.push(element);
}
protected attachElement(element: PageElement) {
this.htmlRoot.appendChild(element.htmlRoot);
this.children.push(element);
}
}

View file

@ -1,6 +1,5 @@
import { html } from '../../framework/model/misc';
import './theme-switcher.scss';
import { html } from '../../types/html';
export const generate = (): html => `
<input id="theme-switcher" aria-label="color-theme-switch" type="checkbox" name="switch-theme"/>

View file

@ -1,21 +1,18 @@
import { PageElement } from '../../framework/page-element';
import { createElement } from '../../framework/helper/create-element';
import { PageElement } from '../page-element';
import { createElement } from '../../helper/create-element';
import { generate } from './theme-switcher.html';
import {
isSystemLevelDarkModeEnabled,
turnOnDarkMode,
turnOnLightMode,
} from '../../framework/styles/dark-mode/dark-mode';
import {
turnOffAnimations,
turnOnAnimations,
} from '../../framework/styles/animations/animations';
import { OnLoadEvent } from '../../framework/events/concrete-events/on-load-event';
import { OnPageThemeChangedEvent } from '../../framework/events/concrete-events/on-page-theme-changed-event';
import { OptionalEvent } from '../../framework/events/optional-event';
} from '../../style/dark-mode/dark-mode';
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 {
private static readonly LOCAL_STORAGE_KEY = 'dark-mode';
private static readonly localStorageKey = 'dark-mode';
public constructor() {
super(createElement(generate()));
@ -24,14 +21,14 @@ export class PageThemeSwitcher extends PageElement {
const isDark = storedIsDark !== null ? storedIsDark : isSystemLevelDarkModeEnabled();
if (isDark) {
(this.element as HTMLInputElement).checked = true;
(this.htmlRoot as HTMLInputElement).checked = true;
turnOffAnimations();
turnOnDarkMode();
setTimeout(() => turnOnAnimations(), 0);
} else {
turnOnLightMode();
}
this.element.onchange = this.handleThemeChange.bind(this);
this.htmlRoot.onchange = this.handleThemeChange.bind(this);
}
public handleOnLoadEvent(event: OnLoadEvent): OptionalEvent {
@ -40,7 +37,7 @@ export class PageThemeSwitcher extends PageElement {
}
private handleThemeChange() {
const isDark = (this.element as HTMLInputElement).checked;
const isDark = (this.htmlRoot as HTMLInputElement).checked;
if (isDark) {
turnOnDarkMode();
} else {
@ -53,14 +50,14 @@ export class PageThemeSwitcher extends PageElement {
private static saveToLocalStorage(darkModeEnabled: boolean) {
localStorage?.setItem(
PageThemeSwitcher.LOCAL_STORAGE_KEY,
PageThemeSwitcher.localStorageKey,
JSON.stringify(darkModeEnabled)
);
}
private static loadFromLocalStorage(): boolean | null {
try {
return JSON.parse(localStorage?.getItem(PageThemeSwitcher.LOCAL_STORAGE_KEY));
return JSON.parse(localStorage?.getItem(PageThemeSwitcher.localStorageKey));
} catch {
return null;
}

View file

@ -1,10 +1,10 @@
import { TimelineElement } from '../../../model/portfolio';
import { html } from '../../../framework/model/misc';
import { TimelineElement } from '../../../types/portfolio';
import './timeline-element.scss';
import { html } from '../../../types/html';
export const generate = (
{ date, title, figure, description, more, link }: TimelineElement,
{ date, title, more }: TimelineElement,
showMore: string,
showLess: string
): html => `
@ -15,8 +15,8 @@ export const generate = (
</div>
<div class="card">
<h2>${title}</h2>
${figure.toHTML(true)}
${description.toHTML()}
<div class="figure"></div>
<div class="description"></div>
${
more
? `
@ -28,7 +28,7 @@ export const generate = (
`
: ''
}
${link ? link.toHTML() : ''}
<div class="link"></div>
</div>
</section>
`;

View file

@ -1,9 +1,9 @@
import { TimelineElement } from '../../../model/portfolio';
import { TimelineElement } from '../../../types/portfolio';
import { PageContent } from '../../content/content';
import { PageElement } from '../../../framework/page-element';
import { PageElement } from '../../page-element';
import { generate } from './timeline-element.html';
import { createElement } from '../../../framework/helper/create-element';
import { OnBodyDimensionsChangedEvent } from '../../../framework/events/concrete-events/on-body-dimensions-changed-event';
import { createElement } from '../../../helper/create-element';
import { OnBodyDimensionsChangedEvent } from '../../../events/concrete-events/on-body-dimensions-changed-event';
export class PageTimelineElement extends PageElement {
private isOpen: boolean;
@ -18,15 +18,23 @@ export class PageTimelineElement extends PageElement {
if (timelineElement.more) {
const content = new PageContent(timelineElement.more);
super(root, [content]);
super(root);
this.children = [content];
this.isOpen = false;
this.more = root.querySelector('.more');
this.more.appendChild(content.element);
this.more.appendChild(content.htmlRoot);
window.addEventListener('resize', this.handleResize.bind(this));
root
.querySelector('.buttons')
.addEventListener('click', this.toggleOpen.bind(this));
} else super(root);
this.attachElementByReplacing('.figure', timelineElement.figure);
this.attachElementByReplacing('.description', timelineElement.description);
if (timelineElement.link) {
this.attachElementByReplacing('.link', timelineElement.link);
}
}
private toggleOpen() {
@ -46,15 +54,10 @@ export class PageTimelineElement extends PageElement {
}
private notifyOfHeightChange(deltaHeight: number = undefined) {
this.eventBroadcaster?.broadcastEvent(
new OnBodyDimensionsChangedEvent(deltaHeight)
);
this.eventBroadcaster?.broadcastEvent(new OnBodyDimensionsChangedEvent(deltaHeight));
setTimeout(
() =>
this.eventBroadcaster?.broadcastEvent(
new OnBodyDimensionsChangedEvent()
),
() => this.eventBroadcaster?.broadcastEvent(new OnBodyDimensionsChangedEvent()),
250
);
}

View file

@ -1,5 +1,5 @@
import { html } from '../../framework/model/misc';
import './timeline.scss';
import { html } from '../../types/html';
export const generate = (): html => `
<div id="timeline"></div>

View file

@ -1,14 +1,14 @@
import { Timeline } from '../../model/portfolio';
import { Timeline } from '../../types/portfolio';
import { PageTimelineElement } from './timeline-element/timeline-element';
import { generate } from './timeline.html';
import { createElement } from '../../framework/helper/create-element';
import { ContainerPage } from '../../framework/container-page';
import { createElement } from '../../helper/create-element';
import { PageElement } from '../page-element';
export class PageTimeline extends ContainerPage {
export class PageTimeline extends PageElement {
public constructor({ elements, showMoreText, showLessText }: Timeline) {
super(
createElement(generate()),
elements.map(e => new PageTimelineElement(e, showMoreText, showLessText))
super(createElement(generate()));
elements.forEach(e =>
this.attachElement(new PageTimelineElement(e, showMoreText, showLessText))
);
}
}