Add final touches
This commit is contained in:
parent
b1fd2f372f
commit
0429ea7f72
64 changed files with 576 additions and 444 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { Header } from '../../model/portfolio';
|
||||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
|
||||
import './about.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,16 @@
|
|||
@import '../../style/mixins';
|
||||
@import '../../style/vars';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
#about {
|
||||
section#about {
|
||||
@include card-base($vars);
|
||||
|
||||
background-color: map_get($vars, $important-card-color);
|
||||
|
||||
* {
|
||||
color: map_get($vars, $important-card-text-color);
|
||||
}
|
||||
background-color: map_get($vars, $accent-color);
|
||||
font-size: 0;
|
||||
|
||||
$img-size: 125px;
|
||||
|
||||
h1,
|
||||
img,
|
||||
.placeholder,
|
||||
& {
|
||||
@include title-font();
|
||||
.placeholder {
|
||||
@include title-font($vars);
|
||||
}
|
||||
|
||||
img {
|
||||
|
|
@ -26,19 +19,18 @@
|
|||
}
|
||||
|
||||
p {
|
||||
@include main-font();
|
||||
@include main-font($vars);
|
||||
text-align: justify;
|
||||
margin-top: map_get($vars, $small-margin);
|
||||
}
|
||||
|
||||
h1 {
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
@include on-small-screen {
|
||||
h1 {
|
||||
margin-top: map_get($vars, $small-margin);
|
||||
}
|
||||
p,
|
||||
h1 {
|
||||
color: map_get($vars, $very-light-text-color);
|
||||
margin-top: map_get($vars, $small-margin);
|
||||
}
|
||||
|
||||
@include on-large-screen {
|
||||
|
|
@ -69,6 +61,7 @@
|
|||
|
||||
h1 {
|
||||
text-align: left;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { PageContent } from '../content/content';
|
||||
import { Header } from '../../model/portfolio';
|
||||
import { PageElement } from '../../framework/page-element';
|
||||
|
||||
import { generate } from './about.html';
|
||||
import { createElement } from '../../framework/helper/create-element';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
@import '../../style/vars';
|
||||
@import '../../style/mixins';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
div.background-element {
|
||||
position: -webkit-sticky;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
|
@ -24,9 +22,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
transition: transform map_get($vars, $long-transition-time),
|
||||
opacity map_get($vars, $long-transition-time),
|
||||
background-color map_get($vars, $long-transition-time);
|
||||
transition: transform map_get($vars, $transition-time),
|
||||
opacity map_get($vars, $transition-time),
|
||||
background-color map_get($vars, $transition-time);
|
||||
|
||||
will-change: transform, opacity;
|
||||
animation: fade-in 1s linear;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { PageElement } from '../../framework/page-element';
|
||||
import { PageEvent, PageEventType } from '../../framework/page-event';
|
||||
import { PageEvent, PageEventType } from '../../framework/events/page-event';
|
||||
import { Blob } from './blob';
|
||||
import { Random } from '../../framework/helper/random';
|
||||
import { getHeight } from '../../framework/helper/get-height';
|
||||
|
|
@ -15,13 +15,17 @@ export class PageBackground extends PageElement {
|
|||
}
|
||||
|
||||
protected handleEvent(event: PageEvent, parent: PageElement) {
|
||||
if (event.type === PageEventType.onLoad) {
|
||||
this.bindListeners(parent);
|
||||
} else if (event.type === PageEventType.onBodyDimensionsChanged) {
|
||||
this.resize(parent, event.data?.deltaHeight);
|
||||
} else if (event.type === PageEventType.pageThemeChanged) {
|
||||
Blob.changeTheme(event.data);
|
||||
this.blobs.forEach(b => b.decideColor());
|
||||
switch (event.type) {
|
||||
case PageEventType.onLoad:
|
||||
this.bindListeners(parent);
|
||||
break;
|
||||
case PageEventType.onBodyDimensionsChanged:
|
||||
this.resize(parent, event.data?.deltaHeight);
|
||||
break;
|
||||
case PageEventType.pageThemeChanged:
|
||||
Blob.changeTheme(event.data);
|
||||
this.blobs.forEach(b => b.decideColor());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
import './background.scss';
|
||||
|
||||
export const generate = (): html => `
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
import { mixColors } from '../../framework/helper/mix-colors';
|
||||
import { createElement } from '../../framework/helper/create-element';
|
||||
import { Random } from '../../framework/helper/random';
|
||||
import { generate } from './background.html';
|
||||
import { generate } from './blob.html';
|
||||
|
||||
export class Blob {
|
||||
private static readonly creatorRandom = new Random(44);
|
||||
private static colorPickerRandom = new Random(132);
|
||||
private static readonly darkColors = ['#2c477a'];
|
||||
private static readonly lightColors = ['#fff9e0', '#ffd6d6'];
|
||||
private static readonly darkColors = ['#2C477A'];
|
||||
private static colorPickerRandom = new Random(132);
|
||||
private static isDarkThemed = false;
|
||||
|
||||
private static zMin: number;
|
||||
private static zMax: number;
|
||||
private static perspective: number;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Content } from '../../model/portfolio';
|
||||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
|
||||
import './content.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
@import '../../style/vars';
|
||||
@import '../../style/mixins';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
.content {
|
||||
margin-top: map_get($vars, $small-margin);
|
||||
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Footer } from '../../model/portfolio';
|
||||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
|
||||
import './footer.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
@import '../../style/mixins';
|
||||
@import '../../style/vars';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
footer#page-footer {
|
||||
text-align: center;
|
||||
|
||||
margin: map_get($vars, $large-margin) auto 0 auto;
|
||||
margin-top: map_get($vars, $large-margin);
|
||||
width: 100%;
|
||||
|
||||
h2 {
|
||||
@include title-font();
|
||||
@include title-font($vars);
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: map_get($vars, $normal-margin);
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
margin-top: map_get($vars, $normal-margin);
|
||||
text-align: left;
|
||||
|
||||
li {
|
||||
|
|
@ -29,10 +28,11 @@
|
|||
img,
|
||||
svg {
|
||||
@include max-square(map_get($vars, $icon-size));
|
||||
margin-right: map_get($vars, $small-margin);
|
||||
|
||||
* {
|
||||
fill: map_get($vars, $normal-text-color);
|
||||
}
|
||||
margin-right: map_get($vars, $small-margin);
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
@ -44,13 +44,17 @@
|
|||
aside.other {
|
||||
@include center-children();
|
||||
flex-direction: column;
|
||||
margin: map_get($vars, $large-margin) auto map_get($vars, $line-height)
|
||||
auto;
|
||||
margin: map_get($vars, $large-margin) auto 0 auto;
|
||||
padding-bottom: map_get($vars, $line-height);
|
||||
width: map_get($vars, $body-width);
|
||||
|
||||
h6 {
|
||||
@include special-text-font($vars);
|
||||
display: inline;
|
||||
&,
|
||||
* {
|
||||
@include special-text-font($vars);
|
||||
color: map_get($vars, $normal-text-color);
|
||||
}
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
import cancel from '../../static/icons/cancel.svg';
|
||||
|
||||
import './image-viewer.scss';
|
||||
|
|
@ -6,6 +6,6 @@ import './image-viewer.scss';
|
|||
export const generate = (): html => `
|
||||
<section id="image-viewer">
|
||||
<div id="container"></div>
|
||||
<img id="cancel" src="${cancel}" alt="cancel"/>
|
||||
<img tabindex="0" id="cancel" src="${cancel}" alt="cancel"/>
|
||||
</section>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
@import '../../style/vars';
|
||||
@import '../../style/mixins';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
#image-viewer {
|
||||
section#image-viewer {
|
||||
@include center-children();
|
||||
display: none;
|
||||
position: fixed;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { PageElement } from '../../framework/page-element';
|
||||
|
||||
import { generate } from './image-viewer.html';
|
||||
import { PageEvent, PageEventType } from '../../framework/page-event';
|
||||
import { PageEvent, PageEventType } from '../../framework/events/page-event';
|
||||
import { createElement } from '../../framework/helper/create-element';
|
||||
|
||||
export class PageImageViewer extends PageElement {
|
||||
|
|
@ -11,24 +11,19 @@ export class PageImageViewer extends PageElement {
|
|||
}
|
||||
|
||||
protected handleEvent(event: PageEvent, parent: PageElement) {
|
||||
if (event.type !== PageEventType.onLoad) {
|
||||
return;
|
||||
}
|
||||
if (event.type === PageEventType.onLoad) {
|
||||
document.body.addEventListener('keydown', this.handleKeydown.bind(this));
|
||||
|
||||
document.body.addEventListener('keydown', this.handleKeydown.bind(this));
|
||||
|
||||
const media = Array.prototype.slice.call(
|
||||
parent.element.querySelectorAll('img, video')
|
||||
);
|
||||
|
||||
media
|
||||
.filter(
|
||||
(e: HTMLElement) =>
|
||||
e.parentElement !== this.element && !e.classList.contains('no-open')
|
||||
)
|
||||
.forEach(
|
||||
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
|
||||
const media = Array.prototype.slice.call(
|
||||
parent.element.querySelectorAll('img')
|
||||
);
|
||||
|
||||
media
|
||||
.filter((e: HTMLElement) => e.parentElement !== this.element)
|
||||
.forEach(
|
||||
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private handleClick(event: Event) {
|
||||
|
|
|
|||
|
|
@ -19,4 +19,20 @@ export const create = ({ header, timeline, footer }: Portfolio) => {
|
|||
new PageBackground(pageHeader, pageFooter),
|
||||
]),
|
||||
]).setAsMain();
|
||||
|
||||
addSupportForTabNavigation();
|
||||
removeUnnecessaryOutlines();
|
||||
};
|
||||
|
||||
const addSupportForTabNavigation = () =>
|
||||
(document.onkeydown = e => {
|
||||
if (e.key === ' ') {
|
||||
(document.activeElement as HTMLElement)?.click();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
const removeUnnecessaryOutlines = () =>
|
||||
(document.onclick = e => {
|
||||
(e.target as HTMLElement)?.blur();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { html } from '../../model/misc';
|
||||
import { html } from '../../framework/model/misc';
|
||||
|
||||
import './theme-switcher.scss';
|
||||
|
||||
export const generate = (): html => `
|
||||
<input id="theme-switcher" type="checkbox" name="switch-theme"/>
|
||||
<input id="theme-switcher" aria-label="color-theme-switch" type="checkbox" name="switch-theme"/>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
@import '../../style/mixins';
|
||||
@import '../../style/vars';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive using($vars) {
|
||||
input[type='checkbox']#theme-switcher {
|
||||
|
|
@ -14,11 +13,12 @@
|
|||
margin-top: map_get($vars, $normal-margin);
|
||||
}
|
||||
|
||||
&::-ms-check {
|
||||
display: none;
|
||||
}
|
||||
|
||||
background-color: map_get($vars, $accent-color);
|
||||
|
||||
z-index: 10;
|
||||
cursor: pointer;
|
||||
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
|
|
@ -33,10 +33,12 @@
|
|||
inset 0 0 1px rgba(0, 0, 0, 0.4);
|
||||
|
||||
&:before {
|
||||
// moon + sun
|
||||
@include square($icon-size);
|
||||
}
|
||||
|
||||
&:after {
|
||||
// sun blocking moon
|
||||
@include square($icon-size * 0.8);
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +52,8 @@
|
|||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
transition: transform map_get($vars, $long-transition-time),
|
||||
background-color map_get($vars, $long-transition-time);
|
||||
transition: transform map_get($vars, $transition-time),
|
||||
background-color map_get($vars, $transition-time);
|
||||
}
|
||||
|
||||
&:not(:checked) {
|
||||
|
|
@ -59,16 +61,16 @@
|
|||
transform: translateY(-50%) translateX(3 * $margin + $icon-size);
|
||||
|
||||
animation: shine 3s linear alternate infinite;
|
||||
background-color: map_get($vars, $theme-switcher-foreground);
|
||||
background-color: map_get($vars, $sun-color);
|
||||
@keyframes shine {
|
||||
from {
|
||||
filter: brightness(1.01);
|
||||
box-shadow: 0 0 4px 2px map_get($vars, $theme-switcher-foreground);
|
||||
box-shadow: 0 0 4px 2px map_get($vars, $sun-color);
|
||||
}
|
||||
|
||||
to {
|
||||
filter: brightness(1.1);
|
||||
box-shadow: 0 0 15px 2px map_get($vars, $theme-switcher-foreground);
|
||||
box-shadow: 0 0 15px 2px map_get($vars, $sun-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,9 +92,5 @@
|
|||
transform: translateY(-50%) translateX($margin + $icon-size * 0.33);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import {
|
|||
isSystemLevelDarkModeEnabled,
|
||||
turnOnDarkMode,
|
||||
turnOnLightMode,
|
||||
} from '../../framework/helper/dark-mode';
|
||||
import { PageEvent, PageEventType } from '../../framework/page-event';
|
||||
import { EventBroadcaster } from '../../framework/event-broadcaster';
|
||||
} from '../../framework/styles/dark-mode/dark-mode';
|
||||
import { PageEvent, PageEventType } from '../../framework/events/page-event';
|
||||
import { EventBroadcaster } from '../../framework/events/event-broadcaster';
|
||||
import {
|
||||
turnOffAnimations,
|
||||
turnOnAnimations,
|
||||
} from '../../framework/helper/animations/animations';
|
||||
} from '../../framework/styles/animations/animations';
|
||||
|
||||
export class PageThemeSwitcher extends PageElement {
|
||||
private static readonly LOCAL_STORAGE_KEY = 'dark-mode';
|
||||
|
|
@ -62,9 +62,12 @@ export class PageThemeSwitcher extends PageElement {
|
|||
}
|
||||
|
||||
private static loadFromLocalStorage(): boolean | null {
|
||||
return JSON.parse(
|
||||
window.localStorage?.getItem(PageThemeSwitcher.LOCAL_STORAGE_KEY) ||
|
||||
'null'
|
||||
);
|
||||
try {
|
||||
return JSON.parse(
|
||||
window.localStorage?.getItem(PageThemeSwitcher.LOCAL_STORAGE_KEY)
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TimelineElement } from '../../../model/portfolio';
|
||||
import { html } from '../../../model/misc';
|
||||
import { html } from '../../../framework/model/misc';
|
||||
|
||||
import './timeline-element.scss';
|
||||
|
||||
|
|
@ -22,8 +22,8 @@ export const generate = (
|
|||
? `
|
||||
<div class="more"></div>
|
||||
<div class="buttons">
|
||||
<a class="show-more">${showMore}</a>
|
||||
<a class="show-less">${showLess}</a>
|
||||
<a tabindex="0" class="show-more">${showMore}</a>
|
||||
<a tabindex="0" class="show-less">${showLess}</a>
|
||||
</div>
|
||||
`
|
||||
: ''
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
@import '../../../style/mixins';
|
||||
@import '../../../style/vars';
|
||||
@use '../../../style/include' as *;
|
||||
|
||||
@mixin q-dependent-line-container($vars, $q) {
|
||||
.line {
|
||||
|
|
@ -18,7 +17,7 @@
|
|||
}
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
.timeline-element {
|
||||
section.timeline-element {
|
||||
display: flex;
|
||||
width: map_get($vars, $body-width);
|
||||
margin: auto;
|
||||
|
|
@ -32,9 +31,13 @@
|
|||
border-left: map_get($vars, $line-width) solid
|
||||
map_get($vars, $accent-color);
|
||||
|
||||
&:before {
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&:before {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
border-left: map_get($vars, $line-width) solid
|
||||
|
|
@ -42,12 +45,10 @@
|
|||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
@include square(map_get($vars, $icon-size));
|
||||
border-radius: 1000px;
|
||||
border: map_get($vars, $line-width) solid
|
||||
map_get($vars, $accent-color);
|
||||
position: absolute;
|
||||
left: -1 * map_get($vars, $icon-size) / 2 +
|
||||
map_get($vars, $line-width) / 2;
|
||||
}
|
||||
|
|
@ -88,18 +89,19 @@
|
|||
|
||||
.card {
|
||||
@include card-base($vars);
|
||||
|
||||
border-radius: map_get($vars, $border-radius);
|
||||
background-color: map_get($vars, $card-color);
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
& > *:not(:first-child) {
|
||||
margin-top: map_get($vars, $line-height);
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@include sub-title-font();
|
||||
@include sub-title-font($vars);
|
||||
}
|
||||
|
||||
& > p {
|
||||
|
|
@ -110,16 +112,16 @@
|
|||
.more {
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
margin-top: 0;
|
||||
transition: height map_get($vars, $long-transition-time);
|
||||
transition: height map_get($vars, $transition-time);
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: relative;
|
||||
margin-top: map_get($vars, $small-margin);
|
||||
margin-top: map_get($vars, $line-height);
|
||||
|
||||
* {
|
||||
transition: opacity map_get($vars, $long-transition-time);
|
||||
.show-more,
|
||||
.show-less {
|
||||
transition: opacity map_get($vars, $transition-time);
|
||||
}
|
||||
|
||||
.show-more {
|
||||
|
|
@ -127,9 +129,9 @@
|
|||
}
|
||||
|
||||
.show-less {
|
||||
@include absolute-center();
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
@include absolute-center();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { TimelineElement } from '../../../model/portfolio';
|
|||
import { PageContent } from '../../content/content';
|
||||
import { PageElement } from '../../../framework/page-element';
|
||||
import { generate } from './timeline-element.html';
|
||||
import { PageEventType } from '../../../framework/page-event';
|
||||
import { PageEventType } from '../../../framework/events/page-event';
|
||||
import { createElement } from '../../../framework/helper/create-element';
|
||||
|
||||
export class PageTimelineElement extends PageElement {
|
||||
private isOpen;
|
||||
private isOpen: boolean;
|
||||
private more: HTMLElement;
|
||||
|
||||
public constructor(
|
||||
|
|
@ -56,7 +56,7 @@ export class PageTimelineElement extends PageElement {
|
|||
this.eventBroadcaster?.broadcastEvent({
|
||||
type: PageEventType.onBodyDimensionsChanged,
|
||||
}),
|
||||
350
|
||||
250
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ export class PageTimelineElement extends PageElement {
|
|||
element.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
element.style.visibility = 'hidden';
|
||||
}, 350);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
private static show(element: HTMLElement) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { html } from "../../model/misc";
|
||||
import "./timeline.scss";
|
||||
import { html } from '../../framework/model/misc';
|
||||
import './timeline.scss';
|
||||
|
||||
export const generate = (): html => `
|
||||
<main id="timeline"></main>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
@import '../../style/vars';
|
||||
@import '../../style/mixins';
|
||||
@use '../../style/include' as *;
|
||||
|
||||
@include responsive() using ($vars) {
|
||||
#timeline {
|
||||
main#timeline {
|
||||
@include on-large-screen {
|
||||
// workaround for IE
|
||||
& > :first-child {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Timeline } from '../../model/portfolio';
|
||||
import { PageElement } from '../../framework/page-element';
|
||||
import { PageTimelineElement } from './timeline-element/timeline-element';
|
||||
import { generate } from './timeline.html';
|
||||
import { createElement } from '../../framework/helper/create-element';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue