An app for logging board climbs
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: cleanup library filters

+42 -15
+1
www/index.ts
··· 8 8 import { formatStopwatchShort } from './utils/format.ts' 9 9 10 10 client.init() 11 + client.startUpdatePolling() 11 12 12 13 interface NavMeta { 13 14 title?: string
+4 -3
www/models/schema/v1.ts
··· 51 51 }) 52 52 export type Progress = z.infer<typeof Progress> 53 53 54 - export const LogFilter = z.enum(['all', 'sent', 'project', 'unattempted']) 54 + export const LogFilter = z.enum(['all', 'sent', 'unsent']) 55 55 export type LogFilter = z.infer<typeof LogFilter> 56 56 57 57 export const GradeScale = z.enum(['french', 'v']) 58 58 export type GradeScale = z.infer<typeof GradeScale> 59 59 60 - export const LibrarySortBy = z.enum(['easiest', 'hardest', 'stars', 'sends']) 60 + export const LibrarySortBy = z 61 + .enum(['easiest', 'hardest', 'stars', 'repeats', 'projects']) 61 62 export type LibrarySortBy = z.infer<typeof LibrarySortBy> 62 63 63 64 export type Preferences = { ··· 80 81 libraryGradeMin: 0, 81 82 libraryGradeMax: 16, 82 83 libraryFilter: LogFilter.enum.all, 83 - librarySortBy: LibrarySortBy.enum.easiest, 84 + librarySortBy: LibrarySortBy.enum.projects, 84 85 activeSessionId: null, 85 86 } 86 87
+1 -1
www/routes/climb.ts
··· 69 69 <ui-badge variant="success">Sent</ui-badge> 70 70 ` 71 71 : html` 72 - <ui-badge>Project</ui-badge> 72 + <ui-badge variant="info">Project</ui-badge> 73 73 ` 74 74 const stars = entry.rating ? '★'.repeat(entry.rating) : '' 75 75 return html`
+36 -11
www/routes/library.ts
··· 16 16 import { formatDate } from '../utils/format.ts' 17 17 import app from '../models/app.ts' 18 18 19 - const { all, sent, project, unattempted } = LogFilter.enum 20 - const { easiest, hardest, stars, sends } = LibrarySortBy.enum 19 + const { all, sent, unsent } = LogFilter.enum 20 + const { easiest, hardest, stars, repeats, projects } = LibrarySortBy.enum 21 21 22 22 export const PAGE_SIZE = 50 23 23 ··· 28 28 logFilter: LogFilter 29 29 sortBy: LibrarySortBy 30 30 shown: number 31 + availableGrades: number[] 31 32 } = { 32 33 search: '', 33 34 gradeMin: 0, 34 35 gradeMax: 16, 35 36 logFilter: all as LogFilter, 36 - sortBy: LibrarySortBy.enum.easiest, 37 + sortBy: LibrarySortBy.enum.projects, 37 38 shown: PAGE_SIZE, 39 + availableGrades: [], 38 40 } 39 41 40 42 export const emitter = new EventTarget() ··· 59 61 this.addEventListener('change', this.#onChange) 60 62 this.addEventListener('click', this.#onClick) 61 63 app.addEventListener(this.#onSettingsUpdate) 64 + emitter.addEventListener('grades', this.#onGrades) 62 65 } 63 66 64 67 override disconnectedCallback() { ··· 67 70 this.removeEventListener('change', this.#onChange) 68 71 this.removeEventListener('click', this.#onClick) 69 72 app.removeEventListener(this.#onSettingsUpdate) 73 + emitter.removeEventListener('grades', this.#onGrades) 74 + } 75 + 76 + #onGrades = () => { 77 + this.requestUpdate() 70 78 } 71 79 72 80 #onSettingsUpdate = () => { ··· 183 191 const opts: { value: LogFilter; label: string }[] = [ 184 192 { value: all, label: 'All' }, 185 193 { value: sent, label: 'Sent' }, 186 - { value: project, label: 'Projects' }, 187 - { value: unattempted, label: 'Unattempted' }, 194 + { value: unsent, label: 'Unsent' }, 188 195 ] 189 196 return opts 190 197 .map( ··· 199 206 private gradeGroups(): { label: string; first: number; last: number }[] { 200 207 const table = this.gradeScale === GradeScale.enum.v ? GRADE_V : GRADE_FRENCH 201 208 const groups: { label: string; first: number; last: number }[] = [] 202 - for (let i = 0; i <= 16; i++) { 209 + const grades = state.availableGrades.length > 0 210 + ? state.availableGrades 211 + : [...Array(17).keys()] 212 + for (const i of grades) { 203 213 const label = table[i] ?? '?' 204 214 const prev = groups[groups.length - 1] 205 215 if (prev && prev.label === label) { ··· 215 225 const opts: { value: LibrarySortBy; label: string }[] = [ 216 226 { value: easiest, label: 'Easiest' }, 217 227 { value: hardest, label: 'Hardest' }, 228 + { value: repeats, label: 'Repeats' }, 218 229 { value: stars, label: '★ Rating' }, 219 - { value: sends, label: 'Sends' }, 230 + { value: projects, label: 'Projects' }, 220 231 ] 221 232 return opts 222 233 .map( ··· 271 282 this.climbs = all 272 283 .filter((c) => c.boardId === this.boardId && c.angle === this.angle) 273 284 .sort(this.#sortClimbs) 285 + state.availableGrades = [...new Set(this.climbs.map((c) => c.grade))] 286 + .sort( 287 + (a, b) => a - b, 288 + ) 289 + emitter.dispatchEvent(new Event('grades')) 274 290 this.loading = false 275 291 this.applyFilters() 276 292 this.requestUpdate() ··· 308 324 this.climbs = all 309 325 .filter((c) => c.boardId === this.boardId && c.angle === this.angle) 310 326 .sort(this.#sortClimbs) 327 + state.availableGrades = [...new Set(this.climbs.map((c) => c.grade))] 328 + .sort( 329 + (a, b) => a - b, 330 + ) 331 + emitter.dispatchEvent(new Event('grades')) 311 332 } 312 333 } 313 334 this.applyFilters() ··· 349 370 } 350 371 const p = progress[c.id] 351 372 if (state.logFilter === sent) return !!p?.sent 352 - if (state.logFilter === project) return !!p && !p.sent 353 - if (state.logFilter === unattempted) return !p 373 + if (state.logFilter === unsent) return !p?.sent 354 374 return true 355 375 }) 356 376 .sort(this.#sortClimbs) ··· 360 380 const progress = app.progress 361 381 const pa = progress[a.id] 362 382 const pb = progress[b.id] 383 + const aIsProject = pa && !pa.sent 384 + const bIsProject = pb && !pb.sent 363 385 switch (state.sortBy) { 386 + case projects: 387 + return (bIsProject ? 1 : 0) - (aIsProject ? 1 : 0) || 388 + a.grade - b.grade || a.repeats - b.repeats 364 389 case easiest: 365 390 return a.grade - b.grade || a.repeats - b.repeats 366 391 case hardest: ··· 370 395 const rb = pb?.rating ?? -1 371 396 return rb - ra || a.grade - b.grade || a.repeats - b.repeats 372 397 } 373 - case sends: 398 + case repeats: 374 399 return b.repeats - a.repeats || a.grade - b.grade 375 400 } 376 401 } ··· 424 449 const badge = p?.sent 425 450 ? '<ui-badge variant="success">Sent</ui-badge>' 426 451 : p 427 - ? '<ui-badge>Project</ui-badge>' 452 + ? '<ui-badge variant="info">Project</ui-badge>' 428 453 : '' 429 454 const meta = p?.sent 430 455 ? `Sent ${formatDate(p.sent)}`