Initial commit: Fast Inventory app
Monorepo with Express + SQLite backend and Vite + React frontend. Features: item CRUD, file uploads with thumbnails, soft delete, item duplication with file copying, autocomplete inputs, stats dashboard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
42
server/src/resize.ts
Normal file
42
server/src/resize.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import sharp from 'sharp';
|
||||
import { join, parse } from 'path';
|
||||
import { UPLOADS_DIR } from './middleware/upload.js';
|
||||
|
||||
interface VariantSpec {
|
||||
suffix: string;
|
||||
maxDimension: number;
|
||||
}
|
||||
|
||||
const VARIANTS: VariantSpec[] = [
|
||||
{ suffix: '_thumb', maxDimension: 300 },
|
||||
{ suffix: '_medium', maxDimension: 768 },
|
||||
{ suffix: '_large', maxDimension: 1920 },
|
||||
];
|
||||
|
||||
const RESIZABLE_MIMES = new Set([
|
||||
'image/jpeg', 'image/png', 'image/webp', 'image/heic',
|
||||
]);
|
||||
|
||||
export function isResizable(mimeType: string): boolean {
|
||||
return RESIZABLE_MIMES.has(mimeType);
|
||||
}
|
||||
|
||||
export async function generateVariants(storedName: string): Promise<void> {
|
||||
const { name, ext } = parse(storedName);
|
||||
const sourcePath = join(UPLOADS_DIR, storedName);
|
||||
|
||||
for (const variant of VARIANTS) {
|
||||
const outPath = join(UPLOADS_DIR, `${name}${variant.suffix}${ext}`);
|
||||
await sharp(sourcePath)
|
||||
.resize(variant.maxDimension, variant.maxDimension, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.toFile(outPath);
|
||||
}
|
||||
}
|
||||
|
||||
export function getVariantFilenames(storedName: string): string[] {
|
||||
const { name, ext } = parse(storedName);
|
||||
return VARIANTS.map(v => `${name}${v.suffix}${ext}`);
|
||||
}
|
||||
Reference in New Issue
Block a user