{"id":15462982,"url":"https://github.com/jimthoburn/picture-gallery","last_synced_at":"2025-04-22T10:43:08.241Z","repository":{"id":37174037,"uuid":"219091620","full_name":"jimthoburn/picture-gallery","owner":"jimthoburn","description":"Universal JavaScript app, made with ECMAScript modules running natively in a browser or local environment 🖼️","archived":false,"fork":false,"pushed_at":"2025-04-13T20:52:50.000Z","size":425916,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-22T10:43:04.172Z","etag":null,"topics":["accessibility","gestures","isomorphic","reactive-programming","state-machine","transitions"],"latest_commit_sha":null,"homepage":"https://pictures.tobbi.co","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jimthoburn.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-11-02T02:17:36.000Z","updated_at":"2025-04-13T20:52:48.000Z","dependencies_parsed_at":"2023-02-05T02:46:00.682Z","dependency_job_id":"88c14b55-643d-40cb-b750-9646d7f0bc14","html_url":"https://github.com/jimthoburn/picture-gallery","commit_stats":{"total_commits":461,"total_committers":3,"mean_commits":"153.66666666666666","dds":"0.37744034707158347","last_synced_commit":"de21f3f9dded19b46822eaf6ede8f8d0fa11da68"},"previous_names":[],"tags_count":20,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimthoburn%2Fpicture-gallery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimthoburn%2Fpicture-gallery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimthoburn%2Fpicture-gallery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimthoburn%2Fpicture-gallery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jimthoburn","download_url":"https://codeload.github.com/jimthoburn/picture-gallery/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250222324,"owners_count":21394850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accessibility","gestures","isomorphic","reactive-programming","state-machine","transitions"],"created_at":"2024-10-02T00:06:31.091Z","updated_at":"2025-04-22T10:43:08.180Z","avatar_url":"https://github.com/jimthoburn.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Picture Gallery _beta_\n\nThis is a work in progress 🚧 \n\nI’m using it to practice with new tools and to share photos with friends 🦊 🐶\n\n* See [an example gallery](https://pictures.tobbi.co)\n* Here’s a [visualization of the gallery’s state machine](https://stately.ai/registry/editor/83f73a9c-669c-4c94-ad55-b9a10acc0644)\n* [Project goals](#goals)\n* Helpful [resources](#resources)\n* Guide about [improving image loading](https://dev.to/jimthoburn/how-to-improve-ux-for-images-while-they-re-loading-on-the-web-3b12) for this project\n\n## How to make your own gallery\n\n* [Quick start](#quick-start)\n* [Setting up a local environment](#setting-up)\n* [Creating a gallery](#creating-a-gallery)\n* [Editing a gallery](#editing-a-gallery)\n* [How to add a new album](#how-to-add-a-new-album)\n* [How to publish your gallery](#how-to-publish-your-gallery)\n* [Secret albums](#secret-albums)\n* [Group albums](#group-albums)\n* [Social sharing image](#social-sharing-image)\n* [How to add a story about an album](#how-to-add-a-story-about-an-album)\n* [Image captions](#image-captions)\n* [Image file storage](#image-file-storage)\n\n### Quick start\n\nTo create your own gallery, you can open this project in a [codespace](https://docs.github.com/en/codespaces/developing-in-codespaces/creating-a-codespace-from-a-template#creating-a-codespace-from-a-template-repository) on GitHub.\n\n### \u003cspan id=\"setting-up\"\u003e\u003c/span\u003e Setting up a local environment\n\n1. [Make a copy of this project on GitHub](https://github.com/jimthoburn/picture-gallery/generate) (or download it)\n\n2. Install [Deno](https://deno.com/runtime) (version `1.46.3` or greater).\n\n3. From the root of your project, start a server for development...\n\n```shell\ndeno task dev\n```\n\n4. Visit `http://localhost:4000`\n\n_If you see an error related to [deno.lock](https://deno.com/manual/basics/modules/integrity_checking), you can delete this file at the root of your project folder (it will be created again automatically)._\n\n### Creating a gallery\n\n1. Add your pictures to the `_pictures` folder, grouped by album name\n\n```\n_pictures/\n    your-album/\n        original/\n            1.jpg\n            2.jpg\n            3.jpg\n    your-other-album/\n        original/\n            1.jpg\n            2.jpg\n            3.jpg\n```\n\nYou may also want to delete the example pictures, and the LICENSE file:\n\n```\n_pictures/\n    LICENSE\n    northern-lights\n    secret-recipes\n    wildflowers\n```\n\n_You can also make [groups of albums](#group-albums)._\n\n2. Add information about your gallery and featured albums to `_api/index.json`\n\n```\n{\n  \"title\": \"A name for your gallery\",\n  \"date\": \"2019 to 2020\",\n  \"albums\": [\n    \"your-album\",\n    \"your-other-album\"\n  ]\n}\n```\n\nYou may also want to remove the `japan` and `wildflowers` examples from the list in `_api/index.json`.\n\n3. Create data and [responsive images](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images) for your new gallery.\n\nIn the root of your project run...\n\n```shell\ndeno task create\n```\n\n### Editing a gallery\n\nYou can edit the [JSON](https://www.json.org/json-en.html) files that were created for you in the `_api` folder:\n\n```\n_api/\n    index.json\n    your-album.json\n    your-other-album.json\n```\n\nFor example, you may want to change the `title` and add a `date` for each album:\n\n```\n\"title\": \"A name for your album\",\n\"date\": \"February \u0026 March, 2020\",\n```\n\nTo see your changes, you may need to stop the server (press “control C”) and then restart the server (`deno task dev`).\n\nIt’s okay to commit the generated files in these folders:\n\n```\n_api\n_archives\n_pictures\n```\n\nThese files are your data and will only change if you re-run the `deno task create` script or edit them yourself.\n\n_Running `deno task create` a second time will skip any existing files, even if \nthey would ideally be updated–for example, `.zip` files in the `_archives` folder. You can work around this by removing any files or folders that you want to re-create._\n\n### How to add a new album\n\n1. Add your pictures to the `_pictures` folder:\n\n```\n_pictures/\n    your-new-album/\n        original/\n            1.jpg\n            2.jpg\n            3.jpg\n```\n\n2. Create data for your new album:\n\n```shell\ndeno task create\n```\n\n3. Edit the data file for your album (optional):\n\n```\n_api/\n    your-new-album.json\n```\n\n4. Add your album to the `index.json` file to feature it on your gallery’s home page (optional):\n\n```\n{\n  \"title\": \"A name for your gallery\",\n  \"date\": \"2019 to 2020\",\n  \"albums\": [\n    \"your-new-album\"\n  ]\n}\n```\n\n### How to publish your gallery\n\nThe `build` command will create a `_site` folder that can be published on any web server.\n\n```shell\ndeno task build\n```\n\nYou can browse the static site locally with this command:\n\n```shell\ndeno task file-server\n```\n\nAnd then visit `http://localhost:4000`\n\nTo publish with [Deno Deploy](https://deno.com/deploy), you can skip a build step and use `server.js` for the `entrypoint`.\n\n### Secret albums\n\nIf you want to publish an album to share with friends without making it public,\nyou can leave it out of the `api/index.json` file. That way, it won’t appear on the home page of your picture gallery site.\n\nTo make the album name hard to guess, you may want to include a [UUID](https://duckduckgo.com/?q=UUID+generator\u0026t=ffab\u0026ia=answer) as part of the name. For example:\n\n```\nyour-secret-album-0c64f7ea-ad3d-4101-b379-fb5098aed301\n```\n\nYou can also ask search engines not to index your album by setting `askSearchEnginesNotToIndex` to `true` in the `JSON` file for your album.\n\n```\n{\n  \"uri\": \"your-secret-album-0c64f7ea-ad3d-4101-b379-fb5098aed301\",\n  \"title\": \"A name of your secret album\",\n  \"date\": \"February \u0026 March, 2019\",\n  \"askSearchEnginesNotToIndex\": true,\n}\n```\n\nThis will add a [noindex](https://support.google.com/webmasters/answer/93710?hl=en) meta element to your page.\n\nAnd you can ask search engines not to index your entire gallery (including the home page) by setting `askSearchEnginesNotToIndex` to `true` in the [_config.js](https://github.com/jimthoburn/picture-gallery/blob/main/_config.js) file:\n\n```\n\"askSearchEnginesNotToIndex\": true\n```\n\nIf your gallery is stored in a public place like GitHub, it may also be a good idea to [make your repository private](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-repositories).\n\n### Group albums\n\nTo group several albums together and show them on a single web page, create a\nnew folder using the name of your group–and place the albums inside it.\n\n```\n_pictures/\n    your-group-of-related-albums/\n        related-album/\n            original/\n                1.jpg\n                2.jpg\n                3.jpg\n        another-related-album/\n            original/\n                1.jpg\n                2.jpg\n                3.jpg\n```\n\nAnd then visit `http://localhost:4000/your-group-of-related-albums/`\n\n### Social sharing image\n\nTo make an [open graph image](https://ogp.me/) available for each page in your gallery, add your domain name to the [_config.js](https://github.com/jimthoburn/picture-gallery/blob/main/_config.js) file:\n\n```\n\"host\": \"https://your-domain-name.com\"\n```\n\n### How to add a story about an album\n\nIf you’d like to include some words about your album, create a [markdown](https://guides.github.com/features/mastering-markdown/) file with the same name as your album’s `.json` file and place it in the `_api` folder. For example:\n\n```\n_api/\n    your-album.json\n    your-album.markdown\n```\n\nYour story will appear along with the images, on the page for your album.\n\n### Image captions\n\nYou can write captions and descriptions for your images by editing the data file for your album:\n\n```\n_api/\n    your-new-album.json\n```\n\n```\n{\n    \"filename\": \"44.jpeg\",\n    \"description\": \"close-up of a tiny plant with purple flowers growing out of ground covered in pebbles\",\n    \"caption\": \"Desert Canterbury Bells at Mastodon Peak\",\n    \"uri\": \"44-mastodon-peak-desert-canterbury-bells\"\n},\n```\n\nThe `caption` will appear as part of the [page title for the image](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title). And the `description` will be used as the [`alt` text for the image](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt).\n\nYou can also edit the `uri` to match your caption. This will appear as part of the URL for the image. For example: `https://pictures.tobbi.co/wildflowers/44-mastodon-peak-desert-canterbury-bells/`\n\nIf you have a lot of images, you may be able to get a head start writing descriptions by using something like [Azure Computer Vision](\nhttps://learn.microsoft.com/en-us/azure/cognitive-services/computer-vision/overview-image-analysis) or [OpenAI Vision](https://platform.openai.com/docs/guides/vision).\n\nThe basic steps for this are...\n\n1. Copy the `.env-example` file in your local copy of this repo to a new file named `.env`\n2. Add your API key for Azure or OpenAPI to the `.env` file.\n\n_Using OpenAI Vision may require a [paid account](https://help.openai.com/en/articles/7102672-how-can-i-access-gpt-4)._\n\nIf you create a new album, descriptions will be generated and added to the data file for your album. You can improve or make corrections to the descriptions by manually editing the file.\n\n### Image file storage\n\nYou may want to use Git LFS, if your repository is getting close to 1 GB in size. See [GitHub disk quota](https://help.github.com/en/github/managing-large-files/what-is-my-disk-quota)\n\n* https://git-lfs.github.com\n\n#### How to move existing files into Git LFS\n\nHere are some commands that I used to migrate large files to Git LFS, when they were already in my Git commit history.\n\n```shell\ngit lfs migrate import --everything --include=\"*.jpg,*.jpeg,*.webp,*.avif,*.png,*.zip\"\ngit status\ngit push --force-with-lease\n```\n\nAnd here are a few commands that I used to switch between `git-lfs` hosts.\n\n1. Fetch images from a `git-lfs` remote host, replacing local pointer files\n\n```shell\ngit lfs fetch --all\n```\n\n2. Upload images to a `git-lfs` remote host, using local image files\n\n```shell\n# Step 1: Push all commits, without uploading any large files\nGIT_LFS_SKIP_PUSH=1 git push origin\n\n# Step 2: Upload the large files for any commits that have been pushed\ngit lfs push origin --all\n```\n\n## State machine visualization\n\nhttps://stately.ai/registry/editor/83f73a9c-669c-4c94-ad55-b9a10acc0644\n\n\u003ca href=\"https://stately.ai/registry/editor/83f73a9c-669c-4c94-ad55-b9a10acc0644\" rel=\"nofollow\"\u003e\u003cimg width=\"544\" alt=\"xstate\" src=\"https://user-images.githubusercontent.com/926616/68066254-8bd83b80-fcf2-11e9-8c77-6427061b98a9.png\"\u003e\n\u003c/a\u003e\n\n## \u003cspan id=\"goals\"\u003e\u003c/span\u003e Project goals\n\nThis project is an experiment to see how easily the following goals can be achieved in a [reactive](https://en.wikipedia.org/wiki/Reactive_programming) single-page application on the web…\n\nUser experience\n- [x] Essential content/features are available in any web browser\n- [x] Browser features (like forward/back and bookmarks) are supported\n- [x] Site is just as accessible as it would be with static HTML and page refreshes\n- [x] Site is just as findable by search engines and [archivable](https://archive.org/) as it would be if it were made of static HTML pages\n- [x] First page renders as quickly as static HTML\n- [x] The application works well on a slow network\n- [x] The application has cues that are equivalent to a normal browsing experience, like a page loading indicator\n- [x] The application is still usable when things go wrong, like if a CSS file doesn’t load or a JavaScript error happens\n- [x] Gesture-driven animations and transitions between pages can be added\n\nEditor experience\n- [x] Content can be created with a simple language like markdown\n- [x] Content can be added, edited and removed using a simple mechanism like files and folders\n- [x] The gallery can be hosted anywhere and kept private, if desired\n\nDeveloper experience\n- [x] The application’s logic is easy to understand and reason about ([Thanks XState!](https://stately.ai/registry/editor/83f73a9c-669c-4c94-ad55-b9a10acc0644))\n- [x] Large features can be broken up into smaller components and modules\n- [x] Code for templates and logic can be used on the client or server side\n- [x] The application can be continuously deployed in a way that is reliable, scalable and secure\n- [x] New features can be added with confidence that things won’t break\n- [ ] The code is easy to read\n- [ ] The app can be ported to another framework without too much rework\n\n## \u003cspan id=\"resources\"\u003e\u003c/span\u003e Helpful resources\n\nThese projects and guides have been super helpful to me, while working on the gallery…\n\n* https://barrgroup.com/Embedded-Systems/How-To/State-Machines-Event-Driven-Systems\n* https://barrgroup.com/Embedded-Systems/How-To/Introduction-Hierarchical-State-Machines\n* https://xstate.js.org\n* https://overreacted.io/a-complete-guide-to-useeffect/\n* https://developers.google.com/web/fundamentals/web-components/\n* https://hacks.mozilla.org/category/es6-in-depth/\n* https://github.com/developit/htm\n* https://www.pika.dev/\n\n## \u003cspan id=\"license\"\u003e\u003c/span\u003e License\n\nThe code for this project is available under an [open source license](LICENSE).\n\nThe example photos and recipes are available under a [creative commons license](https://creativecommons.org/licenses/by-sa/4.0/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimthoburn%2Fpicture-gallery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjimthoburn%2Fpicture-gallery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimthoburn%2Fpicture-gallery/lists"}