all repos — weimar @ 088c2e33b9850fd8e9a0a65e6876d579b0f5433f

Unnamed repository; edit this file 'description' to name the repository.

088c2e33
feat: autocomplete suggestions for tag and uploader filters

Tag filter shows usage count, uploader filter shows upload count.
Both endpoints use requireAuthOrPublic for unauthenticated browse.
200ms debounce on input. Backend uses LIKE prefix match ordered by
count descending.

Assisted-by: Crush:deepseek-v4-flash
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 21:23:05 +0200
3d9ddf2a
feat: filter images by uploader with clickable uploader names

Adds `?uploader=<username>` query param support to GET /api/images.
Uploader names are clickable throughout the UI (browse cards, viewer,
detail page) to filter the gallery to that uploader's media.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-v4-flash
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 21:19:18 +0200
cd624b1b
feat: full-screen drag-and-drop upload zone

Document-level drag events trigger a full-screen overlay with dark
backdrop and dashed red border, accepting the file on drop
anywhere on the page. File can still be selected via button click.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-v4-flash
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 21:14:24 +0200
afea02cb
fix: graceful SIGINT shutdown and SIGHUP config reload

SIGINT now exits cleanly with code 0 instead of propagating
http.ErrServerClosed as a fatal error. SIGHUP re-reads the config file
and atomically swaps the config pointer β€” settings like site_title,
favicon_path, behind_proxy, and require_auth_for_browse take effect
immediately without restarting. Config is stored as *config.Config
throughout so handlers and middleware read the live value at request time.

Co-authored-by: Crush
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 20:10:38 +0200
b26a020c
feat: configurable site title, favicon, and nav logo

Add site_title, favicon_path, and logo_path config options. Default favicon
is an embedded SVG with a red lowercase "w" on black. Custom favicons can
be SVG, PNG, JPG, or ICO β€” the /favicon handler serves them with the
correct Content-Type detected from the file extension. The /logo handler
serves a nav logo; when set, the layout shows an <img> instead of the text
site title. The GET /api/config endpoint exposes these URLs to the frontend.
Includes example config at configs/example.toml.

Co-authored-by: Crush
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 20:05:05 +0200
a213da87
fix: security hardening β€” bcrypt cost, secure cookies, security headers, avatar auth

Bump bcrypt cost from 10 to 12 for adequate brute-force resistance in 2026.
Add behind_proxy config option that enables Secure flag on session cookies
for deployments behind a TLS-terminating reverse proxy (Caddy, nginx).
Add X-Content-Type-Options, X-Frame-Options, and Referrer-Policy security
headers to every response. Fix avatar endpoint auth mismatch β€” avatars are
now served publicly since their URLs are exposed in gallery listings anyway.

Co-authored-by: Crush
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 19:56:35 +0200
87601e8f
feat: public browsing, shareable image URLs, and tag editing

Public browsing is the new default β€” unauthenticated users can browse the
gallery, view images, and download originals. Lock it down by setting
`auth.require_auth_for_browse = true` in weimar.toml.

Each image now gets a shareable URL when opened in the overlay viewer:
`/browse?image=<id>`. Navigate to it directly and the viewer opens
automatically (or redirects to the detail page if the image is on a
different page).

Image owners can now edit tags from the overlay viewer or the detail page.
A text field with autocomplete and ADD/REMOVE buttons appears below the
tag display on your own uploads.

Backend: new public/optional auth middleware, AddImageTags/RemoveImageTags
queries, is_owner field on image detail, require_auth_for_browse config
option. Frontend: viewer tag editing, shareable URL via pushState, image
detail page uses is_owner from backend instead of separate getMe() call.

Co-authored-by: Crush
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 19:42:40 +0200
cf03eeda
fix: reduce avatar processing to 128px, double viewer avatar to 80px

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 18:25:32 +0200
c9643af6
feat: default avatar SVG, nav bar avatar, fix settings preview

- Avatar.svelte component: shows uploaded image or red SVG fallback
  with first letter of username
- Nav bar shows avatar (28px) in top-right corner next to LOGOUT,
  links to /settings
- Layout now fetches GET /api/users/me instead of pinging images
  endpoint for auth state
- Settings page loads current avatar on mount via getMe()
- ImageViewer uses Avatar component for uploader display
- Cleaned up unused CSS classes

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:53:37 +0200
8d72190a
feat: add user avatars and settings page

Backend:
- Migration v7: avatar_path TEXT column on users table
- POST /api/users/me/avatar β€” upload avatar (resized to 256px, JPEG)
- GET /api/users/{id}/avatar β€” serve avatar image
- avatar_url included in both list and detail image responses

