feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
/* Favoritter — custom styles on top of Pico CSS */
|
|
|
|
|
|
2026-03-29 17:54:24 +02:00
|
|
|
/* Visually hidden, accessible to screen readers */
|
|
|
|
|
.sr-only {
|
|
|
|
|
position: absolute;
|
|
|
|
|
width: 1px;
|
|
|
|
|
height: 1px;
|
|
|
|
|
padding: 0;
|
|
|
|
|
margin: -1px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
clip: rect(0, 0, 0, 0);
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
border: 0;
|
|
|
|
|
}
|
|
|
|
|
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
/* Skip navigation link for accessibility */
|
|
|
|
|
.skip-link {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: -100%;
|
|
|
|
|
left: 0;
|
|
|
|
|
padding: 0.5rem 1rem;
|
|
|
|
|
background: var(--pico-primary-background);
|
|
|
|
|
color: var(--pico-primary-inverse);
|
|
|
|
|
z-index: 1000;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.skip-link:focus {
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Inline forms (e.g. logout button in nav) */
|
|
|
|
|
.inline-form {
|
|
|
|
|
display: inline;
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-button {
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0.25rem 0.75rem;
|
|
|
|
|
font-size: 0.875rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Flash messages */
|
|
|
|
|
.flash {
|
|
|
|
|
padding: 1rem;
|
|
|
|
|
border-radius: var(--pico-border-radius);
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flash-success {
|
|
|
|
|
background: color-mix(in srgb, var(--pico-ins-color) 15%, transparent);
|
|
|
|
|
border: 1px solid var(--pico-ins-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flash-error {
|
|
|
|
|
background: color-mix(in srgb, var(--pico-del-color) 15%, transparent);
|
|
|
|
|
border: 1px solid var(--pico-del-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flash-info {
|
|
|
|
|
background: color-mix(in srgb, var(--pico-primary) 10%, transparent);
|
|
|
|
|
border: 1px solid var(--pico-primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fave card grid */
|
|
|
|
|
.fave-grid {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
list-style: none;
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fave-card {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fave-card img {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 200px;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
border-radius: var(--pico-border-radius) var(--pico-border-radius) 0 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fave-card header {
|
|
|
|
|
padding: 0.5rem 1rem 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fave-card footer {
|
|
|
|
|
padding: 0 1rem 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Privacy badge */
|
|
|
|
|
.badge-private {
|
|
|
|
|
background: var(--pico-muted-border-color);
|
|
|
|
|
padding: 0.1rem 0.4rem;
|
|
|
|
|
border-radius: var(--pico-border-radius);
|
|
|
|
|
font-size: 0.75rem;
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
}
|
|
|
|
|
|
feat: add profiles, public views, settings, and code quality fixes
Phase 3 — Profiles & Public Views:
- Public profile page (/u/{username}) with OG meta tags
- User settings page (display name, bio, visibility, default privacy)
- Avatar upload with image processing
- Password change from settings (verifies current password)
- Home page shows public fave feed for logged-in users
- Must-reset-password guard redirects to /reset-password
- Profile visibility: public (full) or limited (username only)
Code quality improvements from /simplify review:
- Fix signup request persistence bug (was silently discarding data)
- Fix health check to use configured listen address, not hardcoded :8080
- Add rate limiter cleanup goroutine (was leaking memory)
- Extract shared helpers: ClearSessionCookie, IsSecureRequest, scanTags,
scanUserFrom (scanner interface), SignupRequestStore
- Replace hand-rolled joinPlaceholders with strings.Join
- Remove dead _method hidden field, redundant devMode field
- Simplify rate-limited route registration (remove double-mux)
- Log previously-swallowed errors (session delete, image delete)
- Stop leaking internal error messages to users in image upload
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:01:41 +02:00
|
|
|
/* Profile header */
|
|
|
|
|
.profile-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 1.5rem;
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Avatar */
|
|
|
|
|
.avatar-large {
|
|
|
|
|
width: 120px;
|
|
|
|
|
height: 120px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
/* Tag chips */
|
|
|
|
|
.tag-chip {
|
|
|
|
|
display: inline-block;
|
|
|
|
|
background: var(--pico-primary-focus);
|
|
|
|
|
color: var(--pico-primary);
|
|
|
|
|
padding: 0.15rem 0.5rem;
|
|
|
|
|
border-radius: 1rem;
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
margin: 0.1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tag-chip:hover {
|
|
|
|
|
background: var(--pico-primary);
|
|
|
|
|
color: var(--pico-primary-inverse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tag autocomplete suggestions */
|
|
|
|
|
.tag-suggestions {
|
|
|
|
|
list-style: none;
|
|
|
|
|
padding: 0;
|
|
|
|
|
margin: 0;
|
|
|
|
|
border: 1px solid var(--pico-muted-border-color);
|
|
|
|
|
border-radius: var(--pico-border-radius);
|
|
|
|
|
max-height: 200px;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tag-suggestions:empty {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tag-suggestion {
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tag-suggestion:hover,
|
2026-03-29 17:54:24 +02:00
|
|
|
.tag-suggestion:focus-visible {
|
|
|
|
|
background: var(--pico-primary-focus);
|
|
|
|
|
outline: 2px solid var(--pico-primary);
|
|
|
|
|
outline-offset: -2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tag-suggestion[aria-selected="true"] {
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
background: var(--pico-primary-focus);
|
2026-03-29 17:58:40 +02:00
|
|
|
outline: 2px solid var(--pico-primary);
|
|
|
|
|
outline-offset: -2px;
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fave detail actions */
|
|
|
|
|
.fave-actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
margin-top: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fave-actions a,
|
|
|
|
|
.fave-actions button {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Current image preview in edit form */
|
|
|
|
|
.current-image {
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.current-image img {
|
|
|
|
|
border-radius: var(--pico-border-radius);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 16:09:30 +02:00
|
|
|
/* Admin */
|
|
|
|
|
.stat {
|
|
|
|
|
font-size: 2rem;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.disabled-row {
|
2026-03-29 17:54:24 +02:00
|
|
|
color: var(--pico-muted-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.disabled-row td:first-child {
|
|
|
|
|
text-decoration: line-through;
|
2026-03-29 16:09:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.inline-input {
|
|
|
|
|
display: inline-block;
|
|
|
|
|
width: auto;
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0.25rem 0.5rem;
|
|
|
|
|
font-size: 0.875rem;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 17:54:24 +02:00
|
|
|
/* Responsive admin tables */
|
|
|
|
|
.table-responsive {
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
}
|
|
|
|
|
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
/* Respect reduced motion preference */
|
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
|
*, *::before, *::after {
|
|
|
|
|
animation-duration: 0.01ms !important;
|
|
|
|
|
animation-iteration-count: 1 !important;
|
|
|
|
|
transition-duration: 0.01ms !important;
|
|
|
|
|
}
|
|
|
|
|
}
|