Phase 2 (snipe#4): after bulk-reporting sellers to eBay T&S, Snipe now
persists which sellers were reported so cards show a muted "Reported to
eBay" badge and users aren't prompted to re-report the same seller.
- migration 012 adds reported_sellers table (user DB, UNIQUE on seller)
- Store.mark_reported / list_reported methods
- POST /api/reported + GET /api/reported endpoints
- reported store (frontend) with optimistic update + server persistence
- reportSelected wires into store after opening eBay tabs
Phase 3 prep (snipe#4): community blocklist share toggle
- Settings > Community section: "Share blocklist with community" toggle
(visible only to signed-in cloud users, default OFF)
- Persisted as community.blocklist_share user preference
- Backend community signal publish now gated on opt-in preference;
privacy-by-architecture: sharing is explicit, never implicit
Adds user-controlled theme selection independent of OS preference:
- useTheme composable: sets data-theme="dark"|"light" on <html>,
persisted to localStorage as snipe:theme. Follows the same pattern
as useSnipeMode.
- theme.css: [data-theme="dark"] and [data-theme="light"] explicit
attribute selectors override @media (prefers-color-scheme: light).
Media query updated to :root:not([data-theme="dark"]) so it has no
effect when the user has forced dark on a light-OS machine.
- App.vue: restoreTheme() called in onMounted alongside restoreSnipeMode.
- SettingsView: Appearance section with System/Dark/Light segmented
button group.
- api/main.py: GET /api/feedback/status + POST /api/feedback — creates
Forgejo issues; disabled (503) when FORGEJO_API_TOKEN unset, 403 in
demo mode; includes view, version, platform context in issue body
- FeedbackButton.vue: 2-step modal (type → review → submit); probes
/api/feedback/status on mount, stays hidden until confirmed enabled
- App.vue: mount FeedbackButton with current route name as view context;
import useRoute for reactive route name tracking
- .env.example: document FORGEJO_API_TOKEN / FORGEJO_REPO / FORGEJO_API_URL