gitoriaLog in with ident

tracker

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit3251488a3251488atracker#7: /my/shows (followed shows, newest follow first, poster, title, last watched SxxEyy); gate can take screenshots (TRACKER_GATE_SHOTS)mre3251488a/styles.hl

7.7 KB

  1. // styles.hl — all of the app's CSS, served as /__hl/app.css. Components carry no Style
  2. // blocks: markup is domain tags, this file lays them out.
  3. //
  4. // TOKENS: the WorldAPI palette + semantic tokens are declared in `shared/tokens.hl` as
  5. // hl:web css variables, vendored verbatim from ident.worldapi.org (see that project's
  6. // README "Design tokens"). This file imports the tokens it uses and writes them as members;
  7. // the app sets only its accent (greenDark, per CONCEPT.md / antcolony README "look and style").
  8. //
  9. // In a styles file a bare name is a TAG (camelCase -> kebab: `emptyState` is `empty-state`),
  10. // a quoted name is a selector written verbatim. MOBILE FIRST: every rule is the phone's; the
  11. // one min-width block adds the wide layout.
  12. import { var } from 'hl:web/css'
  13. import { greenDark, colorText, colorBackground, colorTextStrong, colorBackgroundSunken, colorTextMuted, colorAccentText, colorBorder, colorDanger, colorSurface, red, blueDark } from './shared/tokens.hl'
  14. colorAccent = var(greenDark) // the app's accent: the only token this app sets
  15. // tracker.worldapi.org#4, the creator's own words: artists in red, genre pills in blue — the raw
  16. // palette tokens (like the accent above), not the semantic `colorDanger`/`colorAction` (this isn't a
  17. // warning or an action, just the creator's chosen colour for these two kinds of link/pill)
  18. colorArtist = var(red)
  19. colorGenre = var(blueDark)
  20. '*,
  21. *::before,
  22. *::after' { boxSizing = 'border-box' }
  23. html { colorScheme = 'dark' }
  24. body { margin = '0' font = '16px/1.5 system-ui, sans-serif' color = colorText background = colorBackground }
  25. a { color = colorAccent textDecoration = 'none' }
  26. 'a:hover' { textDecoration = 'underline' }
  27. h1 { margin = '0 0 1rem' fontSize = '1.3rem' lineHeight = '1.3' color = colorTextStrong }
  28. button { font = 'inherit' fontWeight = '600' padding = '.4rem .9rem' color = colorAccentText background = colorAccent border = '0' borderRadius = '.4rem' cursor = 'pointer' }
  29. 'button:hover' { filter = 'brightness(1.1)' }
  30. 'button.quiet' { color = colorText background = 'transparent' border = '0' }
  31. // the ONLY buttons with a border are inverted ones (creator: "no borders for the buttons unless they are inverted")
  32. 'button.inverted' { color = colorAccent background = 'transparent' border = '1px solid ' + colorAccent }
  33. 'button.quiet:hover' { background = colorSurface filter = 'none' }
  34. applicationHeader { position = 'sticky' top = '0' zIndex = '5' display = 'flex' flexWrap = 'wrap' alignItems = 'baseline' gap = '.2rem 1rem' padding = '.6rem 1rem' background = colorBackgroundSunken }
  35. 'application-header .brand' { fontWeight = '100' fontSize = '1.15rem' color = colorAccent }
  36. main { display = 'block' maxWidth = '60rem' margin = '0 auto' padding = '1rem' }
  37. // ---- login (top right of the header), copied from calendar.worldapi.org's styles.hl -------------
  38. userBox { display = 'flex' alignItems = 'center' gap = '.5rem' marginLeft = 'auto' }
  39. 'a.button' { display = 'inline-block' padding = '.35rem .8rem' fontWeight = '600' color = colorAccentText background = colorAccent borderRadius = '.4rem' }
  40. 'a.button:hover' { textDecoration = 'none' filter = 'brightness(1.1)' }
  41. identSelector { '--ident-accent' = colorAccent '--ident-accent-text' = colorAccentText '--ident-background' = colorSurface '--ident-border' = colorBorder '--ident-font' = '600 .9rem/1.4 system-ui, sans-serif' }
  42. 'ident-selector::part(button)' { padding = '.35rem .8rem' border = 'none' }
  43. 'ident-selector::part(status)' { padding = '.35rem .8rem' border = 'none' }
  44. 'ident-selector::part(identity)' { border = 'none' }
  45. '.message' { color = colorDanger }
  46. '.muted' { color = colorTextMuted }
  47. '.message.banner' { margin = '0' padding = '.5rem 1rem' background = colorBackgroundSunken }
  48. 'p.message:empty' { display = 'none' }
  49. // ---- /shows/:slug (tracker.worldapi.org#4) --------------------------------------------------
  50. showPage { display = 'block' }
  51. showHeader { display = 'flex' flexDirection = 'column' gap = '1rem' marginBottom = '1.5rem' }
  52. showPoster { flex = 'none' width = '10rem' }
  53. 'show-poster img' { display = 'block' width = '100%' height = 'auto' borderRadius = '.4rem' aspectRatio = '2 / 3' objectFit = 'cover' background = colorSurface }
  54. showMeta { flex = '1' }
  55. showGenres { display = 'flex' flexWrap = 'wrap' gap = '.4rem' margin = '.5rem 0' }
  56. '.genre-pill' { display = 'inline-block' padding = '.15rem .6rem' borderRadius = '1rem' fontSize = '.85rem' color = colorGenre border = '1px solid ' + colorGenre }
  57. showSummary { display = 'block' margin = '.5rem 0' color = colorText }
  58. showCast { display = 'block' margin = '.5rem 0' }
  59. '.artist-link' { color = colorArtist }
  60. '.artist-link:not(:last-child)::after' { content = "', '" color = colorTextMuted }
  61. showSeasons { display = 'block' }
  62. seasonRow { display = 'flex' alignItems = 'center' gap = '.6rem' padding = '.6rem 0' borderTop = '1px solid ' + colorBorder }
  63. 'button.season-toggle' { flex = '1' display = 'flex' alignItems = 'baseline' gap = '.6rem' justifyContent = 'flex-start' padding = '0' color = colorText background = 'transparent' border = '0' fontWeight = '600' cursor = 'pointer' textAlign = 'left' }
  64. seasonCount { fontWeight = '400' fontSize = '.85rem' color = colorTextMuted }
  65. episodeRow { display = 'flex' alignItems = 'center' gap = '.6rem' padding = '.4rem 0 .4rem 2.8rem' }
  66. episodeNumber { flex = 'none' width = '2rem' color = colorTextMuted }
  67. episodeTitle { flex = '1' }
  68. // the check: "a disc with a check in it" (drawn in CSS/SVG, no icon font) — solid (filled, accent)
  69. // once watched, regular (outline only) while not
  70. 'button.checkicon' { flex = 'none' display = 'grid' placeItems = 'center' width = '2rem' height = '2rem' padding = '0' background = 'transparent' border = '0' borderRadius = '50%' cursor = 'pointer' }
  71. '.checkicon circle' { fill = 'transparent' stroke = colorBorder strokeWidth = '1.5' }
  72. '.checkicon path' { fill = 'none' stroke = 'transparent' strokeWidth = '2' strokeLinecap = 'round' strokeLinejoin = 'round' }
  73. '.checkicon.solid circle' { fill = colorAccent stroke = colorAccent }
  74. '.checkicon.solid path' { stroke = colorAccentText }
  75. // ---- /unwatched (tracker.worldapi.org#5) ----------------------------------------------------
  76. unwatchedPage { display = 'block' }
  77. unwatchedRows { display = 'block' }
  78. unwatchedRow { display = 'flex' alignItems = 'center' gap = '.6rem' padding = '.5rem 0' borderTop = '1px solid ' + colorBorder }
  79. '.unwatched-show' { flex = 'none' fontWeight = '600' }
  80. unwatchedEpisode { flex = '1' color = colorText }
  81. unwatchedDate { flex = 'none' fontSize = '.85rem' color = colorTextMuted }
  82. // ---- /schedule (tracker.worldapi.org#6) — same row layout as /unwatched, minus the check icon -----
  83. schedulePage { display = 'block' }
  84. scheduleRows { display = 'block' }
  85. scheduleRow { display = 'flex' alignItems = 'center' gap = '.6rem' padding = '.5rem 0' borderTop = '1px solid ' + colorBorder }
  86. '.schedule-show' { flex = 'none' fontWeight = '600' }
  87. scheduleEpisode { flex = '1' color = colorText }
  88. scheduleDate { flex = 'none' fontSize = '.85rem' color = colorTextMuted }
  89. // ---- /my/shows (tracker.worldapi.org#7) — small poster, title, last watched episode ------------
  90. myShowsPage { display = 'block' }
  91. myShowsRows { display = 'block' }
  92. myShowRow { display = 'flex' alignItems = 'center' gap = '.8rem' padding = '.5rem 0' borderTop = '1px solid ' + colorBorder }
  93. 'img.myshow-poster' { flex = 'none' display = 'block' width = '2.5rem' height = 'auto' aspectRatio = '2 / 3' objectFit = 'cover' borderRadius = '.25rem' background = colorSurface }
  94. '.myshow-title' { flex = '1' fontWeight = '600' }
  95. myShowEpisode { flex = 'none' fontSize = '.9rem' color = colorTextMuted fontVariantNumeric = 'tabular-nums' }
  96. '@media (min-width: 40rem)' = {
  97. showHeader = { flexDirection = 'row' }
  98. }

Branches

Latest commits

  • 3251488atracker#7: /my/shows (followed shows, newest follow first, poster, title, last watched SxxEyy); gate can take screenshots (TRACKER_GATE_SHOTS)mre
  • 44b7d9f9tracker#6: /schedule — upcoming episodes of followed shows, soonest firstmre
  • 91c9fc8ctracker#5: /unwatched — unwatched released episodes of followed shows, newest firstmre
  • a97c0295tracker#4: show page /shows/:slug (header, seasons, episodes, watch checks) + tools/relink-episode-seasons.hlmre
  • 05f407c5tracker: no border on any button except inverted ones (Log out, ident status and identities too); header brand weight 100mre
  • 17375427tracker#2: tools/migrate.hl + tools/verify.hl — old MongoDB data into mpackdb with new idsmre
  • 31aac936tracker#3: no border on the header and on filled buttons; inverted buttons keep theirsmre
  • 2ad9d29ctracker#1: login exactly like calendar (identity selector in the header, empty homepage)mre
  • 3691e176tracker#1: empty tracker with the ident login (state of 2026-09-27)mre