Frontend:
- New /settings page with avatar upload (file picker, preview, save)
- SETTINGS link in nav bar (visible when logged in)
- Uploader avatar shown in browse card overlay, ImageViewer info bar,
  and image detail page

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:41:12 +0200
74fc3e1e
feat: show uploader username and database ID on media

- Added UploaderUsername field to Image model, populated from users
  table in both list and detail API responses
- Shows uploader username in browse card overlay, ImageViewer info
  bar, and image detail page
- Shows database ID (#id) alongside metadata in all three locations
  for admin CLI convenience

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:31:26 +0200
da5efcda
fix: restore full-width grid by fixing :global target after layout refactor

The layout changed from `<main>` to `<div class="main">`, breaking
the browse page's `:global(main)` override. Updated to `:global(.main)`.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:19:04 +0200
a8921d22
feat: bold Swiss/constructivist design overhaul

Typography:
- Inter for body text, Oswald for headings (bold condensed)
- ALL CAPS labels, large type hierarchy, tight letter-spacing

Colors:
- Black (#1a1a1a) background on UI elements, white text
- Red (#c62828) accent for hover states, underlines, CTA buttons
- Light gray (#f5f5f5) page background for contrast

Layout:
- Black nav bar with red bottom border, red hover states
- Red accent underline blocks (3px x 3rem) on page headings
- No border-radius anywhere β€” sharp rectangular constructivist forms
- Full-width 6-column gallery grid with 2px gaps

All pages redesigned: home, browse, upload, login, image detail,
and image viewer overlay.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:14:34 +0200
3ab9da92
feat: make tags clickable with usage counts, larger and more prominent

- Tags in ImageViewer and detail page are now clickable pill buttons
- Clicking a tag navigates to /browse?tag=<tagname>
  with the filter auto-applied on mount
- Browse page reads ?tag= URL param on initial load
- Tags display usage count badge (sorted most→least frequent)
- Larger pill sizing with hover effects in both viewer and detail page
- New GetImageTagsWithCounts DB function joins tags+image_tags
  for usage counts returned in GET /api/images/{id} as tags_detail

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 16:02:30 +0200
a338ad58
feat: make browse grid 6 columns and full-width

- Grid layout set to repeat(6, 1fr) with responsive breakpoints for smaller screens
- Removed layout max-width constraint on browse page via :global(main) override
- Header and pagination get their own padding within the full-width layout
- Increased per page to 60 for better coverage at 6 columns

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 15:50:15 +0200
4725091c
feat: redesign browse grid with Chevereto-style card layout and hover overlay

- Compact grid with 2px gaps and dark image backgrounds (aspect-ratio 16:10)
- Image fills card via object-fit: cover with subtle scale-on-hover
- Gradient overlay on hover shows filename, dimensions, and truncated tags
- Removed rounded corners and info text below cards for cleaner look

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 15:44:59 +0200
4240c5c9
feat: add image overlay viewer with keyboard navigation and idle UI fade

Replaces full-page navigation with a Chevereto-inspired lightbox overlay
when clicking thumbnails in the browse grid. Supports prev/next via
buttons and arrow keys, close via Esc/click-outside, auto-hiding controls
after 3s of inactivity, and a bottom info bar with metadata and download.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 15:34:07 +0200
5db53247
fix: preserve all tags on upload and return empty array on no match

Tags beyond the first were silently dropped because `r.FormValue("tags")`
returns only the first value when the frontend sends each tag as a
separate FormData field. Changed to `r.Form["tags"]`.

Nil slices in API responses (`var images []Image`) marshalled to JSON
`null`, causing a TypeError in the Svelte template (`null.length`),
making "Loading..." persist forever. Initialized all API-facing slices
with `make()` so they marshal as `[]`.

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 15:16:05 +0200
77821058
feat: implement core backend API and SvelteKit SPA

Full MVP implementation of the weimar media repository:
- CLI commands for user CRUD, image deletion, password reset
- HTTP API with auth (cookie sessions), upload, browse, download,
  thumbnail serving, and tag autocomplete
- SQLite-backed storage with migrations
- Hash-partitioned disk storage with EXIF stripping and thumbnails
- SvelteKit SPA with login, upload, browse grid, and image detail pages
- Makefile build flow: SvelteKit build -> Go embed -> single binary
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 14:03:41 +0200
28e89651
feat: initial project scaffolding

Single-binary media repository for home servers β€” Go backend with
embedded SvelteKit SPA.

- Cobra CLI with viper config (TOML, env vars WEIMAR_*, flags)
- Commands: serve, users, image, version
- HTTP server with Go 1.22+ ServeMux, API route stubs, SPA fallback
- SvelteKit frontend with adapter-static (SPA mode, 5 routes)
- Build pipeline: Makefile, GoReleaser, UPX compression
- ldflags-based version and build date injection

πŸ’˜ Generated with Crush

Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 11:05:44 +0200