Improve image handling & fix shadows
This commit is contained in:
parent
bc5074b28d
commit
2bb2117a59
47 changed files with 330 additions and 329 deletions
0
src/page/figure/bordered-image/bordered-image.scss
Normal file
0
src/page/figure/bordered-image/bordered-image.scss
Normal file
23
src/page/figure/bordered-image/bordered-image.ts
Normal file
23
src/page/figure/bordered-image/bordered-image.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ResponsiveImage } from '../../../types/responsive-image';
|
||||
import { ImageViewer } from '../../image-viewer/image-viewer';
|
||||
import { Image } from '../../image/image.html';
|
||||
import { Figure } from '../figure';
|
||||
import './bordered-image.scss';
|
||||
|
||||
export class BorderedImage extends Figure {
|
||||
public constructor(
|
||||
options: {
|
||||
image: ResponsiveImage;
|
||||
alt: string;
|
||||
sizes?: string | null;
|
||||
isEagerLoaded?: boolean;
|
||||
},
|
||||
public imageViewer?: ImageViewer
|
||||
) {
|
||||
super(Image(options));
|
||||
}
|
||||
|
||||
protected async onClick() {
|
||||
this.imageViewer?.showImage(this.query('img') as HTMLImageElement);
|
||||
}
|
||||
}
|
||||
21
src/page/figure/figure.html.ts
Normal file
21
src/page/figure/figure.html.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import play from '../../../static/icons/play-button.svg';
|
||||
import { html } from '../../types/html';
|
||||
import './figure.scss';
|
||||
|
||||
export const generate = ({
|
||||
children,
|
||||
hasButton,
|
||||
invertButton,
|
||||
}: {
|
||||
children: html;
|
||||
hasButton: boolean;
|
||||
invertButton: boolean;
|
||||
}): html => `
|
||||
<div class="figure-container" tabindex=0 >
|
||||
${children}
|
||||
${
|
||||
hasButton
|
||||
? `<div class="start-button ${invertButton ? 'inverted' : ''}" >${play}</div>`
|
||||
: ''
|
||||
}
|
||||
</div>`;
|
||||
29
src/page/figure/figure.scss
Normal file
29
src/page/figure/figure.scss
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
@use '../../style/mixins' as *;
|
||||
|
||||
.figure-container {
|
||||
box-shadow: var(--inset-shadow);
|
||||
transition: box-shadow var(--transition-time);
|
||||
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
> .start-button {
|
||||
@include image-button(var(--large-icon-size));
|
||||
@include absolute-center;
|
||||
@include square(calc(var(--large-icon-size) + var(--normal-margin) * 2));
|
||||
|
||||
&:hover > svg {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
> svg {
|
||||
border-radius: 1000px;
|
||||
@include blurred-background;
|
||||
transition: transform var(--transition-time), box-shadow var(--transition-time);
|
||||
}
|
||||
|
||||
&.inverted > svg {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/page/figure/figure.ts
Normal file
21
src/page/figure/figure.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { html } from '../../types/html';
|
||||
import { PageElement } from '../page-element';
|
||||
import { generate } from './figure.html';
|
||||
|
||||
export abstract class Figure extends PageElement {
|
||||
public constructor(
|
||||
children: html,
|
||||
{
|
||||
hasButton = false,
|
||||
invertButton = false,
|
||||
}: {
|
||||
hasButton?: boolean;
|
||||
invertButton?: boolean;
|
||||
} = {}
|
||||
) {
|
||||
super(generate({ children, hasButton, invertButton }));
|
||||
this.htmlRoot.addEventListener('click', this.onClick.bind(this));
|
||||
}
|
||||
|
||||
protected abstract onClick(): unknown;
|
||||
}
|
||||
21
src/page/figure/preview/preview.html.ts
Normal file
21
src/page/figure/preview/preview.html.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import loading from '../../../../static/icons/loading.svg';
|
||||
import { html } from '../../../types/html';
|
||||
import { ResponsiveImage } from '../../../types/responsive-image';
|
||||
import { Image } from '../../image/image.html';
|
||||
import './preview.scss';
|
||||
|
||||
export const generate = ({
|
||||
alt,
|
||||
poster,
|
||||
}: {
|
||||
alt: string;
|
||||
poster: ResponsiveImage;
|
||||
}): html =>
|
||||
`${Image({
|
||||
image: poster,
|
||||
alt,
|
||||
})}
|
||||
<div class="overlay">
|
||||
<div class="loading">${loading}</div>
|
||||
<iframe title="${alt}" allowfullscreen loading="lazy"></iframe>
|
||||
</div>`;
|
||||
|
|
@ -1,42 +1,38 @@
|
|||
@use '../../style/mixins' as *;
|
||||
@use '../../../style/mixins' as *;
|
||||
|
||||
.preview {
|
||||
position: relative;
|
||||
|
||||
.overlay {
|
||||
.figure-container {
|
||||
> .overlay {
|
||||
@include square(100%);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.loading {
|
||||
> .loading {
|
||||
@include square(var(--large-icon-size));
|
||||
@include absolute-center;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
iframe {
|
||||
> iframe {
|
||||
@include square(100%);
|
||||
border: none;
|
||||
&:fullscreen {
|
||||
border-radius: 0;
|
||||
}
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.loaded {
|
||||
.figure-container,
|
||||
.start-button {
|
||||
> .start-button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.loading {
|
||||
visibility: visible;
|
||||
> .overlay {
|
||||
pointer-events: all;
|
||||
|
||||
> .loading {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/page/figure/preview/preview.ts
Normal file
28
src/page/figure/preview/preview.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { ResponsiveImage } from '../../../types/responsive-image';
|
||||
import { Figure } from '../figure';
|
||||
import { generate } from './preview.html';
|
||||
|
||||
export class Preview extends Figure {
|
||||
public constructor(poster: ResponsiveImage, private readonly url: string, alt: string) {
|
||||
super(generate({ poster, alt }), {
|
||||
hasButton: true,
|
||||
});
|
||||
this.url += '?portfolioView';
|
||||
}
|
||||
|
||||
protected onClick() {
|
||||
this.htmlRoot.classList.add('loaded');
|
||||
(this.query('iframe') as HTMLIFrameElement).src = this.url;
|
||||
}
|
||||
|
||||
protected initialize() {
|
||||
new IntersectionObserver((e) => {
|
||||
if (!e[0].isIntersecting) {
|
||||
this.htmlRoot.classList.remove('loaded');
|
||||
(this.query('iframe') as HTMLIFrameElement).src = '';
|
||||
}
|
||||
}).observe(this.htmlRoot.parentElement!);
|
||||
|
||||
super.initialize();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { ResponsiveImage } from '../../types/responsive-image';
|
||||
import { url } from '../../types/url';
|
||||
import { ResponsiveImage } from '../../../types/responsive-image';
|
||||
import { url } from '../../../types/url';
|
||||
|
||||
export interface VideoParameters {
|
||||
mp4: url;
|
||||
14
src/page/figure/video/video.html.ts
Normal file
14
src/page/figure/video/video.html.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { html } from '../../../types/html';
|
||||
import { Image } from '../../image/image.html';
|
||||
import { VideoParameters } from './video-parameters';
|
||||
import './video.scss';
|
||||
|
||||
export const generate = ({ webm, mp4, poster, altText }: VideoParameters): html => `
|
||||
${Image({
|
||||
image: poster,
|
||||
alt: altText,
|
||||
})}
|
||||
<video playsinline controls preload="none">
|
||||
<source src="${webm}" type="video/webm"/>
|
||||
<source src="${mp4}" type="video/mp4"/>
|
||||
</video>`;
|
||||
16
src/page/figure/video/video.scss
Normal file
16
src/page/figure/video/video.scss
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
@use '../../../style/mixins' as *;
|
||||
|
||||
.figure-container {
|
||||
&.loaded > .start-button,
|
||||
&:not(.loaded) > video {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
> video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
import { PageElement } from '../page-element';
|
||||
import { Figure } from '../figure';
|
||||
import { VideoParameters } from './video-parameters';
|
||||
import { generate } from './video.html';
|
||||
|
||||
export class Video extends PageElement {
|
||||
export class Video extends Figure {
|
||||
public constructor(options: VideoParameters) {
|
||||
super(generate(options));
|
||||
|
||||
this.query('.start-button').addEventListener('click', this.startVideo.bind(this));
|
||||
super(generate(options), {
|
||||
hasButton: true,
|
||||
invertButton: options.invertButton,
|
||||
});
|
||||
}
|
||||
|
||||
private async startVideo() {
|
||||
protected async onClick() {
|
||||
this.query('.start-button').style.visibility = 'hidden';
|
||||
this.htmlRoot.classList.add('loaded');
|
||||
|
||||
|
|
@ -4,15 +4,13 @@ import './header.scss';
|
|||
export const generate = ({
|
||||
name,
|
||||
about,
|
||||
photo,
|
||||
}: {
|
||||
name: string;
|
||||
about: Array<string>;
|
||||
photo: html;
|
||||
}): html => `
|
||||
<header id="about">
|
||||
<div class="photo-container">
|
||||
${photo}
|
||||
<div class="profile-picture">
|
||||
<img/>
|
||||
<div class="placeholder"></div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@
|
|||
}
|
||||
|
||||
$img-size: 125px;
|
||||
> .photo-container > .image {
|
||||
> .profile-picture {
|
||||
@include square($img-size);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
> h1 {
|
||||
|
|
@ -30,11 +31,10 @@
|
|||
auto;
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
> .photo-container {
|
||||
position: relative;
|
||||
|
||||
> .image {
|
||||
> .profile-picture {
|
||||
> .figure-container {
|
||||
@include square($img-size);
|
||||
|
||||
position: absolute;
|
||||
left: calc(#{math.div(-$img-size, 3)} - var(--normal-margin));
|
||||
top: calc(#{math.div(-$img-size, 3)} - var(--normal-margin));
|
||||
|
|
@ -55,15 +55,19 @@
|
|||
}
|
||||
|
||||
> h1,
|
||||
> .photo-container > .placeholder {
|
||||
> .profile-picture > .placeholder {
|
||||
@include title-font();
|
||||
}
|
||||
|
||||
> .photo-container {
|
||||
> .image {
|
||||
border-radius: 100%;
|
||||
box-shadow: var(--shadow);
|
||||
margin: auto;
|
||||
> .profile-picture {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.figure-container {
|
||||
&,
|
||||
> .image {
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { ResponsiveImage } from '../../types/responsive-image';
|
||||
import { Image } from '../image-viewer/image/image.html';
|
||||
import { BorderedImage } from '../figure/bordered-image/bordered-image';
|
||||
import { ImageViewer } from '../image-viewer/image-viewer';
|
||||
import { PageElement } from '../page-element';
|
||||
import { generate } from './header.html';
|
||||
import { ThemeSwitcher } from './theme-switcher/theme-switcher';
|
||||
|
|
@ -10,22 +11,31 @@ export class Header extends PageElement {
|
|||
image,
|
||||
imageAltText,
|
||||
about,
|
||||
imageViewer,
|
||||
}: {
|
||||
name: string;
|
||||
image: ResponsiveImage;
|
||||
imageAltText: string;
|
||||
about: Array<string>;
|
||||
imageViewer?: ImageViewer;
|
||||
}) {
|
||||
super(
|
||||
generate({
|
||||
name,
|
||||
about,
|
||||
photo: Image({
|
||||
})
|
||||
);
|
||||
|
||||
this.attachElementByReplacing(
|
||||
'img',
|
||||
new BorderedImage(
|
||||
{
|
||||
image,
|
||||
alt: imageAltText,
|
||||
sizes: '(max-width: 924px) 125px, 190px',
|
||||
}),
|
||||
})
|
||||
},
|
||||
imageViewer
|
||||
)
|
||||
);
|
||||
this.attachElement(new ThemeSwitcher());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import './image-viewer.scss';
|
|||
|
||||
export const generate = (): html => `
|
||||
<div id="image-viewer">
|
||||
<img height="0" width="0" image-viewer-ignore />
|
||||
<img height="0" width="0" />
|
||||
<button id="cancel">${cancel}</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,9 @@
|
|||
|
||||
img {
|
||||
@include square(auto);
|
||||
|
||||
@include on-large-screen {
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
}
|
||||
box-shadow: var(--shadow);
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
|
||||
@include on-small-screen {
|
||||
max-width: 95%;
|
||||
|
|
|
|||
|
|
@ -5,18 +5,6 @@ export class ImageViewer extends PageElement {
|
|||
public constructor() {
|
||||
super(generate());
|
||||
|
||||
document.body.addEventListener('click', (event: MouseEvent) => {
|
||||
const element = event.target as HTMLElement;
|
||||
|
||||
if (element.classList?.contains('image')) {
|
||||
this.showImage(element.querySelector('img')!);
|
||||
}
|
||||
|
||||
if (element instanceof HTMLImageElement) {
|
||||
this.showImage(element);
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener('keydown', (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
this.hideImage();
|
||||
|
|
@ -26,11 +14,7 @@ export class ImageViewer extends PageElement {
|
|||
this.htmlRoot.addEventListener('click', this.hideImage.bind(this));
|
||||
}
|
||||
|
||||
private showImage(source: HTMLImageElement) {
|
||||
if (source.attributes['image-viewer-ignore'] as boolean | undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
public showImage(source: HTMLImageElement) {
|
||||
const image = this.query('img') as HTMLImageElement;
|
||||
image.src = '';
|
||||
image.src = source.src;
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
import { html } from '../../../types/html';
|
||||
import { ResponsiveImage } from '../../../types/responsive-image';
|
||||
import './image.scss';
|
||||
|
||||
export const Image = ({
|
||||
image,
|
||||
alt,
|
||||
container = false,
|
||||
isIgnoredByImageViewer = false,
|
||||
sizes = null,
|
||||
isEagerLoaded = false,
|
||||
}: {
|
||||
image: ResponsiveImage;
|
||||
alt: string;
|
||||
container?: boolean;
|
||||
isIgnoredByImageViewer?: boolean;
|
||||
sizes?: string | null;
|
||||
isEagerLoaded?: boolean;
|
||||
}): html => `
|
||||
${
|
||||
container
|
||||
? `<div class="figure-container" style="padding-top:${
|
||||
(image.height / image.width) * 100
|
||||
}%">`
|
||||
: ''
|
||||
}
|
||||
<div
|
||||
class="image"
|
||||
style="background-size: cover; background-image: url('${image.placeholder}')"
|
||||
${isIgnoredByImageViewer ? '' : 'tabindex="0"'}
|
||||
>
|
||||
<img
|
||||
${isIgnoredByImageViewer ? 'image-viewer-ignore' : ''}
|
||||
${isEagerLoaded ? '' : 'loading="lazy"'}
|
||||
srcset="${image.srcSet}"
|
||||
${sizes ? `sizes="${sizes}"` : ''}
|
||||
src="${image.src}"
|
||||
width="${image.width}"
|
||||
height="${image.height}"
|
||||
alt="${alt}"
|
||||
/>
|
||||
</div>
|
||||
${container ? '</div>' : ''}
|
||||
`;
|
||||
31
src/page/image/image.html.ts
Normal file
31
src/page/image/image.html.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { html } from '../../types/html';
|
||||
import { ResponsiveImage } from '../../types/responsive-image';
|
||||
import './image.scss';
|
||||
|
||||
export const Image = ({
|
||||
image,
|
||||
alt,
|
||||
sizes = null,
|
||||
isEagerLoaded = false,
|
||||
}: {
|
||||
image: ResponsiveImage;
|
||||
alt: string;
|
||||
sizes?: string | null;
|
||||
isEagerLoaded?: boolean;
|
||||
}): html => `
|
||||
<div
|
||||
class="image"
|
||||
style="background-size: cover; background-image: url('${
|
||||
image.placeholder
|
||||
}'); aspect-ratio: ${image.width / image.height}"
|
||||
>
|
||||
<img
|
||||
${isEagerLoaded ? '' : 'loading="lazy"'}
|
||||
srcset="${image.srcSet}"
|
||||
${sizes ? `sizes="${sizes}"` : ''}
|
||||
src="${image.src}"
|
||||
width="${image.width}"
|
||||
height="${image.height}"
|
||||
alt="${alt}"
|
||||
/>
|
||||
</div>`;
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
.image {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
|
||||
&:not([image-viewer-ignore]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
import loading from '../../../static/icons/loading.svg';
|
||||
import play from '../../../static/icons/play-button.svg';
|
||||
import { html } from '../../types/html';
|
||||
import { ResponsiveImage } from '../../types/responsive-image';
|
||||
import { Image } from '../image-viewer/image/image.html';
|
||||
import './preview.scss';
|
||||
|
||||
export const generate = ({
|
||||
alt,
|
||||
poster,
|
||||
}: {
|
||||
alt: string;
|
||||
poster: ResponsiveImage;
|
||||
}): html => `
|
||||
<div class="preview">
|
||||
${Image({
|
||||
image: poster,
|
||||
alt,
|
||||
container: true,
|
||||
isIgnoredByImageViewer: true,
|
||||
})}
|
||||
<div class="overlay">
|
||||
<div class="loading">${loading}</div>
|
||||
<iframe title="${alt}" allowfullscreen loading="lazy"></iframe>
|
||||
<div class="start-button">${play}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import { ResponsiveImage } from '../../types/responsive-image';
|
||||
import { PageElement } from '../page-element';
|
||||
import { generate } from './preview.html';
|
||||
|
||||
export class Preview extends PageElement {
|
||||
public constructor(poster: ResponsiveImage, private readonly url: string, alt: string) {
|
||||
super(generate({ poster, alt }));
|
||||
this.url += '?portfolioView';
|
||||
this.query('.start-button').addEventListener('click', this.loadContent.bind(this));
|
||||
}
|
||||
|
||||
protected initialize() {
|
||||
new IntersectionObserver((e) => {
|
||||
if (!e[0].isIntersecting) {
|
||||
this.unloadContent();
|
||||
}
|
||||
}).observe(this.htmlRoot.parentElement!);
|
||||
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
public loadContent() {
|
||||
this.htmlRoot.classList.add('loaded');
|
||||
(this.query('iframe') as HTMLIFrameElement).src = this.url;
|
||||
}
|
||||
|
||||
public unloadContent() {
|
||||
this.htmlRoot.classList.remove('loaded');
|
||||
(this.query('iframe') as HTMLIFrameElement).src = '';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
import { html } from '../../types/html';
|
||||
import { Preview } from '../preview/preview';
|
||||
import { Video } from '../video/video';
|
||||
import { Figure } from '../figure/figure';
|
||||
|
||||
export interface TimelineElementParameters {
|
||||
date: string;
|
||||
figure: html | Video | Preview;
|
||||
figure: Figure;
|
||||
title: string;
|
||||
description: string;
|
||||
more?: Array<html>;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@
|
|||
background-color: var(--blurred-card-color);
|
||||
transition: background-color var(--transition-time);
|
||||
|
||||
> .figure-container {
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
}
|
||||
|
||||
> .lower {
|
||||
> * {
|
||||
padding: 0 var(--normal-margin);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { titleToFragment } from '../../helper/title-to-fragment';
|
||||
import { BorderedImage } from '../figure/bordered-image/bordered-image';
|
||||
import { ImageViewer } from '../image-viewer/image-viewer';
|
||||
import { PageElement } from '../page-element';
|
||||
import { TimelineElementParameters } from './timeline-element-parameters';
|
||||
import { generate } from './timeline-element.html';
|
||||
|
|
@ -10,7 +12,8 @@ export class TimelineElement extends PageElement {
|
|||
public constructor(
|
||||
private timelineElement: TimelineElementParameters,
|
||||
private readonly showMore: string,
|
||||
private readonly showLess: string
|
||||
private readonly showLess: string,
|
||||
imageViewer?: ImageViewer
|
||||
) {
|
||||
super(generate(timelineElement, showMore));
|
||||
|
||||
|
|
@ -24,12 +27,11 @@ export class TimelineElement extends PageElement {
|
|||
);
|
||||
}
|
||||
|
||||
this.attachElementByReplacing(
|
||||
'.figure',
|
||||
timelineElement.figure instanceof PageElement
|
||||
? timelineElement.figure
|
||||
: new PageElement(timelineElement.figure)
|
||||
);
|
||||
if (timelineElement.figure instanceof BorderedImage) {
|
||||
timelineElement.figure.imageViewer = imageViewer;
|
||||
}
|
||||
|
||||
this.attachElementByReplacing('.figure', timelineElement.figure);
|
||||
}
|
||||
|
||||
protected initialize(): void {
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
import play from '../../../static/icons/play-button.svg';
|
||||
import { html } from '../../types/html';
|
||||
import { Image } from '../image-viewer/image/image.html';
|
||||
import { VideoParameters } from './video-parameters';
|
||||
import './video.scss';
|
||||
|
||||
export const generate = ({
|
||||
webm,
|
||||
mp4,
|
||||
poster,
|
||||
invertButton,
|
||||
altText,
|
||||
}: VideoParameters): html => `
|
||||
<div class="figure-container video-container" style="padding-top:${
|
||||
(poster.height / poster.width) * 100
|
||||
}%">
|
||||
${Image({
|
||||
image: poster,
|
||||
alt: altText,
|
||||
isIgnoredByImageViewer: true,
|
||||
})}
|
||||
<video playsinline controls preload="none">
|
||||
<source src="${webm}" type="video/webm"/>
|
||||
<source src="${mp4}" type="video/mp4"/>
|
||||
</video>
|
||||
<div class="start-button ${invertButton ? 'inverted' : ''}" tabindex=0>${play}</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
@use '../../style/mixins' as *;
|
||||
|
||||
.video-container {
|
||||
&.loaded > .start-button,
|
||||
&:not(.loaded) > video {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue