diff --git a/.gitignore b/.gitignore index c20fb2d..2d01eaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *.swp *.swo dist/ -img/* -!img/data.json +img/ node_modules .DS_Store diff --git a/README.md b/README.md index a33b0bb..36cfe56 100644 --- a/README.md +++ b/README.md @@ -3,22 +3,3 @@ ## [ski.aarongutierrez.com](https://ski.aarongutierrez.com) A portfolio site for my ski photography. Built with TypeScript, React, Vite, and <3 - -## Commands - -- `vp dev` starts the Vite+ dev server. -- `vp check` runs formatting, linting, and type checks through Vite+. -- `vp fmt` formats supported source files through Oxfmt. -- `vp lint` runs Oxlint with type-aware checks. -- `vp build` creates a production build in `dist/`. -- `npm run images` regenerates hashed originals and resized image variants from `img/original/`, then prepends newly discovered images to `img/data.json` under a placeholder set you can fill in. -- `npm run deploy` builds the app, uploads `dist/` and `img/` to S3, ensures CloudFront serves `index.html`, and invalidates `/` plus `/index.html`. - -React Compiler is enabled through the Vite React plugin, so local dev and production builds both run with the compiler transform. - -## Deploy Prerequisites - -- The publish script expects AWS credentials under the `push` profile. -- Publishing uses the TypeScript script at `scripts/publish.ts`. -- `npm run deploy` executes that script with Node's TypeScript support. -- `npm run images` expects `magick` to be installed and available on your shell path. diff --git a/img/data.json b/data.json similarity index 89% rename from img/data.json rename to data.json index a0d4558..f0e0b1d 100644 --- a/img/data.json +++ b/data.json @@ -1,5 +1,69 @@ { "sets": [ + { + "location": "CMH Galena", + "description": "9-13 April 2026", + "images": [ + { "src": "034c54f978de4454971de80a38d3ce4c.jpg", "width": 4140, "height": 5796 }, + { "src": "36316490902321afd81a30d01e61b824.jpg", "width": 6000, "height": 4000 }, + { "src": "2b6aa4ceaa02f502889ada5ba2ca5f65.jpg", "width": 6000, "height": 4000 }, + { "src": "a204566e2cfeaf45e04e532e0942d53c.jpg", "width": 6031, "height": 3978 }, + { "src": "214f7781f6165cebfa4a371c9385e55e.jpg", "width": 6000, "height": 4000 }, + { "src": "fe2adde96f9b4aab55006d63d8e25ece.jpg", "width": 4000, "height": 6000 }, + { "src": "92c60778d073d934797933c66a1efda2.jpg", "width": 6000, "height": 4000 }, + { "src": "1d59e664286ba9a278c91ee6744e1d39.jpg", "width": 6000, "height": 4000 }, + { "src": "7a403edb2b912574a57567fd19fc9e7c.jpg", "width": 6000, "height": 4000 }, + { "src": "3a83c03b2f3dcca92f1d6f2413765623.jpg", "width": 4898, "height": 4898 }, + { "src": "fcee998aa4a0dae71dfe570f9cba5695.jpg", "width": 6000, "height": 4000 }, + { "src": "659148d22cd0172aba41a3c83a90e519.jpg", "width": 4898, "height": 4898 }, + { "src": "cda0f0232b3bb7ffbe9f6e173b9fb92e.jpg", "width": 5894, "height": 4071 }, + { "src": "e5f1a62bf3ee93b67baadc359cda2df5.jpg", "width": 6000, "height": 4000 }, + { "src": "311ebf3df6508414734b8957b5d08370.jpg", "width": 6000, "height": 4000 }, + { "src": "0366a677757670856d99720be66c6742.jpg", "width": 5796, "height": 4140 }, + { "src": "f414c50697830dc51a442eb8a5362e47.jpg", "width": 5476, "height": 4381 }, + { "src": "577d1d94fa3fe6de58ee9674f236ad49.jpg", "width": 5476, "height": 4381 }, + { "src": "cfd1c29ea111757239f770313aa9a46f.jpg", "width": 5476, "height": 4381 }, + { "src": "431bbd251fa1ef74c98fd82109167a25.jpg", "width": 6000, "height": 4000 }, + { "src": "f2e19a33c202c47b2fb6181ecf0c21aa.jpg", "width": 4898, "height": 4898 }, + { "src": "d35185e04b507a827351605c77c137d1.jpg", "width": 5476, "height": 4381 }, + { "src": "f4b5ecb4c4f4d76d284122db3aa163c5.jpg", "width": 4898, "height": 4898 }, + { "src": "b76d873073da5e4c9f26c4316aa6c05a.jpg", "width": 6000, "height": 4000 }, + { "src": "922ee42075ba8ad22035038fb42f3af7.jpg", "width": 5476, "height": 4381 }, + { "src": "551e2fb306a8846387b2ecaea34a0367.jpg", "width": 5796, "height": 4140 }, + { "src": "7a88a7246acd0e9ea5a696b7842219ab.jpg", "width": 5476, "height": 4381 }, + { "src": "4369819089f066e32fbee40e3233c170.jpg", "width": 5476, "height": 4381 }, + { "src": "bba46dde99a392a2a270f8fe9dac93c6.jpg", "width": 5005, "height": 4795 }, + { "src": "7be73ef716ff231b9df93b053d8d48b5.jpg", "width": 6000, "height": 4000 }, + { "src": "c66f7d3d1e04d1133e61c859e5e36c61.jpg", "width": 6000, "height": 4000 }, + { "src": "a7418014c30b74f4b5edb4282a4c88a1.jpg", "width": 4898, "height": 4898 }, + { "src": "490a0c177e1a9670e578cfb8f5e70d4e.jpg", "width": 6000, "height": 4000 }, + { "src": "95a85e099ec26afa1cfe04e67d0ee3b1.jpg", "width": 5796, "height": 4140 }, + { "src": "6a2b38a014e357c9a3d508cceaad12e1.jpg", "width": 4898, "height": 4898 }, + { "src": "d051e9a6f74e27450449e2f62c2c4343.jpg", "width": 5476, "height": 4381 }, + { "src": "e265e72d18a56823c8a2d852e98ad896.jpg", "width": 6000, "height": 4000 }, + { "src": "75af6d566b05e41d3b374d2466fa95e3.jpg", "width": 5796, "height": 4140 }, + { "src": "302737efead4ac02e8d959339b39fe23.jpg", "width": 6000, "height": 4000 }, + { "src": "15261d5ba57f1c25d91b3bf11165dbe3.jpg", "width": 4898, "height": 4898 }, + { "src": "fcbb4872551f66cb13f76d062b76b799.jpg", "width": 4898, "height": 4898 }, + { "src": "3170b31de96baf96c330b84a30d45f94.jpg", "width": 5476, "height": 4381 }, + { "src": "0384e88762564c5c245f67ede356f641.jpg", "width": 6204, "height": 3868 }, + { "src": "5be673ceee18c3b646628d2a6d4dba40.jpg", "width": 4898, "height": 4898 }, + { "src": "a042509b0dab0c7c7d790d98dad28c84.jpg", "width": 6000, "height": 4000 }, + { "src": "b8c3b11b467199ba96e84f5e56b1adc3.jpg", "width": 5476, "height": 4381 }, + { "src": "d4e966d9d7c4992ba3d0e0a8f92d3a24.jpg", "width": 6000, "height": 4000 }, + { "src": "fa6da6fc5303f2c33b1086c520052a0c.jpg", "width": 4140, "height": 5796 }, + { "src": "d729b5aca68a23f43c21ca178cbceaad.jpg", "width": 6000, "height": 4000 }, + { "src": "0697b314307749e97766e77ca5f15649.jpg", "width": 4898, "height": 4898 }, + { "src": "112c1663ae8705ce448c600e0ee39bd5.jpg", "width": 5796, "height": 4140 }, + { "src": "14a43af492963047be70cab7384dddfb.jpg", "width": 6000, "height": 4000 }, + { "src": "8502cf9b1bdd7727942155811594f8c0.jpg", "width": 5476, "height": 4381 }, + { "src": "8f8e79eb17e14d7a91d6d810390d6756.jpg", "width": 5796, "height": 4140 }, + { "src": "5a33f05eb68873f596aa4348f2c4ca9d.jpg", "width": 6000, "height": 4000 }, + { "src": "afdd57e5077d6d885408419e3d6d74b9.jpg", "width": 5796, "height": 4140 }, + { "src": "26dad3867edd6915257afd7e1dab3c3a.jpg", "width": 6000, "height": 4000 }, + { "src": "c0938aa4a8066f13ac0aa7d06991bb26.jpg", "width": 6000, "height": 4000 } + ] + }, { "location": "CMH Gothics", "description": "2-10 January 2026", diff --git a/scripts/convert.ts b/scripts/convert.ts index 5d2eedd..11b8419 100644 --- a/scripts/convert.ts +++ b/scripts/convert.ts @@ -6,7 +6,7 @@ import { pathToFileURL } from "node:url"; const IMAGE_ROOT = "img"; const ORIGINAL_DIR = path.join(IMAGE_ROOT, "original"); -const DATA_FILE = path.join(IMAGE_ROOT, "data.json"); +const DATA_FILE = "data.json"; const JPG_QUALITY = 30; const JSON_WIDTH = 100; const PLACEHOLDER_LOCATION = "TODO location"; @@ -227,7 +227,7 @@ const prependPlaceholderSet = async (images: ManifestImage[]): Promise => const newImages = findNewImages(existing, images); if (newImages.length === 0) { - console.log("No new images to add to img/data.json"); + console.log("No new images to add to data.json"); return; } diff --git a/scripts/publish.ts b/scripts/publish.ts index 748c10a..40a5265 100644 --- a/scripts/publish.ts +++ b/scripts/publish.ts @@ -24,7 +24,7 @@ const AWS_REGION = "us-west-2"; const credentials = fromIni({ profile: AWS_PROFILE }); const s3 = new S3Client({ credentials, region: AWS_REGION }); -const cloudfront = new CloudFrontClient({ credentials }); +const cloudfront = new CloudFrontClient({ credentials, region: AWS_REGION }); let existingKeysPromise: Promise> | null = null; @@ -150,10 +150,6 @@ const uploadTree = async (root: string, keyPrefix: string, overwrite: boolean): for (const file of files) { const relative = path.relative(root, file).split(path.sep).join("/"); - if (root === IMAGE_DIR && relative === "data.json") { - continue; - } - const key = keyPrefix ? `${keyPrefix}/${relative}` : relative; await uploadFile(file, key, overwrite); } diff --git a/src/model.ts b/src/model.ts index d1c82ae..5816af1 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,4 +1,4 @@ -import galleryData from "../img/data.json"; +import galleryData from "../data.json"; export const SIZES = [2400, 1600, 1200, 800, 600, 400, 200]; diff --git a/vite.config.ts b/vite.config.ts index e0c9349..6784bc1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -17,6 +17,17 @@ export default defineConfig({ plugins: ["babel-plugin-react-compiler"], }, }), + { + // Rolldown-vite's JSON HMR logs an update but doesn't reload the browser. + // Force a full reload when data.json changes. + name: "reload-data-json", + handleHotUpdate({ file, server }) { + if (file.endsWith("/data.json")) { + server.ws.send({ type: "full-reload" }); + return []; + } + }, + }, ], resolve: { alias: {