feat: Courses-redesign + Tjing-import (#8) #22

Merged
shcizo merged 6 commits from feat/courses-redesign-tjing-import-8 into main 2026-05-25 10:52:08 +02:00
Owner

Summary

  • Redesignar Courses-sidan: tabbat action-card ("Find courses" / "Import from Tjing"), results-bar, ny grid-tabell med Players-mönster (header, accent-på-hover, typografi), expanded view med par/rating-chips färgade efter tier, collapsible inaktiva layouter.
  • Återinför Tjing-importflödet som togs bort i 6e05d30searchTjingCourses + getTjingCourse mot Tjing GraphQL, getOrCreateLayout i course.js, nya endpoints /api/tjing/search + /api/tjing/import/:tjingId, klientfunktioner för sök/importera.
  • Bugfix på saveCourseToDB: this.lastID = 0 vid ON CONFLICT DO UPDATE ledde till orphan-layouts vid Tjing-re-import — nu fallback till SELECT id WHERE link = ?.

Closes #8

Test plan

  • Sidan /courses laddar utan 500-fel
  • Tabbat action-card: switch mellan "Find courses" och "Import from Tjing"
  • Live-filter på "Find courses" filtrerar rader på namn + stad, Showing N of M uppdateras
  • Tabellhuvud "Course / City / Last updated" matchar Players visuellt (11px uppercase, paper-2 bg, --line border)
  • Kursrad: namn i --ink, hover/open → accent, meta-rad 11px --ink-3 ("N layouts" eller "N layouts · K active")
  • Expansion: 3px accent-stripe, par-chip i accent, rating-chip färg per tier (≥970 grön, ≥940 amber, <940 orange), null-rating omittas
  • Inaktiva layouter: collapsible accordion, dashed border + 65% opacity, "Last played: " om historisk, "Never played" i rött om null
  • Refresh-ikon (fa-sync-alt) snurrar via .refresh-icon.spinning
  • Chevron-ikon (fa-chevron-down) roterar 180° på .row-open och .is-open
  • Tjing-sök: skriv → resultat, klick på "Import" → kursen syns i tabellen efter HTMX-swap
  • Tjing re-import (samma kurs) — layouts kopplade till rätt course_id (inte 0)
  • FontAwesome-ikoner matchar Players (refresh + chevron)
  • Logger backend använder pino, inga console.* i src/

Notes

  • Sex commits för historik-spårbarhet (feature → fixes från code review → EJS parse-fix → ikon-parity → header → typografi). Release-workflow:n bumpar baserat på högsta prefix (minor pga feat:).
  • En orphan CSS-regel .results-link ligger kvar i courses.css (elementet togs bort i fix-fasen) — kan rensas i nästa PR, påverkar inget.
  • course-cards.ejs (mobile) tar nu total-prop men ingen query — mobile-filter är ute scope för #8 per design.
## Summary - Redesignar Courses-sidan: tabbat action-card ("Find courses" / "Import from Tjing"), results-bar, ny grid-tabell med Players-mönster (header, accent-på-hover, typografi), expanded view med par/rating-chips färgade efter tier, collapsible inaktiva layouter. - Återinför Tjing-importflödet som togs bort i `6e05d30` — `searchTjingCourses` + `getTjingCourse` mot Tjing GraphQL, `getOrCreateLayout` i `course.js`, nya endpoints `/api/tjing/search` + `/api/tjing/import/:tjingId`, klientfunktioner för sök/importera. - Bugfix på `saveCourseToDB`: `this.lastID = 0` vid `ON CONFLICT DO UPDATE` ledde till orphan-layouts vid Tjing-re-import — nu fallback till `SELECT id WHERE link = ?`. Closes #8 ## Test plan - [x] Sidan `/courses` laddar utan 500-fel - [x] Tabbat action-card: switch mellan "Find courses" och "Import from Tjing" - [x] Live-filter på "Find courses" filtrerar rader på namn + stad, `Showing N of M` uppdateras - [x] Tabellhuvud "Course / City / Last updated" matchar Players visuellt (11px uppercase, paper-2 bg, --line border) - [x] Kursrad: namn i `--ink`, hover/open → accent, meta-rad 11px `--ink-3` ("N layouts" eller "N layouts · K active") - [x] Expansion: 3px accent-stripe, par-chip i accent, rating-chip färg per tier (≥970 grön, ≥940 amber, <940 orange), null-rating omittas - [x] Inaktiva layouter: collapsible accordion, dashed border + 65% opacity, "Last played: <datum>" om historisk, "Never played" i rött om null - [x] Refresh-ikon (fa-sync-alt) snurrar via `.refresh-icon.spinning` - [x] Chevron-ikon (fa-chevron-down) roterar 180° på `.row-open` och `.is-open` - [x] Tjing-sök: skriv → resultat, klick på "Import" → kursen syns i tabellen efter HTMX-swap - [x] Tjing re-import (samma kurs) — layouts kopplade till rätt course_id (inte 0) - [x] FontAwesome-ikoner matchar Players (refresh + chevron) - [x] Logger backend använder pino, inga `console.*` i `src/` ## Notes - Sex commits för historik-spårbarhet (feature → fixes från code review → EJS parse-fix → ikon-parity → header → typografi). Release-workflow:n bumpar baserat på högsta prefix (minor pga `feat:`). - En orphan CSS-regel `.results-link` ligger kvar i `courses.css` (elementet togs bort i fix-fasen) — kan rensas i nästa PR, påverkar inget. - `course-cards.ejs` (mobile) tar nu `total`-prop men ingen `query` — mobile-filter är ute scope för #8 per design.
shcizo added 6 commits 2026-05-25 10:51:52 +02:00
- Restore src/scrapers/tjing.js with AbortController timeout (8s),
  error-object returns, and verbatim GraphQL queries
- Add getOrCreateLayout() to src/models/course.js
- New /api/tjing/search and /api/tjing/import/:tjingId routes;
  course-table route now includes layoutCount/activeLayoutCount via
  LEFT JOIN aggregation
- Rewrite courses.ejs: action-card with Find/Import tabs, results bar,
  HTMX course-table-region with body:refresh trigger
- Rewrite course-table.ejs: CSS-grid div structure replacing <table>,
  lazy-load expanded layouts via JS htmx.ajax
- Rewrite course-layouts.ejs: layout-card chips with rating tier colouring,
  collapsible inactive layouts section
- Rewrite courses.js: tab switching, live client-side filter, count display,
  Tjing search/import using DOM API (no innerHTML with untrusted data)
- Rewrite courses.css: full new design system using project tokens
- Fix saveCourseToDB returning 0 on conflict by falling back to SELECT
- Fix inactive layouts showing 'Never played' when last_played exists
- Add .icon-btn.spinning to courses.css for refresh button feedback
- Remove duplicate .btn-primary from courses.css (use shared.css version)
- Tokenize rating tier colors into --rating-tier-{high,mid,low} CSS vars
- Convert var to const/let throughout courses.js
- Fix logger.error calls to use {err} object form (pino convention)
- Extract RATING_TIER_HIGH/MID constants in course-layouts.ejs scriptlet
- Remove dead href='#' View all link from courses.ejs (deferred)
- Pass total prop explicitly from course-table.ejs to course-cards.ejs
- Remove dead #search-results-info selector from mobile.css
- Remove redundant .replace(/"/g, '&quot;') from data attributes in course-table.ejs
shcizo merged commit 6faddc6232 into main 2026-05-25 10:52:08 +02:00
Sign in to join this conversation.