pc setup v2: one-screen layout with a time slider, photo grid and lightbox
All checks were successful
Deploy production / deploy (push) Successful in 1m7s
All checks were successful
Deploy production / deploy (push) Successful in 1m7s
- hardware: slots, sections, usage, install/removal dates, images and a hidden flag on components and devices; setup_photos table; setup_overview view gains the new columns - data: hide the 2021 friends-PC build and the wrong 140mm / unknown fans (kept, not deleted); 7x SL-INF + 3 Kraken stock fans; mice, audio, desk extras; MacBook Pro 16 M2 Pro 1 TB; dates for every swap so the slider can rebuild the setup on any day - self-hosted product images in static/hardware (webp + thumbs) - prices and order details are owner-only (in a popover)
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
import { isOwner, requireOwner } from '#lib/server/owner.js';
|
||||
import { deleteRow, loadSetup, saveDevice, saveGame, savePart } from '#lib/server/hardware.js';
|
||||
import {
|
||||
addPhoto,
|
||||
deletePhoto,
|
||||
deleteRow,
|
||||
loadSetup,
|
||||
saveDevice,
|
||||
saveGame,
|
||||
savePart
|
||||
} from '#lib/server/hardware.js';
|
||||
import { deleteObject, setupImageKey, uploadImage } from '#lib/server/r2.js';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
@@ -7,15 +16,16 @@ import type { Actions, PageServerLoad } from './$types';
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const owner = isOwner(event);
|
||||
if (owner) event.setHeaders({ 'cache-control': 'private, no-store' });
|
||||
const { devices, games } = await loadSetup(owner);
|
||||
const { devices, games, photos } = await loadSetup(owner);
|
||||
return {
|
||||
owner,
|
||||
devices,
|
||||
games,
|
||||
photos,
|
||||
seo: {
|
||||
title: 'PC setup',
|
||||
description:
|
||||
'Every part in my PC with specs and prices, my other devices and servers, the planned next build and my mouse sensitivities.'
|
||||
'My PC, desk and devices on one screen, with a time slider that shows the setup on any day since 2021, plus the planned next build and my mouse sensitivities.'
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -49,5 +59,33 @@ export const actions: Actions = {
|
||||
deleteGame: async (event) => {
|
||||
requireOwner(event);
|
||||
return run(deleteRow('game', await event.request.formData()));
|
||||
},
|
||||
addPhoto: async (event) => {
|
||||
requireOwner(event);
|
||||
const form = await event.request.formData();
|
||||
const photo = form.get('photo');
|
||||
if (
|
||||
!(photo instanceof File) ||
|
||||
!['image/jpeg', 'image/png', 'image/webp'].includes(photo.type) ||
|
||||
!photo.size ||
|
||||
photo.size > 15 * 1024 * 1024
|
||||
)
|
||||
return fail(400, { message: 'Choose a JPEG, PNG or WebP image up to 15 MB.' });
|
||||
let url: string;
|
||||
try {
|
||||
url = (await uploadImage(photo, 'setup')).publicUrl;
|
||||
} catch (cause) {
|
||||
console.error('setup photo upload failed', cause);
|
||||
return fail(503, { message: 'Image storage is unavailable.' });
|
||||
}
|
||||
return run(addPhoto(url, form));
|
||||
},
|
||||
deletePhoto: async (event) => {
|
||||
requireOwner(event);
|
||||
const r = await deletePhoto(await event.request.formData());
|
||||
if (!r.ok) return fail(400, { message: r.message });
|
||||
const key = r.url ? setupImageKey(r.url) : null;
|
||||
if (key) await deleteObject(key).catch(() => {});
|
||||
return { saved: true };
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user