This commit is contained in:
Andras Schmelczer 2026-05-31 11:13:13 +01:00
parent ff6c7f6f68
commit 35a962935c
58 changed files with 5642 additions and 151 deletions

View file

@ -7,12 +7,15 @@ on:
branches: ['main']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: 'pages'
cancel-in-progress: false
group: 'photos-${{ github.ref }}'
cancel-in-progress: true
jobs:
build:
validate:
runs-on: docker
steps:
@ -21,18 +24,46 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '12'
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: |
npm install
run: npm ci
- name: Check
run: npm run check
- name: Build
run: |
npm run build
run: npm run build
- name: Copy files to nginx pages mount
- name: Install Playwright browser
run: npx playwright install --with-deps chromium
- name: End-to-end smoke test
run: npm run test:e2e
deploy:
runs-on: docker
needs: validate
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Copy build to host pages mount
run: |
apt update && apt install -y rsync
rsync -a --delete --mkpath --chmod=ugo=rwx dist/ /pages/photos/
mkdir -p /pages/photos
rsync -a --delete dist/ /pages/photos/

1
.gitattributes vendored
View file

@ -1 +0,0 @@
og-image.jpg filter=lfs diff=lfs merge=lfs -text

5
.gitignore vendored
View file

@ -1,5 +1,8 @@
node_modules
dist
target
package-lock.json
.DS_Store
public/static/photos
src/generated
playwright-report
test-results

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
22.13.0

26
custom.d.ts vendored
View file

@ -1,26 +0,0 @@
declare module '*.svg' {
const content: string;
export default content;
}
declare module '*.jpg' {
import { ResponsiveImage } from 'src/model/responsive-image';
const content: ResponsiveImage;
export default content;
}
declare module '*.jpeg' {
import { ResponsiveImage } from 'src/model/responsive-image';
const content: ResponsiveImage;
export default content;
}
declare module '*.txt' {
const content: string;
export default content;
}
declare module '*.html' {
const content: string;
export default content;
}

38
eslint.config.js Normal file
View file

@ -0,0 +1,38 @@
import js from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default [
{
ignores: [
'dist/**',
'public/static/photos/**',
'src/generated/**',
'playwright-report/**',
'test-results/**',
],
},
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.ts'],
languageOptions: {
parser: tseslint.parser,
globals: {
...globals.browser,
},
},
rules: {
'no-undef': 'off',
},
},
{
files: ['**/*.js', '**/*.mjs'],
languageOptions: {
sourceType: 'module',
globals: {
...globals.node,
},
},
},
];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 243 KiB

Before After
Before After

5495
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

BIN
public/og-image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

4
public/robots.txt Normal file
View file

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://schmelczer.dev/photos/sitemap.xml

15
public/site.webmanifest Normal file
View file

@ -0,0 +1,15 @@
{
"name": "Photos - András Schmelczer",
"short_name": "Photos",
"start_url": ".",
"display": "standalone",
"background_color": "#eeeeee",
"theme_color": "#a63446",
"icons": [
{
"src": "favicon.svg",
"sizes": "64x64",
"type": "image/svg+xml"
}
]
}

6
public/sitemap.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://schmelczer.dev/photos/</loc>
</url>
</urlset>

View file

@ -1,22 +0,0 @@
import { ResponsiveImage } from '../model/responsive-image';
import { last } from './last';
export const createImage = (
image: ResponsiveImage,
alt: string,
tabIndex: number,
imageScreenRatio = 0.25
): HTMLImageElement => {
const img = new Image(image.width, image.height);
img.tabIndex = tabIndex;
img.srcset = image.srcSet;
img.sizes =
image.images
.map(d => `(max-width: ${d.width / imageScreenRatio}px) ${d.width}px,`)
.join('\n') + `\n${last(image.images).width}px`;
img.src = last(image.images)?.path;
img.alt = alt;
return img;
};

View file

@ -1,2 +0,0 @@
export const last = <T>(list: ArrayLike<T>): T =>
list.length >= 1 ? list[list.length - 1] : undefined;

View file

@ -1,35 +1,19 @@
import './index.scss';
import './no-change/404.html';
import './no-change/robots.txt';
import { Photos } from './photos';
import { photos } from './generated/photos';
import { PhotoGallery, requiredElement } from './photos';
// @ts-ignore
const images = require.context('./pictures', true, /.jpg$/);
const imagePath = name => images(name, true);
document.documentElement.classList.add('js');
const addSupportForTabNavigation = () =>
(document.onkeydown = e => {
if (e.key === ' ') {
(document.activeElement as HTMLElement)?.click();
e.preventDefault();
}
});
const sizeFrame = () => {
const container = document.querySelector('#frame-container') as HTMLElement;
const image = container.querySelector('img');
image.style.maxWidth = container.clientWidth + 'px';
image.style.left = container.offsetLeft + container.clientWidth / 2 + 'px';
};
new Photos(
images.keys().map(k => imagePath(k)),
document.querySelector('#landscapes'),
document.querySelector('#portraits'),
document.querySelector('#frame-image')
const gallery = requiredElement<HTMLElement>('#gallery', HTMLElement);
const frame = requiredElement<HTMLElement>('#frame-content', HTMLElement);
const toggle = requiredElement<HTMLButtonElement>(
'#slideshow-toggle',
HTMLButtonElement
);
addSupportForTabNavigation();
window.addEventListener('resize', sizeFrame);
sizeFrame();
new PhotoGallery({
photos,
gallery,
frame,
toggle,
});

View file

@ -1,12 +0,0 @@
export type ResponsiveImage = {
srcSet: string;
src: string;
placeholder: string;
width: number;
height: number;
images: Array<{
path: string;
width: number;
height: number;
}>;
};

View file

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Not found</title>
<meta name="theme-color" content="#b7455e" />
<meta name="viewport" content="initial-scale=1.0" />
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: #b7455e;
}
h1 {
font-family: "Roboto", "Helvetica Neue", sans-serif;
font-weight: 100;
font-size: 3rem;
color: white;
text-align: center;
padding: 0.5rem;
}
</style>
</head>
<body>
<h1>The requested resource cannot be found.</h1>
</body>
</html>

View file

@ -1,2 +0,0 @@
User-agent: *
Allow: /

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 MiB

After

Width:  |  Height:  |  Size: 3 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 MiB

After

Width:  |  Height:  |  Size: 7.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 MiB

After

Width:  |  Height:  |  Size: 4.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 MiB

After

Width:  |  Height:  |  Size: 2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 482 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 288 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 265 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 189 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 274 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 308 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

After

Width:  |  Height:  |  Size: 346 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 KiB

After

Width:  |  Height:  |  Size: 462 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 429 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 436 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 392 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 264 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

After

Width:  |  Height:  |  Size: 406 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 KiB

After

Width:  |  Height:  |  Size: 437 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 820 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

After

Width:  |  Height:  |  Size: 572 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 KiB

After

Width:  |  Height:  |  Size: 691 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 KiB

After

Width:  |  Height:  |  Size: 920 KiB

Before After
Before After

View file

@ -1,11 +1,26 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": false,
"module": "es6",
"target": "es5",
"sourceMap": true,
"allowJs": true,
"downlevelIteration": true
}
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noUncheckedIndexedAccess": true,
"types": ["vite/client", "vitest/globals"]
},
"include": [
"src/**/*.ts",
"src/**/*.json",
"vite.config.ts",
"eslint.config.js"
]
}