feat: awesome badges (#781)

This commit is contained in:
Jason Rasmussen
2026-09-03 14:32:36 -04:00
committed by GitHub
parent 23c828f360
commit 6abfb6bd11
8 changed files with 212 additions and 112 deletions
+1
View File
@@ -8,3 +8,4 @@ CHANGELOG.md
.svelte-kit/ .svelte-kit/
.release-please-manifest.json .release-please-manifest.json
**/backend/worker-configuration.d.ts **/backend/worker-configuration.d.ts
deployment/
+9 -1
View File
@@ -8,7 +8,15 @@ When adding a project to the list, please ensure that it meets the following cri
- Open source - Open source
- Non-commercial - Non-commercial
- Link goes to the source code/README - `sourceCodeUrl` points at the source code, and `websiteUrl` at the project's own website or documentation, if it has one. At least one of the two is required.
- The project should avoid bad practices like directly connecting to Immich's postgres database. If it does, please disclose it clearly to users. - The project should avoid bad practices like directly connecting to Immich's postgres database. If it does, please disclose it clearly to users.
Each entry also supports an optional `tags` array, whose values show as badges:
| Tag | Meaning |
| -------------- | --------------------------------------------------- |
| `Official` | Built and maintained by the Immich team |
| `Unmaintained` | No longer maintained |
| `Vibe-Coded` | Predominantly AI-generated with little human review |
You can add a project through https://github.com/immich-app/static-pages/edit/main/apps/awesome.immich.app/src/data/items.json. You can add a project through https://github.com/immich-app/static-pages/edit/main/apps/awesome.immich.app/src/data/items.json.
+5 -2
View File
@@ -16,8 +16,10 @@
"@sveltejs/kit": "^2.55.0", "@sveltejs/kit": "^2.55.0",
"@sveltejs/vite-plugin-svelte": "^7.0.0", "@sveltejs/vite-plugin-svelte": "^7.0.0",
"@tailwindcss/vite": "^4.2.2", "@tailwindcss/vite": "^4.2.2",
"@types/lodash-es": "^4.17.12",
"@types/luxon": "^3.7.1", "@types/luxon": "^3.7.1",
"@types/node": "^24.13.3", "@types/node": "^24.13.3",
"@typescript/native": "npm:typescript@^7.0.2",
"@vitest/browser": "^4.1.0", "@vitest/browser": "^4.1.0",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"front-matter": "^4.0.2", "front-matter": "^4.0.2",
@@ -29,7 +31,6 @@
"svelte": "^5.39.5", "svelte": "^5.39.5",
"svelte-check": "^4.3.2", "svelte-check": "^4.3.2",
"tailwindcss": "^4.2.2", "tailwindcss": "^4.2.2",
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2", "typescript": "npm:@typescript/typescript6@^6.0.2",
"vite": "^8.0.0", "vite": "^8.0.0",
"vitest": "^4.0.12", "vitest": "^4.0.12",
@@ -37,6 +38,8 @@
}, },
"dependencies": { "dependencies": {
"@immich/ui": "workspace:*", "@immich/ui": "workspace:*",
"@mdi/js": "^7.4.47" "@mdi/js": "^7.4.47",
"lodash-es": "^4.18.1",
"zod": "^4.4.3"
} }
} }
+98 -73
View File
@@ -7,78 +7,88 @@
{ {
"title": "ImmichFrame", "title": "ImmichFrame",
"description": "Run an Immich slideshow in a photo frame.", "description": "Run an Immich slideshow in a photo frame.",
"href": "https://github.com/3rob3/ImmichFrame" "websiteUrl": "https://immichframe.dev",
"sourceCodeUrl": "https://github.com/immichFrame/ImmichFrame"
}, },
{ {
"title": "Immich Desktop", "title": "Immich Desktop",
"description": "MacOS app that surfaces your Immich library in the Finder sidebar and every file dialog. Photos appear as on-demand files with thumbnails.", "description": "MacOS app that surfaces your Immich library in the Finder sidebar and every file dialog. Photos appear as on-demand files with thumbnails.",
"href": "https://kartax.github.io/immich-desktop-app/" "websiteUrl": "https://kartax.github.io/immich-desktop-app/",
"sourceCodeUrl": "https://github.com/Kartax/immich-desktop-app"
}, },
{ {
"title": "Immich Kiosk", "title": "Immich Kiosk",
"description": "Highly configurable slideshows for displaying Immich assets on browsers and devices.", "description": "Highly configurable slideshows for displaying Immich assets on browsers and devices.",
"href": "https://github.com/damongolding/immich-kiosk" "websiteUrl": "https://immichkiosk.app",
"sourceCodeUrl": "https://github.com/damongolding/immich-kiosk"
}, },
{ {
"title": "Immich Slides", "title": "Immich Slides",
"description": "Yet another Immich slideshow app — but with an actual settings UI. Configure layouts, filters, timing, and animations directly from the interface instead of Docker env files or URL parameters.", "description": "Yet another Immich slideshow app — but with an actual settings UI. Configure layouts, filters, timing, and animations directly from the interface instead of Docker env files or URL parameters.",
"href": "https://github.com/ntrampe/slides" "sourceCodeUrl": "https://github.com/ntrampe/slides"
}, },
{ {
"title": "Immich Android TV", "title": "Immich Android TV",
"description": "Unofficial Immich Android TV app.", "description": "Unofficial Immich Android TV app.",
"href": "https://github.com/giejay/Immich-Android-TV" "sourceCodeUrl": "https://github.com/giejay/Immich-Android-TV"
}, },
{ {
"title": "Immich Gallery", "title": "Immich Gallery",
"description": "Unofficial Apple TV Client for your Apple TV.", "description": "Unofficial Apple TV Client for your Apple TV.",
"href": "https://github.com/mensadilabs/Immich-Gallery" "websiteUrl": "https://mensadilabs.github.io/Immich-Gallery/",
"sourceCodeUrl": "https://github.com/mensadilabs/Immich-Gallery"
}, },
{ {
"title": "Immich Apple TV", "title": "Immich Apple TV",
"description": "Unofficial Immich Apple TV app.", "description": "Unofficial Immich Apple TV app.",
"href": "https://github.com/adriankraemer/Immich-Viewer" "websiteUrl": "https://immich.adriank.app",
"sourceCodeUrl": "https://github.com/adriankraemer/Immich-Viewer"
}, },
{ {
"title": "Immich Public Proxy", "title": "Immich Public Proxy",
"description": "Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.", "description": "Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.",
"href": "https://github.com/alangrainger/immich-public-proxy" "websiteUrl": "https://docs.ipp.nz",
"sourceCodeUrl": "https://github.com/alangrainger/immich-public-proxy"
}, },
{ {
"title": "View-Only Web Interface", "title": "View-Only Web Interface",
"description": "Display Immich photos publicly while allowing for the ability to filter and search for images.", "description": "Display Immich photos publicly while allowing for the ability to filter and search for images.",
"href": "https://github.com/JimmyeJones/Immich-View-Only-Web-Interface", "sourceCodeUrl": "https://github.com/JimmyeJones/Immich-View-Only-Web-Interface",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Mimick", "title": "Mimick",
"description": "Unofficial GTK4 Immich client for Linux with persistent background sync.", "description": "Unofficial GTK4 Immich client for Linux with persistent background sync.",
"href": "https://github.com/nicx17/mimick" "websiteUrl": "https://mimick.nicx.dev",
"sourceCodeUrl": "https://github.com/nicx17/mimick"
}, },
{ {
"title": "Harbour-Immich", "title": "Harbour-Immich",
"description": "Unofficial Immich Sailfish OS application.", "description": "Unofficial Immich Sailfish OS application.",
"href": "https://github.com/mezmerize/harbour-immich" "sourceCodeUrl": "https://github.com/mezmerize/harbour-immich"
}, },
{ {
"title": "Immich Companion", "title": "Immich Companion",
"description": "Browser extension that adds right-click save to Immich, CLIP-powered search from the toolbar, optional new tab photo memories, and inline search results that show your photos alongside Google/DuckDuckGo results.", "description": "Browser extension that adds right-click save to Immich, CLIP-powered search from the toolbar, optional new tab photo memories, and inline search results that show your photos alongside Google/DuckDuckGo results.",
"href": "https://github.com/bjoernch/immich-companion" "sourceCodeUrl": "https://github.com/bjoernch/immich-companion"
}, },
{ {
"title": "Picture Frame", "title": "Picture Frame",
"description": "Self-hosted digital photo frame for the Raspberry Pi that syncs an Immich album, with smooth crossfades even on a Pi Zero, motion-aware screen power, and Home Assistant control over MQTT.", "description": "Self-hosted digital photo frame for the Raspberry Pi that syncs an Immich album, with smooth crossfades even on a Pi Zero, motion-aware screen power, and Home Assistant control over MQTT.",
"href": "https://github.com/MateEke/picture-frame" "websiteUrl": "https://pictureframe.ekemate.hu",
"sourceCodeUrl": "https://github.com/MateEke/picture-frame"
}, },
{ {
"title": "Immich Screensaver", "title": "Immich Screensaver",
"description": "Native Windows screensaver that shows photos from your Immich server, with a different photo on each monitor, album selection, configurable crossfades and a clock overlay.", "description": "Native Windows screensaver that shows photos from your Immich server, with a different photo on each monitor, album selection, configurable crossfades and a clock overlay.",
"href": "https://github.com/xchimx/ImmichScreensaver" "websiteUrl": "https://www.schottstaedt.net/en/immich-screensaver-windows",
"sourceCodeUrl": "https://github.com/xchimx/ImmichScreensaver"
}, },
{ {
"title": "Imora", "title": "Imora",
"description": "Unofficial native Immich client for iOS, written in Swift.", "description": "Unofficial native Immich client for iOS, written in Swift.",
"href": "https://imora.vexcited.com" "websiteUrl": "https://imora.vexcited.com",
"sourceCodeUrl": "https://code.vexcited.com/imora/imora"
} }
] ]
}, },
@@ -90,87 +100,84 @@
{ {
"title": "immich-go", "title": "immich-go",
"description": "An alternative to the immich-CLI that doesn't depend on nodejs. It specializes in importing Google Photos Takeout archives.", "description": "An alternative to the immich-CLI that doesn't depend on nodejs. It specializes in importing Google Photos Takeout archives.",
"href": "https://github.com/simulot/immich-go" "sourceCodeUrl": "https://github.com/simulot/immich-go"
}, },
{ {
"title": "gPhotos2Immich", "title": "gPhotos2Immich",
"description": "Sync Google Photos shared albums to Immich, with automatic scheduling, deduplication, and Docker support.", "description": "Sync Google Photos shared albums to Immich, with automatic scheduling, deduplication, and Docker support.",
"href": "https://github.com/warreth/gPhotos2Immich" "sourceCodeUrl": "https://github.com/warreth/gPhotos2Immich"
}, },
{ {
"title": "Powershell Module PSImmich", "title": "Powershell Module PSImmich",
"description": "Powershell Module for the Immich API", "description": "Powershell Module for the Immich API",
"href": "https://github.com/hanpq/PSImmich" "websiteUrl": "https://getps.dev/modules/PSImmich/",
}, "sourceCodeUrl": "https://github.com/hanpq/PSImmich"
{
"title": "Immich Stack",
"description": "Automatically groups similar photos into stacks within the Immich photo management system.",
"href": "https://github.com/Majorfi/immich-stack/"
}, },
{ {
"title": "Immich Stack", "title": "Immich Stack",
"description": "Auto-stack photos with identical filenames and differing extensions (i.e. JPG+RAW)", "description": "Auto-stack photos with identical filenames and differing extensions (i.e. JPG+RAW)",
"href": "https://github.com/sid3windr/immich-stack", "sourceCodeUrl": "https://github.com/sid3windr/immich-stack",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "API Album Sync", "title": "API Album Sync",
"description": "A Python script to sync folders as albums.", "description": "A Python script to sync folders as albums.",
"href": "https://git.orenit.solutions/open/immichalbumpull" "sourceCodeUrl": "https://git.orenit.solutions/open/immichalbumpull"
}, },
{ {
"title": "Create albums from folders", "title": "Create albums from folders",
"description": "A Python script to create albums based on the folder structure of an external library.", "description": "A Python script to create albums based on the folder structure of an external library.",
"href": "https://github.com/Salvoxia/immich-folder-album-creator" "sourceCodeUrl": "https://github.com/Salvoxia/immich-folder-album-creator"
}, },
{ {
"title": "Immich Birthday Sync", "title": "Immich Birthday Sync",
"description": "Bulk-upload and -download birthdays, with CardDAV sync support", "description": "Bulk-upload and -download birthdays, with CardDAV sync support",
"href": "https://github.com/sid3windr/immich-birthday" "sourceCodeUrl": "https://github.com/sid3windr/immich-birthday"
}, },
{ {
"title": "Immich Downloader", "title": "Immich Downloader",
"description": "Downloads a configurable number of random photos based on people or album ID.", "description": "Downloads a configurable number of random photos based on people or album ID.",
"href": "https://github.com/jon6fingrs/immich-dl", "sourceCodeUrl": "https://github.com/jon6fingrs/immich-dl",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Immich Machine Learning Load Balancer", "title": "Immich Machine Learning Load Balancer",
"description": "Speed up your machine learning by load balancing your requests to multiple computers", "description": "Speed up your machine learning by load balancing your requests to multiple computers",
"href": "https://github.com/apetersson/immich_ml_balancer", "sourceCodeUrl": "https://github.com/apetersson/immich_ml_balancer",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Immich-Slideshow-Toolkit", "title": "Immich-Slideshow-Toolkit",
"description": "Commandline tools for creating video slideshow Mp4s from Immich albums.", "description": "Commandline tools for creating video slideshow Mp4s from Immich albums.",
"href": "https://github.com/knom/immich-slideshow-toolkit", "sourceCodeUrl": "https://github.com/knom/immich-slideshow-toolkit",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "TeleImmich", "title": "TeleImmich",
"description": "Sync exported Telegram backups to an Immich instance", "description": "Sync exported Telegram backups to an Immich instance",
"href": "https://github.com/dev-mkm/TeleImmich", "sourceCodeUrl": "https://github.com/rohamaa/TeleImmich",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Immich Face Recognition Export Tool", "title": "Immich Face Recognition Export Tool",
"description": "A Python tool to export face recognition data from Immich photo management system to DigiKam-compatible XMP format files.", "description": "A Python tool to export face recognition data from Immich photo management system to DigiKam-compatible XMP format files.",
"href": "https://github.com/yuhuan417/immich-scripts" "sourceCodeUrl": "https://github.com/yuhuan417/immich-scripts"
}, },
{ {
"title": "immichpy", "title": "immichpy",
"description": "The stable, typed Python API layer for Immich automation and integrations.", "description": "The stable, typed Python API layer for Immich automation and integrations.",
"href": "https://github.com/timonrieger/immichpy" "websiteUrl": "https://immichpy.timonrieger.de",
"sourceCodeUrl": "https://github.com/timonrieger/immichpy"
}, },
{ {
"title": "lrimmich", "title": "lrimmich",
"description": "Sync albums and metadata from a Lightroom Classic catalog to Immich when both share the same photo folder via an external library.", "description": "Sync albums and metadata from a Lightroom Classic catalog to Immich when both share the same photo folder via an external library.",
"href": "https://github.com/haavardnk/lrimmich" "sourceCodeUrl": "https://github.com/haavardnk/lrimmich"
}, },
{ {
"title": "Immich Custom Memories", "title": "Immich Custom Memories",
"description": "Create customized Memories in Immich.", "description": "Create customized Memories in Immich.",
"href": "https://github.com/SinTan1729/immich-custom-memories" "sourceCodeUrl": "https://github.com/SinTan1729/immich-custom-memories"
} }
] ]
}, },
@@ -182,24 +189,26 @@
{ {
"title": "Immich Kodi", "title": "Immich Kodi",
"description": "Unofficial Kodi plugin for Immich.", "description": "Unofficial Kodi plugin for Immich.",
"href": "https://github.com/vladd11/immich-kodi", "sourceCodeUrl": "https://github.com/vladd11/immich-kodi",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Lightroom Publisher: mi.Immich.Publisher", "title": "Lightroom Publisher: mi.Immich.Publisher",
"description": "Lightroom plugin to publish photos from Lightroom collections to Immich albums.", "description": "Lightroom plugin to publish photos from Lightroom collections to Immich albums.",
"href": "https://github.com/midzelis/mi.Immich.Publisher", "sourceCodeUrl": "https://github.com/midzelis/mi.Immich.Publisher",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Lightroom Immich Plugin: lrc-immich-plugin", "title": "Lightroom Immich Plugin: lrc-immich-plugin",
"description": "Lightroom plugin to publish, export photos from Lightroom to Immich. Import from Immich to Lightroom is also supported.", "description": "Lightroom plugin to publish, export photos from Lightroom to Immich. Import from Immich to Lightroom is also supported.",
"href": "https://blog.fokuspunk.de/lrc-immich-plugin/" "websiteUrl": "https://blog.fokuspunk.de/lrc-immich-plugin/",
"sourceCodeUrl": "https://github.com/bmachek/lrc-immich-plugin"
}, },
{ {
"title": "Rollfilm", "title": "Rollfilm",
"description": "Desktop photo manager for macOS, Windows and Linux. Import from a memory card, cull, rate and edit RAW files, then mirror photos and albums to Immich in the background. Semantic search runs locally.", "description": "Desktop photo manager for macOS, Windows and Linux. Import from a memory card, cull, rate and edit RAW files, then mirror photos and albums to Immich in the background. Semantic search runs locally.",
"href": "https://github.com/pasqualkreher/rollfilm" "sourceCodeUrl": "https://github.com/pasqualkreher/rollfilm",
"tags": ["Vibe-Coded"]
} }
] ]
}, },
@@ -208,51 +217,59 @@
"name": "Tools", "name": "Tools",
"types": ["tool", "tools"], "types": ["tool", "tools"],
"projects": [ "projects": [
{
"title": "Docker Compose Builder",
"description": "Build a custom docker-compose.yml file using known options and configuration.",
"websiteUrl": "https://immich.app/docker-compose-builder",
"sourceCodeUrl": "https://github.com/immich-app/static-pages",
"tags": ["Official"]
},
{ {
"title": "Immich-Tiktok-Remover", "title": "Immich-Tiktok-Remover",
"description": "Script to search for and remove TikTok videos from your Immich library.", "description": "Script to search for and remove TikTok videos from your Immich library.",
"href": "https://github.com/mxc2/immich-tiktok-remover" "sourceCodeUrl": "https://github.com/mxc2/immich-tiktok-remover"
}, },
{ {
"title": "Immich Upload Optimizer", "title": "Immich Upload Optimizer",
"description": "Automatically optimize files uploaded to Immich in order to save storage space", "description": "Automatically optimize files uploaded to Immich in order to save storage space",
"href": "https://github.com/miguelangel-nubla/immich-upload-optimizer" "sourceCodeUrl": "https://github.com/miguelangel-nubla/immich-upload-optimizer"
}, },
{ {
"title": "FlowLogix Mirror Immich", "title": "FlowLogix Mirror Immich",
"description": "Sync your macOS Apple Photos to Immich with title, description, keywords and other metadata", "description": "Sync your macOS Apple Photos to Immich with title, description, keywords and other metadata",
"href": "https://github.com/flowlogix/mirror-immich" "sourceCodeUrl": "https://github.com/flowlogix/mirror-immich"
}, },
{ {
"title": "Telegram to Immich Bot", "title": "Telegram to Immich Bot",
"description": "Telegram bot for uploading files directly to your Immich instance, preserving the metadata", "description": "Telegram bot for uploading files directly to your Immich instance, preserving the metadata",
"href": "https://github.com/myanesp/telegram-immich-bot", "sourceCodeUrl": "https://github.com/myanesp/telegram-immich-bot",
"maintained": false "tags": ["Unmaintained"]
}, },
{ {
"title": "Immich timelaspe selfie", "title": "Immich timelaspe selfie",
"description": "This tool creates selfie timelapse videos using Immich.", "description": "This tool creates selfie timelapse videos using Immich.",
"href": "https://github.com/ArnaudCrl/immich-automated-selfie-timelapse" "sourceCodeUrl": "https://github.com/ArnaudCrl/immich-automated-selfie-timelapse"
}, },
{ {
"title": "Immich ReverseGeo", "title": "Immich ReverseGeo",
"description": "Improve, correct, and get more precise reverse geocoding using Overture and GADM. Integrated geocoding", "description": "Improve, correct, and get more precise reverse geocoding using Overture and GADM. Integrated geocoding",
"href": "https://immich-reversegeo.github.io" "websiteUrl": "https://immich-reversegeo.github.io",
"sourceCodeUrl": "https://github.com/immich-reversegeo/immich-reversegeo.github.io"
}, },
{ {
"title": "Immich Power Tools", "title": "Immich Power Tools",
"description": "A unofficial Immich client to provide better tools to organize and manage your Immich account.", "description": "A unofficial Immich client to provide better tools to organize and manage your Immich account.",
"href": "https://github.com/immich-power-tools/immich-power-tools" "sourceCodeUrl": "https://github.com/immich-power-tools/immich-power-tools"
}, },
{ {
"title": "Immich Dark Theme Generator", "title": "Immich Dark Theme Generator",
"description": "Generate a custom dark theme for Immich.", "description": "Generate a custom dark theme for Immich.",
"href": "https://github.com/damongolding/immich-theme-generator" "sourceCodeUrl": "https://github.com/damongolding/immich-theme-generator"
}, },
{ {
"title": "Media Backup Manager", "title": "Media Backup Manager",
"description": "Windows desktop app for downloading original photos and videos from Immich by album or year for local backups. Uses only the Immich API without direct database access.", "description": "Windows desktop app for downloading original photos and videos from Immich by album or year for local backups. Uses only the Immich API without direct database access.",
"href": "https://github.com/olmos-cmd/Media-Backup-Manager-for-immich" "sourceCodeUrl": "https://github.com/olmos-cmd/Media-Backup-Manager-for-immich"
} }
] ]
}, },
@@ -264,12 +281,14 @@
{ {
"title": "Immich Distribution", "title": "Immich Distribution",
"description": "Snap package for easy install and zero-care auto updates of Immich. Self-hosted photo management.", "description": "Snap package for easy install and zero-care auto updates of Immich. Self-hosted photo management.",
"href": "https://immich-distribution.nsg.cc" "websiteUrl": "https://immich-distribution.nsg.cc",
"sourceCodeUrl": "https://github.com/nsg/immich-distribution"
}, },
{ {
"title": "SynoCommunity", "title": "SynoCommunity",
"description": "Native Synology DSM package for Immich, installable via Package Center. Includes PostgreSQL, Redis, and ffmpeg dependencies managed automatically.", "description": "Native Synology DSM package for Immich, installable via Package Center. Includes PostgreSQL, Redis, and ffmpeg dependencies managed automatically.",
"href": "https://docs.synocommunity.com/packages/immich/" "websiteUrl": "https://docs.synocommunity.com/packages/immich/",
"sourceCodeUrl": "https://github.com/SynoCommunity/spksrc"
} }
] ]
}, },
@@ -281,72 +300,78 @@
{ {
"title": "Cloudflare Tunnels with SSO/OAuth", "title": "Cloudflare Tunnels with SSO/OAuth",
"description": "Setting up Cloudflare Tunnels and a SaaS App for Immich.", "description": "Setting up Cloudflare Tunnels and a SaaS App for Immich.",
"href": "https://github.com/immich-app/immich/discussions/8299" "websiteUrl": "https://github.com/immich-app/immich/discussions/8299"
}, },
{ {
"title": "Database backup in TrueNAS", "title": "Database backup in TrueNAS",
"description": "Create a database backup with pgAdmin in TrueNAS.", "description": "Create a database backup with pgAdmin in TrueNAS.",
"href": "https://github.com/immich-app/immich/discussions/8809" "websiteUrl": "https://github.com/immich-app/immich/discussions/8809"
}, },
{ {
"title": "Unraid backup scripts", "title": "Unraid backup scripts",
"description": "Back up your assets in Unraid with a pre-prepared script.", "description": "Back up your assets in Unraid with a pre-prepared script.",
"href": "https://github.com/immich-app/immich/discussions/8416" "websiteUrl": "https://github.com/immich-app/immich/discussions/8416"
}, },
{ {
"title": "Sync folders with albums", "title": "Sync folders with albums",
"description": "synchronize folders in imported library with albums having the folders name.", "description": "synchronize folders in imported library with albums having the folders name.",
"href": "https://github.com/immich-app/immich/discussions/3382" "websiteUrl": "https://github.com/immich-app/immich/discussions/3382"
}, },
{ {
"title": "SynoCommunity Package Install", "title": "SynoCommunity Package Install",
"description": "Step-by-step guide for installing Immich as a native Synology DSM package via SynoCommunity's Package Center. Covers prerequisites, PostgreSQL setup, the installation wizard, and upgrade notes.", "description": "Step-by-step guide for installing Immich as a native Synology DSM package via SynoCommunity's Package Center. Covers prerequisites, PostgreSQL setup, the installation wizard, and upgrade notes.",
"href": "https://docs.synocommunity.com/packages/immich/" "websiteUrl": "https://docs.synocommunity.com/packages/immich/",
"sourceCodeUrl": "https://github.com/SynoCommunity/spksrc"
}, },
{ {
"title": "Immich Podman Quadlets Handbook", "title": "Immich Podman Quadlets Handbook",
"description": "A rewrite of the original Immich Docker Compose file using Podman Quadlets, with a set of extra guides in the repository's wiki.", "description": "A rewrite of the original Immich Docker Compose file using Podman Quadlets, with a set of extra guides in the repository's wiki.",
"href": "https://github.com/linux-universe/immich-podman-quadlets/blob/main/README.md" "websiteUrl": "https://github.com/linux-universe/immich-podman-quadlets/blob/main/README.md",
"sourceCodeUrl": "https://github.com/linux-universe/immich-podman-quadlets"
}, },
{ {
"title": "Podman/Quadlets Install", "title": "Podman/Quadlets Install",
"description": "Documentation for simple podman setup using quadlets.", "description": "Documentation for simple podman setup using quadlets.",
"href": "https://github.com/tbelway/immich-podman-quadlets/blob/main/docs/install/podman-quadlet.md" "websiteUrl": "https://github.com/tbelway/immich-podman-quadlets/blob/main/docs/install/podman-quadlet.md",
"sourceCodeUrl": "https://github.com/tbelway/immich-podman-quadlets"
}, },
{ {
"title": "Google Photos import + albums", "title": "Google Photos import + albums",
"description": "Import your Google Photos files into Immich and add your albums.", "description": "Import your Google Photos files into Immich and add your albums.",
"href": "https://github.com/immich-app/immich/discussions/1340" "websiteUrl": "https://github.com/immich-app/immich/discussions/1340"
}, },
{ {
"title": "Access Immich with custom domain", "title": "Access Immich with custom domain",
"description": "Access your local Immich installation over the internet using your own domain.", "description": "Access your local Immich installation over the internet using your own domain.",
"href": "https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md" "websiteUrl": "https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md",
"sourceCodeUrl": "https://github.com/ppr88/immich-guides"
}, },
{ {
"title": "Nginx caching map server", "title": "Nginx caching map server",
"description": "Increase privacy by using nginx as a caching proxy in front of a map tile server.", "description": "Increase privacy by using nginx as a caching proxy in front of a map tile server.",
"href": "https://github.com/pcouy/pcouy.github.io/blob/main/_posts/2024-08-30-proxying-a-map-tile-server-for-increased-privacy.md" "websiteUrl": "https://pierre-couy.dev/server-admin/2024/08/proxying-a-map-tile-server-for-increased-privacy.html",
"sourceCodeUrl": "https://github.com/pcouy/pcouy.github.io"
}, },
{ {
"title": "fail2ban setup instructions", "title": "fail2ban setup instructions",
"description": "How to configure an existing fail2ban installation to block incorrect login attempts.", "description": "How to configure an existing fail2ban installation to block incorrect login attempts.",
"href": "https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948" "websiteUrl": "https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948"
}, },
{ {
"title": "Immich remote access with NordVPN Meshnet", "title": "Immich remote access with NordVPN Meshnet",
"description": "Access Immich with an end-to-end encrypted connection.", "description": "Access Immich with an end-to-end encrypted connection.",
"href": "https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access" "websiteUrl": "https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access"
}, },
{ {
"title": "Trust Self Signed Certificates with Immich - OAuth Setup", "title": "Trust Self Signed Certificates with Immich - OAuth Setup",
"description": "Set up Certificate Authority trust with Immich, and your private OAuth2/OpenID service, while using a private CA for HTTPS communication.", "description": "Set up Certificate Authority trust with Immich, and your private OAuth2/OpenID service, while using a private CA for HTTPS communication.",
"href": "https://github.com/immich-app/immich/discussions/18614" "websiteUrl": "https://github.com/immich-app/immich/discussions/18614"
}, },
{ {
"title": "How-To Install Immich on Rockstor NAS", "title": "How-To Install Immich on Rockstor NAS",
"description": "Set up Immich with External Libraries on your Rockstor NAS server.", "description": "Set up Immich with External Libraries on your Rockstor NAS server.",
"href": "https://rockstor.com/docs/interface/docker-based-rock-ons/immich.html" "websiteUrl": "https://rockstor.com/docs/interface/docker-based-rock-ons/immich.html",
"sourceCodeUrl": "https://github.com/rockstor/rockstor-doc"
} }
] ]
} }
@@ -1,27 +1,51 @@
<script lang="ts"> <script lang="ts">
import type { Project } from '$lib'; import { getProjectUrl, ProjectTag, type Project } from '$lib';
import { Card, CardBody, CardHeader, Heading, Link, Text, Badge } from '@immich/ui'; import { Badge, Card, CardBody, CardHeader, Heading, Link, Text, type Color, type IconLike } from '@immich/ui';
import { mdiAlertOutline, mdiCheckDecagram, mdiCodeTags, mdiOpenInNew, mdiRobot, mdiWeb } from '@mdi/js/mdi';
type Props = { type Props = {
project: Project; project: Project;
}; };
const { project }: Props = $props(); const { project }: Props = $props();
const badges: Record<ProjectTag, { color: Color; icon: IconLike }> = {
[ProjectTag.Official]: { color: 'primary', icon: mdiCheckDecagram },
[ProjectTag.Unmaintained]: { color: 'warning', icon: mdiAlertOutline },
[ProjectTag.VibeCoded]: { color: 'warning', icon: mdiRobot },
};
const url = $derived(getProjectUrl(project));
</script> </script>
<Link href={project.href} underline={false}> <Card color="secondary" class="h-full">
<Card color="secondary" class="group h-full"> <CardHeader>
<CardHeader> <div class="mb-2 flex flex-wrap items-center gap-2">
<div class="flex items-center gap-2"> <Link href={url} underline={false}>
<Heading size="small" class="group-hover:underline">{project.title}</Heading> <Heading size="small" class="hover:underline">{project.title}</Heading>
{#if !project.maintained} </Link>
<Badge size="small" color="warning">Unmaintained</Badge>
{/if} {#each project.tags as tag (tag)}
</div> <Badge leadingIcon={badges[tag].icon} size="small" color={badges[tag].color}>{tag}</Badge>
<Text color="muted" size="small">{project.href}</Text> {/each}
</CardHeader> </div>
<CardBody> <Link href={url} underline={false}>
<Text>{project.description}</Text> <Text color="muted" size="small" class="hover:underline">{url}</Text>
</CardBody> </Link>
</Card> </CardHeader>
</Link> <CardBody>
<Text>{project.description}</Text>
</CardBody>
<div class="flex flex-wrap items-center gap-2 px-4 pb-4">
{#if project.websiteUrl}
<Link href={project.websiteUrl} underline={false}>
<Badge leadingIcon={mdiWeb} size="small" color="primary" trailingIcon={mdiOpenInNew}>Website</Badge>
</Link>
{/if}
{#if project.sourceCodeUrl}
<Link href={project.sourceCodeUrl} underline={false}>
<Badge leadingIcon={mdiCodeTags} size="small" color="primary" trailingIcon={mdiOpenInNew}>Source code</Badge>
</Link>
{/if}
</div>
</Card>
+38 -13
View File
@@ -1,4 +1,6 @@
import { defaultProvider, linkCommands, type ActionProvider } from '@immich/ui'; import { defaultProvider, linkCommands, type ActionProvider } from '@immich/ui';
import { orderBy } from 'lodash-es';
import { z } from 'zod';
import items from '../data/items.json'; import items from '../data/items.json';
export const siteMetadata = { export const siteMetadata = {
@@ -14,21 +16,38 @@ export type Category = {
projects: Project[]; projects: Project[];
}; };
export type Project = { export enum ProjectTag {
title: string; Official = 'Official',
description: string; Unmaintained = 'Unmaintained',
href: string; VibeCoded = 'Vibe-Coded',
maintained: boolean; }
};
export const projectSchema = z
.object({
title: z.string(),
description: z.string(),
websiteUrl: z.string().optional(),
sourceCodeUrl: z.string().optional(),
tags: z.array(z.enum(ProjectTag)).default([]),
})
.refine(({ websiteUrl, sourceCodeUrl }) => !!(websiteUrl ?? sourceCodeUrl), {
error: 'A project requires a websiteUrl, a sourceCodeUrl, or both',
});
export type Project = z.infer<typeof projectSchema>;
export const getProjectUrl = ({ websiteUrl, sourceCodeUrl }: Project) => websiteUrl ?? sourceCodeUrl!;
export const categories = items.map((category) => ({ export const categories = items.map((category) => ({
...category, ...category,
projects: category.projects projects: orderBy(
.map((project) => ({ category.projects.map((project) => projectSchema.parse(project)),
...project, [
maintained: project.maintained ?? true, (project) => project.tags.includes(ProjectTag.Official),
})) (project) => !project.tags.includes(ProjectTag.Unmaintained),
.toSorted((a, b) => (a.maintained === b.maintained ? 0 : a.maintained ? -1 : 1)), ],
['desc', 'desc'],
),
})); }));
export const getCategoryProviders = () => { export const getCategoryProviders = () => {
@@ -36,7 +55,13 @@ export const getCategoryProviders = () => {
defaultProvider({ defaultProvider({
name: category.name, name: category.name,
types: category.types, types: category.types,
actions: linkCommands(category.projects), actions: linkCommands(
category.projects.map((project) => ({
title: project.title,
description: project.description,
href: getProjectUrl(project),
})),
),
}), }),
); );
@@ -1,20 +1,25 @@
<script lang="ts"> <script lang="ts">
import LinkableHeading from '$common/components/LinkableHeading.svelte'; import LinkableHeading from '$common/components/LinkableHeading.svelte';
import { categories, siteMetadata, type Category } from '$lib'; import { categories, siteMetadata, type Category, type Project } from '$lib';
import ProjectCard from '$lib/components/ProjectCard.svelte'; import ProjectCard from '$lib/components/ProjectCard.svelte';
import { Heading, Input, Link, SiteMetadata, Text } from '@immich/ui'; import { Heading, Input, Link, SiteMetadata, Text } from '@immich/ui';
import { mdiMagnify } from '@mdi/js'; import { mdiMagnify } from '@mdi/js';
let query = $state(''); let query = $state('');
const matchesQuery = (project: Project, query: string) =>
[project.title, project.description, project.websiteUrl, project.sourceCodeUrl]
.filter(Boolean)
.join('|')
.toLowerCase()
.includes(query);
const filterProjects = (query: string) => { const filterProjects = (query: string) => {
query = query.toLowerCase().trim(); query = query.toLowerCase().trim();
const results: Category[] = []; const results: Category[] = [];
for (const category of categories) { for (const category of categories) {
const projects = category.projects.filter(({ title, description, href }) => const projects = category.projects.filter((project) => !query || matchesQuery(project, query));
[title, description, href].join('|').toLowerCase().includes(query),
);
if (projects.length > 0) { if (projects.length > 0) {
results.push({ ...category, projects }); results.push({ ...category, projects });
@@ -53,7 +58,7 @@
</LinkableHeading> </LinkableHeading>
<div class="mt-4 grid grid-cols-1 gap-4"> <div class="mt-4 grid grid-cols-1 gap-4">
{#each category.projects as project (project.href)} {#each category.projects as project (category.id + project.title)}
<ProjectCard {project} /> <ProjectCard {project} />
{/each} {/each}
</div> </div>
+9
View File
@@ -147,6 +147,12 @@ importers:
'@mdi/js': '@mdi/js':
specifier: ^7.4.47 specifier: ^7.4.47
version: 7.4.47 version: 7.4.47
lodash-es:
specifier: ^4.18.1
version: 4.18.1
zod:
specifier: ^4.4.3
version: 4.4.3
devDependencies: devDependencies:
'@sveltejs/adapter-static': '@sveltejs/adapter-static':
specifier: ^3.0.9 specifier: ^3.0.9
@@ -160,6 +166,9 @@ importers:
'@tailwindcss/vite': '@tailwindcss/vite':
specifier: ^4.2.2 specifier: ^4.2.2
version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0))
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
'@types/luxon': '@types/luxon':
specifier: ^3.7.1 specifier: ^3.7.1
version: 3.7.5 version: 3.7.5