4bbf6d9728
- 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
40 lines
2.0 KiB
Plaintext
40 lines
2.0 KiB
Plaintext
<% if (!courses || courses.length === 0) { %>
|
|
<p style="text-align: center; color: var(--ink-3); padding: 40px 0;">No courses found. Use "Import from Tjing" or scrape courses from PDGA.</p>
|
|
<% } else { %>
|
|
<div class="course-grid" data-total-count="<%= courses.length %>">
|
|
<% courses.forEach(function(course) {
|
|
var layoutCount = course.layoutCount || 0;
|
|
var activeLayoutCount = course.activeLayoutCount || 0;
|
|
%>
|
|
<div class="course-row expandable-row" data-course-id="<%= course.id %>" data-course-name="<%= (course.name || '').toLowerCase().replace(/"/g, '"') %>" data-course-city="<%= (course.city || '').toLowerCase().replace(/"/g, '"') %>" onclick="toggleCourseLayouts(<%= course.id %>)">
|
|
<div class="course-cell">
|
|
<span class="course-name"><%= course.name %></span>
|
|
<span class="course-meta">
|
|
<% if (layoutCount > 0) { %>
|
|
<% if (activeLayoutCount !== layoutCount) { %>
|
|
<%= layoutCount %> layouts · <%= activeLayoutCount %> active
|
|
<% } else { %>
|
|
<%= layoutCount %> layouts
|
|
<% } %>
|
|
<% } else { %>
|
|
No layouts
|
|
<% } %>
|
|
</span>
|
|
</div>
|
|
<div class="course-city"><%= course.city || '—' %></div>
|
|
<div class="course-updated"><%= course.last_updated ? new Date(course.last_updated).toISOString().slice(0,10) : '—' %></div>
|
|
<div class="course-actions">
|
|
<button class="icon-btn" onclick="event.stopPropagation(); scrapeLayouts(<%= course.id %>, this)" title="Refresh layouts">↻</button>
|
|
<button class="icon-btn icon-chev" onclick="event.stopPropagation(); toggleCourseLayouts(<%= course.id %>)" title="Expand"><i>▾</i></button>
|
|
</div>
|
|
</div>
|
|
<div class="expanded-content" id="course-layouts-<%= course.id %>">
|
|
<div class="expanded-cell">
|
|
<div class="loading">Loading layouts…</div>
|
|
</div>
|
|
</div>
|
|
<% }); %>
|
|
</div>
|
|
<%- include('course-cards', { courses: courses }) %>
|
|
<% } %>
|