Add webp
This commit is contained in:
parent
848ccf0ff3
commit
e291817264
10 changed files with 159 additions and 60 deletions
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
|
@ -1,8 +1,11 @@
|
||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"andras",
|
"andras",
|
||||||
|
"decla",
|
||||||
"favicons",
|
"favicons",
|
||||||
|
"forex",
|
||||||
"schmelczer",
|
"schmelczer",
|
||||||
"webm"
|
"webm",
|
||||||
|
"webp"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
26
custom.d.ts
vendored
26
custom.d.ts
vendored
|
|
@ -3,13 +3,37 @@ declare module '*.svg' {
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg' {
|
||||||
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
|
const content: ResponsiveImage;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg?format=webp' {
|
||||||
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
|
const content: ResponsiveImage;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg?format=jpg' {
|
||||||
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
|
const content: ResponsiveImage;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
declare module '*.png' {
|
declare module '*.png' {
|
||||||
import { ResponsiveImage } from 'src/types/responsive-image';
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
const content: ResponsiveImage;
|
const content: ResponsiveImage;
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.jpg' {
|
declare module '*.png?format=webp' {
|
||||||
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
|
const content: ResponsiveImage;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.png?format=jpg' {
|
||||||
import { ResponsiveImage } from 'src/types/responsive-image';
|
import { ResponsiveImage } from 'src/types/responsive-image';
|
||||||
const content: ResponsiveImage;
|
const content: ResponsiveImage;
|
||||||
export default content;
|
export default content;
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"resolve-url-loader": "^3.1.1",
|
"resolve-url-loader": "^3.1.1",
|
||||||
"responsive-loader": "^1.2.0",
|
"responsive-loader": "^2.2.0",
|
||||||
"sass": "^1.26.10",
|
"sass": "^1.26.10",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"sharp": "^0.23.4",
|
"sharp": "^0.23.4",
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,36 @@ import { html } from '../../../types/html';
|
||||||
|
|
||||||
export const generate = ({
|
export const generate = ({
|
||||||
sizes,
|
sizes,
|
||||||
image,
|
imageWebP,
|
||||||
|
imageJpeg,
|
||||||
alt,
|
alt,
|
||||||
container,
|
container,
|
||||||
}: {
|
}: {
|
||||||
sizes: string;
|
sizes: string;
|
||||||
image: ResponsiveImage;
|
imageWebP: ResponsiveImage;
|
||||||
|
imageJpeg: ResponsiveImage;
|
||||||
alt: string;
|
alt: string;
|
||||||
container: boolean;
|
container: boolean;
|
||||||
}): html => `
|
}): html => `
|
||||||
${container ? `<div class="figure-container">` : ''}
|
${container ? `<div class="figure-container">` : ''}
|
||||||
<img tabindex="0"
|
<picture loading="lazy">
|
||||||
loading="lazy"
|
<source
|
||||||
srcset="${image.srcSet}"
|
srcset="${imageWebP.srcSet}"
|
||||||
sizes="${sizes}"
|
sizes="${sizes}"
|
||||||
width="${image.width}"
|
width="${imageWebP.width}"
|
||||||
height="${image.height}"
|
height="${imageWebP.height}"
|
||||||
src="${last(image.images)?.path}"
|
|
||||||
alt="${alt}"
|
alt="${alt}"
|
||||||
/>
|
/>
|
||||||
|
<img
|
||||||
|
tabindex="0"
|
||||||
|
loading="lazy"
|
||||||
|
srcset="${imageJpeg.srcSet}"
|
||||||
|
sizes="${sizes}"
|
||||||
|
width="${imageJpeg.width}"
|
||||||
|
height="${imageJpeg.height}"
|
||||||
|
src="${last(imageJpeg.images)?.path}"
|
||||||
|
alt="${alt}"
|
||||||
|
/>
|
||||||
|
</picture>
|
||||||
${container ? `</div>` : ''}
|
${container ? `</div>` : ''}
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,22 @@ import { ResponsiveImage } from '../../../types/responsive-image';
|
||||||
export class Image extends PageElement {
|
export class Image extends PageElement {
|
||||||
private static readonly imageScreenRatio = 0.8;
|
private static readonly imageScreenRatio = 0.8;
|
||||||
|
|
||||||
public constructor(image: ResponsiveImage, alt: string, container = true) {
|
public constructor(
|
||||||
|
imageWebP: ResponsiveImage,
|
||||||
|
imageJpeg: ResponsiveImage,
|
||||||
|
alt: string,
|
||||||
|
container = true
|
||||||
|
) {
|
||||||
super(
|
super(
|
||||||
createElement(generate({ image, alt, container, sizes: Image.getSizes(image) }))
|
createElement(
|
||||||
|
generate({
|
||||||
|
imageWebP,
|
||||||
|
imageJpeg,
|
||||||
|
alt,
|
||||||
|
container,
|
||||||
|
sizes: Image.getSizes(imageWebP),
|
||||||
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,15 @@ import { ResponsiveImage } from '../../../types/responsive-image';
|
||||||
import { OnLoadEvent } from '../../../events/concrete-events/on-load-event';
|
import { OnLoadEvent } from '../../../events/concrete-events/on-load-event';
|
||||||
|
|
||||||
export class Preview extends PageElement {
|
export class Preview extends PageElement {
|
||||||
public constructor(poster: ResponsiveImage, private readonly url: string, alt: string) {
|
public constructor(
|
||||||
|
posterWebP: ResponsiveImage,
|
||||||
|
posterJpeg: ResponsiveImage,
|
||||||
|
private readonly url: string,
|
||||||
|
alt: string
|
||||||
|
) {
|
||||||
super(createElement(generate({ alt })));
|
super(createElement(generate({ alt })));
|
||||||
this.url += '?portfolioView';
|
this.url += '?portfolioView';
|
||||||
this.attachElementByReplacing('.poster', new Image(poster, alt));
|
this.attachElementByReplacing('.poster', new Image(posterWebP, posterJpeg, alt));
|
||||||
this.query('.load-button').addEventListener('click', this.loadContent.bind(this));
|
this.query('.load-button').addEventListener('click', this.loadContent.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
121
src/portfolio.ts
121
src/portfolio.ts
|
|
@ -11,29 +11,54 @@ import { Anchor } from './page/basics/anchor/anchor';
|
||||||
import { Body } from './page/body/body';
|
import { Body } from './page/body/body';
|
||||||
import { ImageAnchorFactory } from './page/basics/image-anchor/image-anchor';
|
import { ImageAnchorFactory } from './page/basics/image-anchor/image-anchor';
|
||||||
import { Preview } from './page/basics/preview/preview';
|
import { Preview } from './page/basics/preview/preview';
|
||||||
import me from './static/media/me.jpg';
|
|
||||||
import declared from './static/media/decla-red.png';
|
import meJpeg from './static/media/me.jpg?format=jpg';
|
||||||
import forexMP4 from './static/media/forex.mp4';
|
import meWebP from './static/media/me.jpg?format=webp';
|
||||||
import forexWEBM from './static/media/forex.webm';
|
|
||||||
import thesis from './static/media/andras-schmelczer-thesis.pdf';
|
import declaredJpeg from './static/media/decla-red.png?format=jpg';
|
||||||
import adAstraMP4 from './static/media/ad_astra_720.mp4';
|
import declaredWebP from './static/media/decla-red.png?format=webp';
|
||||||
import cvIcon from './static/icons/cv.svg';
|
|
||||||
import adAstraWEBM from './static/media/ad_astra_720.webm';
|
import sdf2dJpeg from './static/media/sdf2d.png?format=jpg';
|
||||||
import ad_astra_index from './static/media/ad_astra.jpg';
|
import sdf2dWebP from './static/media/sdf2d.png?format=webp';
|
||||||
import myNotes from './static/media/my-notes.png';
|
|
||||||
import sdf2d from './static/media/sdf2d.png';
|
import myNotesJpeg from './static/media/my-notes.png?format=jpg';
|
||||||
import processSimulator from './static/media/process-simulator.jpg';
|
import myNotesWebP from './static/media/my-notes.png?format=webp';
|
||||||
import processSimulatorInput from './static/media/process-simulator-input.jpg';
|
|
||||||
import citySimulation from './static/media/simulation.jpg';
|
import processSimulatorJpeg from './static/media/process-simulator.jpg?format=jpg';
|
||||||
import colour from './static/media/color.jpg';
|
import processSimulatorWebP from './static/media/process-simulator.jpg?format=webp';
|
||||||
import platform from './static/media/platform.png';
|
|
||||||
import photos from './static/media/photos.jpg';
|
import processSimulatorInputJpeg from './static/media/process-simulator-input.jpg?format=jpg';
|
||||||
import led from './static/media/led.jpg';
|
import processSimulatorInputWebP from './static/media/process-simulator-input.jpg?format=webp';
|
||||||
import cvEnglish from './static/cv/cv_andras_schmelczer.pdf';
|
|
||||||
import ledMP4 from './static/media/led.mp4';
|
import citySimulationJpeg from './static/media/simulation.jpg?format=jpg';
|
||||||
import ledWEBM from './static/media/led.webm';
|
import citySimulationWebP from './static/media/simulation.jpg?format=webp';
|
||||||
|
|
||||||
|
import colourJpeg from './static/media/color.jpg?format=jpg';
|
||||||
|
import colourWebP from './static/media/color.jpg?format=webp';
|
||||||
|
|
||||||
|
import platformJpeg from './static/media/platform.png?format=jpg';
|
||||||
|
import platformWebP from './static/media/platform.png?format=webp';
|
||||||
|
|
||||||
|
import photosJpeg from './static/media/photos.jpg?format=jpg';
|
||||||
|
import photosWebP from './static/media/photos.jpg?format=webp';
|
||||||
|
|
||||||
|
import cvEnglish from './static/media/cv_andras_schmelczer.pdf';
|
||||||
|
import thesis from './static/media/andras_schmelczer_thesis.pdf';
|
||||||
|
|
||||||
|
import forexMp4 from './static/media/forex.mp4';
|
||||||
|
import forexWebM from './static/media/forex.webm';
|
||||||
|
|
||||||
|
import adAstraPoster from './static/media/ad_astra.jpg?format=jpg';
|
||||||
|
import adAstraMp4 from './static/media/ad_astra_720.mp4';
|
||||||
|
import adAstraWebM from './static/media/ad_astra_720.webm';
|
||||||
|
|
||||||
|
import ledPoster from './static/media/led.jpg?format=jpg';
|
||||||
|
import ledMp4 from './static/media/led.mp4';
|
||||||
|
import ledWebM from './static/media/led.webm';
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
export const create = () => {
|
export const create = () => {
|
||||||
const GitHub = ImageAnchorFactory(githubIcon, 'Open on GitHub');
|
const GitHub = ImageAnchorFactory(githubIcon, 'Open on GitHub');
|
||||||
|
|
@ -44,7 +69,7 @@ export const create = () => {
|
||||||
imageViewer: new PageImageViewer(),
|
imageViewer: new PageImageViewer(),
|
||||||
header: new PageHeader({
|
header: new PageHeader({
|
||||||
name: `András Schmelczer`,
|
name: `András Schmelczer`,
|
||||||
picture: new Image(me, `a picture of me`, false),
|
picture: new Image(meWebP, meJpeg, `a picture of me`, false),
|
||||||
about: [
|
about: [
|
||||||
new Text(`I have always been fascinated by the engineering feats that surround us and pervade every aspect
|
new Text(`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
|
||||||
|
|
@ -62,7 +87,8 @@ export const create = () => {
|
||||||
title: `Multiplayer game`,
|
title: `Multiplayer game`,
|
||||||
date: `2020 Autumn`,
|
date: `2020 Autumn`,
|
||||||
figure: new Preview(
|
figure: new Preview(
|
||||||
declared,
|
declaredWebP,
|
||||||
|
declaredJpeg,
|
||||||
'https://decla.red',
|
'https://decla.red',
|
||||||
'The website of the video game'
|
'The website of the video game'
|
||||||
),
|
),
|
||||||
|
|
@ -88,7 +114,8 @@ export const create = () => {
|
||||||
title: `2D ray tracing`,
|
title: `2D ray tracing`,
|
||||||
date: `2020 Autumn`,
|
date: `2020 Autumn`,
|
||||||
figure: new Preview(
|
figure: new Preview(
|
||||||
sdf2d,
|
sdf2dWebP,
|
||||||
|
sdf2dJpeg,
|
||||||
'https://sdf2d.schmelczer.dev',
|
'https://sdf2d.schmelczer.dev',
|
||||||
'A webpage showcasing the SDF-2D project.'
|
'A webpage showcasing the SDF-2D project.'
|
||||||
),
|
),
|
||||||
|
|
@ -112,9 +139,9 @@ export const create = () => {
|
||||||
title: `Video game on an ATtiny85`,
|
title: `Video game on an ATtiny85`,
|
||||||
date: `2020 Spring`,
|
date: `2020 Spring`,
|
||||||
figure: new Video(
|
figure: new Video(
|
||||||
last(ad_astra_index.images).path,
|
last(adAstraPoster.images).path,
|
||||||
adAstraMP4,
|
adAstraMp4,
|
||||||
adAstraWEBM,
|
adAstraWebM,
|
||||||
`controls playsinline preload="none"`
|
`controls playsinline preload="none"`
|
||||||
),
|
),
|
||||||
description: new Text(`A simple game engine with a sample game set in space. The greatest challenge was to overcome
|
description: new Text(`A simple game engine with a sample game set in space. The greatest challenge was to overcome
|
||||||
|
|
@ -142,8 +169,8 @@ export const create = () => {
|
||||||
date: `2019 Autumn`,
|
date: `2019 Autumn`,
|
||||||
figure: new Video(
|
figure: new Video(
|
||||||
null,
|
null,
|
||||||
forexMP4,
|
forexMp4,
|
||||||
forexWEBM,
|
forexWebM,
|
||||||
`autoplay loop muted playsinline controls`
|
`autoplay loop muted playsinline controls`
|
||||||
),
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
|
|
@ -167,7 +194,11 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2019 November`,
|
date: `2019 November`,
|
||||||
title: `My Notes`,
|
title: `My Notes`,
|
||||||
figure: new Image(myNotes, `two screenshots of the application`),
|
figure: new Image(
|
||||||
|
myNotesWebP,
|
||||||
|
myNotesJpeg,
|
||||||
|
`two screenshots of the application`
|
||||||
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`A minimalist note organizer and editor powered by Markwon.`
|
`A minimalist note organizer and editor powered by Markwon.`
|
||||||
),
|
),
|
||||||
|
|
@ -189,7 +220,11 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2018 October - November`,
|
date: `2018 October - November`,
|
||||||
title: `Simulating the cooling system of a nuclear facility`,
|
title: `Simulating the cooling system of a nuclear facility`,
|
||||||
figure: new Image(processSimulator, `a screenshot of the simulator`),
|
figure: new Image(
|
||||||
|
processSimulatorWebP,
|
||||||
|
processSimulatorJpeg,
|
||||||
|
`a screenshot of the simulator`
|
||||||
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`Dynamically calculating the temperatures and flow velocities
|
`Dynamically calculating the temperatures and flow velocities
|
||||||
in a fluid-based cooling system based on a simple model.`
|
in a fluid-based cooling system based on a simple model.`
|
||||||
|
|
@ -212,7 +247,11 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2018 October - November`,
|
date: `2018 October - November`,
|
||||||
title: `Graph editing application`,
|
title: `Graph editing application`,
|
||||||
figure: new Image(processSimulatorInput, `a picture of the simulator's UI`),
|
figure: new Image(
|
||||||
|
processSimulatorInputWebP,
|
||||||
|
processSimulatorInputJpeg,
|
||||||
|
`a picture of the simulator's UI`
|
||||||
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`An intuitive editor to create and edit input files for the nuclear facility simulator.`
|
`An intuitive editor to create and edit input files for the nuclear facility simulator.`
|
||||||
),
|
),
|
||||||
|
|
@ -231,7 +270,11 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2018 July - August`,
|
date: `2018 July - August`,
|
||||||
title: `City simulation`,
|
title: `City simulation`,
|
||||||
figure: new Image(citySimulation, `a picture of a low-poly city`),
|
figure: new Image(
|
||||||
|
citySimulationWebP,
|
||||||
|
citySimulationJpeg,
|
||||||
|
`a picture of a low-poly city`
|
||||||
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`Simulating a city where car crashes are more frequent than usual.`
|
`Simulating a city where car crashes are more frequent than usual.`
|
||||||
),
|
),
|
||||||
|
|
@ -260,7 +303,7 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2018 June`,
|
date: `2018 June`,
|
||||||
title: `Photo colour grader`,
|
title: `Photo colour grader`,
|
||||||
figure: new Image(colour, `a picture of the app`),
|
figure: new Image(colourWebP, colourJpeg, `a picture of the app`),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`An innovative (at least I thought so) colour grader web application.`
|
`An innovative (at least I thought so) colour grader web application.`
|
||||||
),
|
),
|
||||||
|
|
@ -284,7 +327,7 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2017 autumn`,
|
date: `2017 autumn`,
|
||||||
title: `Platform game`,
|
title: `Platform game`,
|
||||||
figure: new Image(platform, `a picture of the app`),
|
figure: new Image(platformWebP, platformJpeg, `a picture of the app`),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
`A 3D game written in C with the help of SDL 1.2 (I haven't heard of GPU programming at the time).`
|
`A 3D game written in C with the help of SDL 1.2 (I haven't heard of GPU programming at the time).`
|
||||||
),
|
),
|
||||||
|
|
@ -300,7 +343,7 @@ export const create = () => {
|
||||||
{
|
{
|
||||||
date: `2016 summer`,
|
date: `2016 summer`,
|
||||||
title: `Photos`,
|
title: `Photos`,
|
||||||
figure: new Image(photos, `a picture of the website`),
|
figure: new Image(photosWebP, photosJpeg, `a picture of the website`),
|
||||||
description: new Text(`A simple web page where you can view my photos.`),
|
description: new Text(`A simple web page where you can view my photos.`),
|
||||||
links: [new Open('https://photo.schmelczer.dev')],
|
links: [new Open('https://photo.schmelczer.dev')],
|
||||||
},
|
},
|
||||||
|
|
@ -308,9 +351,9 @@ export const create = () => {
|
||||||
date: `2016 spring`,
|
date: `2016 spring`,
|
||||||
title: `Lights synchronised to music`,
|
title: `Lights synchronised to music`,
|
||||||
figure: new Video(
|
figure: new Video(
|
||||||
last(led.images).path,
|
last(ledPoster.images).path,
|
||||||
ledMP4,
|
ledMp4,
|
||||||
ledWEBM,
|
ledWebM,
|
||||||
`controls playsinline preload="none"`
|
`controls playsinline preload="none"`
|
||||||
),
|
),
|
||||||
description: new Text(
|
description: new Text(
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ module.exports = (env, argv) => ({
|
||||||
options: {
|
options: {
|
||||||
adapter: Sharp,
|
adapter: Sharp,
|
||||||
outputPath: 'static/',
|
outputPath: 'static/',
|
||||||
sizes: [200, 400, 800, 1200, 2000],
|
sizes: [200, 400, 800, 1200, 1600, 2000],
|
||||||
placeholder: false,
|
format: 'webp',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -122,7 +122,6 @@ module.exports = (env, argv) => ({
|
||||||
test: /\.svg$/i,
|
test: /\.svg$/i,
|
||||||
use: 'raw-loader',
|
use: 'raw-loader',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
test: /\.scss$/i,
|
test: /\.scss$/i,
|
||||||
use: [
|
use: [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue