gitoriaLog in with ident

tickets

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commita75e0279a75e0279mission 010 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (456 lets → plain declarations; Hybriel refuses a plain declaration inside a loop on its 2nd pass). gate 249/0, connect 60/0, real-data reads identical, a 50-step write sequence (API + faces) identical to the old codemrea75e0279/components/styles.hl

17.4 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 (<ticket-board>, <ticket-state>, …), this file lays them out.
  3. //
  4. // TOKENS (ticket antcolony#3, mission 021): the WorldAPI palette + semantic tokens are declared in
  5. // `shared/tokens.hl` as hl:web css variables (`static colorText = var(light)`), hand-written, a
  6. // verbatim copy of loreana /media/STORAGE/projects/worldapi-tokens/tokens.hl (vendored like
  7. // plugins/; edit it THERE and cp it here). This file IMPORTS the tokens it uses and writes them as
  8. // members (`color = colorText`, `border = '1px solid ' + colorBorder`); hl:web names each token
  9. // after its member (--color-text), writes all of tokens.hl's tokens into the one :root and every
  10. // use as var(--color-text). The app sets only its accent (`colorAccent = var(…)` below, written
  11. // after the default, so it wins). hl:web does this itself since hybriel#39 (the mission-021 patch is gone).
  12. //
  13. // In a styles file a bare name is a TAG (camelCase → kebab: `ticketState` is
  14. // `ticket-state`), a quoted name is a selector written verbatim. MOBILE FIRST: every
  15. // rule is the phone's; the one min-width block adds the wide layout.
  16. import { var } from 'hl:web/css'
  17. import { purple, colorText, colorBackground, colorTextStrong, colorTextMuted, colorBackgroundSunken, colorAccentText, colorSurface, colorBorder, colorDanger, colorSuccess, colorAction, colorWarning } from '../shared/tokens.hl'
  18. colorAccent = var(purple) // the app's accent: the only token this app sets
  19. '*,
  20. *::before,
  21. *::after' { boxSizing = 'border-box' }
  22. html { colorScheme = 'dark' }
  23. body { margin = '0' font = '16px/1.5 system-ui, sans-serif' color = colorText background = colorBackground }
  24. a { color = colorAccent textDecoration = 'none' }
  25. 'a:hover' { textDecoration = 'underline' }
  26. h1 { margin = '0' fontSize = '1.3rem' lineHeight = '1.3' color = colorTextStrong overflowWrap = 'anywhere' }
  27. h2 { margin = '0 0 .5rem' fontSize = '1rem' color = colorTextStrong }
  28. time { color = colorTextMuted fontSize = '.85rem' whiteSpace = 'nowrap' }
  29. 'input,
  30. textarea,
  31. select' { font = 'inherit' width = '100%' padding = '.5rem .7rem' color = colorTextStrong background = colorBackgroundSunken border = '1px solid ' + colorBorder borderRadius = '.4rem' }
  32. 'input:focus,
  33. textarea:focus,
  34. select:focus' { outline = '2px solid ' + colorAccent outlineOffset = '1px' }
  35. textarea { resize = 'vertical' minHeight = '4.5rem' }
  36. label { display = 'grid' gap = '.25rem' fontSize = '.9rem' color = colorTextMuted }
  37. button { font = 'inherit' fontWeight = '600' padding = '.55rem 1.1rem' color = colorAccentText background = colorAccent border = '0' borderRadius = '.4rem' cursor = 'pointer' justifySelf = 'start' }
  38. 'button:hover' { filter = 'brightness(1.1)' }
  39. // ---- the shell ---------------------------------------------------------------------------
  40. applicationHeader { position = 'sticky' top = '0' zIndex = '5' display = 'flex' flexWrap = 'wrap' alignItems = 'center' gap = '.5rem 1rem' padding = '.6rem 1rem' background = colorBackgroundSunken borderBottom = '1px solid ' + colorBorder }
  41. 'application-header .brand' { fontWeight = '800' fontSize = '1.15rem' color = colorAccent marginRight = 'auto' }
  42. 'application-header nav' { display = 'flex' gap = '1rem' }
  43. 'application-header nav a' { color = colorText }
  44. inboxBadge { display = 'inline-block' marginLeft = '.35rem' padding = '0 .45rem' borderRadius = '999px' fontSize = '.8rem' fontWeight = '700' color = colorAccentText background = colorAccent }
  45. main { maxWidth = '60rem' margin = '0 auto' padding = '1rem' }
  46. // offline (mission 046, components/main.hl): the note, and the invisible probe whose animation ticks every second
  47. offlineNote { display = 'block' padding = '.5rem 1rem' color = colorTextStrong background = colorSurface borderBottom = '1px solid ' + colorBorder }
  48. netProbe { position = 'fixed' left = '0' top = '0' width = '1px' height = '1px' opacity = '0' pointerEvents = 'none' animation = 'tickets-net-tick 1s linear infinite' }
  49. '@keyframes tickets-net-tick' = {
  50. 'from' = { opacity = '0' }
  51. to = { opacity = '0' }
  52. }
  53. // ---- the login, top right (ticket #7): ident's selector (its shadow DOM in ident's design,
  54. // restyled to tickets' accent through its custom properties), the login button, who you are
  55. userBox { display = 'flex' flexWrap = 'wrap' alignItems = 'center' justifyContent = 'flex-end' gap = '.4rem .6rem' marginLeft = 'auto' maxWidth = '100%' }
  56. identSelector { '--ident-accent' = colorAccent '--ident-accent-text' = colorAccentText '--ident-background' = colorSurface '--ident-border' = colorBorder '--ident-font' = '600 .9rem/1.4 system-ui, sans-serif' }
  57. 'ident-selector::part(button)' { padding = '.35rem .8rem' }
  58. 'ident-selector::part(status)' { padding = '.35rem .8rem' }
  59. '#whoami' { fontWeight = '600' color = colorTextStrong overflowWrap = 'anywhere' }
  60. 'a.button' { display = 'inline-block' fontWeight = '600' fontSize = '.9rem' padding = '.35rem .8rem' color = colorAccent border = '1px solid ' + colorAccent borderRadius = '.4rem' }
  61. 'a.button:hover' { textDecoration = 'none' background = colorSurface }
  62. 'button.quiet' { color = colorText background = 'transparent' border = '1px solid ' + colorBorder padding = '.35rem .8rem' fontSize = '.9rem' }
  63. 'button.danger' { color = colorDanger borderColor = colorDanger }
  64. namePrompt { display = 'block' maxWidth = '60rem' margin = '1rem auto 0' padding = '0 1rem' }
  65. '#nameform' { display = 'grid' gap = '.5rem' padding = '.8rem' background = colorSurface border = '1px solid ' + colorAccent borderRadius = '.5rem' }
  66. '.banner' { maxWidth = '60rem' margin = '.8rem auto 0' padding = '0 1rem' }
  67. '.hint' { margin = '0' fontSize = '.9rem' color = colorTextMuted }
  68. '.muted' { margin = '0' fontSize = '.9rem' color = colorTextMuted }
  69. // ---- /you: the account and the API tokens ---------------------------------------------------
  70. youView { display = 'grid' gap = '1.2rem' }
  71. 'you-view section' { display = 'grid' gap = '.6rem' padding = '.8rem' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  72. 'you-view dl' { display = 'grid' gap = '.2rem' margin = '0' }
  73. 'you-view dt' { fontSize = '.85rem' color = colorTextMuted }
  74. 'you-view dd' { margin = '0 0 .4rem' color = colorTextStrong overflowWrap = 'anywhere' }
  75. 'you-view code' { overflowWrap = 'anywhere' wordBreak = 'break-all' }
  76. '#tokenform' { display = 'grid' gap = '.5rem' }
  77. tokenShown { display = 'grid' gap = '.4rem' padding = '.7rem' border = '1px solid ' + colorSuccess borderRadius = '.4rem' }
  78. 'token-shown p' { margin = '0' }
  79. '#newtoken' { color = colorSuccess fontSize = '.95rem' }
  80. '#tokenlist' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.4rem' }
  81. '#tokenlist li' { display = 'flex' flexWrap = 'wrap' alignItems = 'center' gap = '.3rem .8rem' padding = '.4rem .6rem' background = colorBackgroundSunken borderRadius = '.4rem' }
  82. '#tokenlist .label' { flex = '1 1 10rem' color = colorTextStrong overflowWrap = 'anywhere' }
  83. // ---- ticket lists (/, filters, /inbox) -----------------------------------------------------
  84. ticketBoard { display = 'grid' gap = '1rem' }
  85. ticketFilters { display = 'grid' gap = '.5rem' }
  86. 'ticket-filters nav' { display = 'flex' flexWrap = 'wrap' gap = '.35rem' }
  87. 'ticket-filters a' { padding = '.2rem .65rem' fontSize = '.85rem' color = colorText border = '1px solid ' + colorBorder borderRadius = '999px' }
  88. 'ticket-filters a.selected' { color = colorAccentText background = colorAccent borderColor = colorAccent }
  89. '.tickets' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.5rem' }
  90. '.tickets li' { display = 'grid' gridTemplateColumns = 'minmax(0, 1fr)' gap = '.3rem' padding = '.7rem .8rem' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  91. '.tickets li ticket-state' { justifySelf = 'start' }
  92. '.tickets .subject' { color = colorTextStrong fontWeight = '600' overflowWrap = 'anywhere' }
  93. ticketRef { marginRight = '.4rem' color = colorTextMuted fontWeight = '400' }
  94. formerRef { marginLeft = '.2rem' fontSize = '.85rem' color = colorTextMuted }
  95. ticketMeta { display = 'flex' flexWrap = 'wrap' gap = '.2rem .8rem' fontSize = '.85rem' }
  96. '.empty' { margin = '0' padding = '1rem' textAlign = 'center' color = colorTextMuted border = '1px dashed ' + colorBorder borderRadius = '.5rem' }
  97. '.notice' { margin = '0' color = colorSuccess }
  98. // the new-ticket form, folded away until asked for
  99. details { background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  100. summary { padding = '.6rem .8rem' cursor = 'pointer' fontWeight = '600' color = colorAccent }
  101. 'details form' { display = 'grid' gap = '.7rem' padding = '0 .8rem .8rem' }
  102. // ---- the state badge: one colour per state -------------------------------------------------
  103. ticketState { display = 'inline-block' padding = '.05rem .55rem' fontSize = '.8rem' fontWeight = '600' whiteSpace = 'nowrap' borderRadius = '999px' border = '1px solid currentColor' color = colorTextMuted }
  104. 'ticket-state.open' { color = colorAction }
  105. 'ticket-state.progress' { color = colorWarning }
  106. 'ticket-state.pending' { color = colorTextMuted }
  107. 'ticket-state.review' { color = colorAccent }
  108. 'ticket-state.reopened' { color = colorDanger }
  109. 'ticket-state.done' { color = colorSuccess }
  110. 'ticket-state.canceled' { color = colorTextMuted }
  111. 'ticket-filters a.selected.open,
  112. ticket-filters a.selected.progress,
  113. ticket-filters a.selected.pending,
  114. ticket-filters a.selected.review,
  115. ticket-filters a.selected.reopened,
  116. ticket-filters a.selected.done,
  117. ticket-filters a.selected.canceled' { color = colorAccentText }
  118. // ---- ticket #20: projects, members, assignee, the inbox ------------------------------------------
  119. projectActions { display = 'flex' flexWrap = 'wrap' gap = '.5rem' }
  120. // ticket #21: the apps connected to a project, and the connect page
  121. '.connections' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.4rem' }
  122. '.connections li' { display = 'flex' flexWrap = 'wrap' alignItems = 'center' gap = '.2rem .6rem' padding = '.4rem .8rem' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' fontSize = '.9rem' }
  123. connectPage { display = 'grid' gap = '1rem' maxWidth = '38rem' }
  124. 'connect-page form' { display = 'grid' gap = '.8rem' }
  125. projectDescription { display = 'block' padding = '.8rem' overflowWrap = 'anywhere' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  126. assignee { color = colorTextMuted }
  127. 'assignee::before' { content = '"→ "' }
  128. 'ticket-view .people' { margin = '0' color = colorTextMuted fontSize = '.9rem' }
  129. 'ticket-view .people strong' { color = colorText }
  130. 'project-form,
  131. project-settings' { display = 'grid' gridTemplateColumns = 'minmax(0, 1fr)' gap = '1rem' }
  132. 'project-form form,
  133. project-settings form,
  134. project-settings section' { display = 'grid' gap = '.6rem' }
  135. 'project-settings h1,
  136. project-settings h2' { margin = '0' }
  137. 'project-settings h2' { fontSize = '1.1rem' }
  138. '#members' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.4rem' }
  139. '#members li' { display = 'flex' flexWrap = 'wrap' alignItems = 'center' gap = '.4rem .8rem' padding = '.4rem .6rem' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.4rem' }
  140. '#members strong' { flex = '1 1 8rem' }
  141. inviteShown { display = 'block' padding = '.7rem .8rem' overflowWrap = 'anywhere' background = colorSurface border = '1px solid ' + colorAccent borderRadius = '.5rem' }
  142. 'invite-shown p' { margin = '0 0 .4rem' }
  143. '#projectlist' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.3rem' }
  144. '.role' { color = colorTextMuted fontSize = '.85rem' }
  145. '#reviewbox,
  146. #pendingbox' { display = 'grid' gap = '.5rem' }
  147. '#reviewbox h2,
  148. #pendingbox h2' { margin = '0' fontSize = '1.1rem' }
  149. // ---- one ticket ----------------------------------------------------------------------------
  150. ticketView { display = 'grid' gridTemplateColumns = 'minmax(0, 1fr)' gap = '1.2rem' }
  151. 'ticket-view header' { display = 'grid' gap = '.4rem' }
  152. 'ticket-view header p' { margin = '0' }
  153. 'ticket-view header ticket-state' { justifySelf = 'start' }
  154. 'ticket-view .dates' { color = colorTextMuted fontSize = '.85rem' }
  155. ticketSummary { display = 'block' padding = '.8rem' overflowWrap = 'anywhere' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  156. 'ticket-view section' { display = 'grid' gap = '.7rem' }
  157. '#events' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.5rem' borderLeft = '2px solid ' + colorBorder }
  158. '#events > li' { marginLeft = '.8rem' padding = '.5rem .7rem' background = colorSurface borderRadius = '.4rem' }
  159. '#events > li.state' { background = 'transparent' padding = '.2rem .7rem' }
  160. eventHead { display = 'block' fontSize = '.9rem' }
  161. 'event-head strong' { color = colorTextStrong }
  162. eventText { display = 'block' marginTop = '.3rem' overflowWrap = 'anywhere' }
  163. 'ticket-view form' { display = 'grid' gap = '.5rem' }
  164. // ---- ticket #8: the author's edit form; an edit in the history keeps what was before -------
  165. '#editform' { padding = '.8rem' background = colorSurface border = '1px solid ' + colorAccent borderRadius = '.5rem' }
  166. formButtons { display = 'flex' flexWrap = 'wrap' gap = '.5rem' }
  167. 'event-text.edit' { fontSize = '.9rem' color = colorTextMuted }
  168. 'event-text.edit p' { margin = '0' }
  169. 'event-text.edit s' { color = colorText }
  170. 'event-text.edit details' { marginTop = '.3rem' background = colorBackgroundSunken }
  171. 'event-text.edit summary' { padding = '.3rem .6rem' fontWeight = '400' fontSize = '.85rem' }
  172. 'event-text.edit markdown-text' { padding = '0 .6rem .5rem' color = colorText }
  173. // ---- ticket #6: Markdown in text fields (components/markdown.hl). Line breaks inside a
  174. // paragraph stay visible (the page showed the texts with pre-wrap before) ----------------------
  175. markdownText { display = 'block' }
  176. 'markdown-text > :first-child' { marginTop = '0' }
  177. 'markdown-text > :last-child' { marginBottom = '0' }
  178. 'markdown-text p,
  179. markdown-text li' { whiteSpace = 'pre-wrap' }
  180. 'markdown-text p' { margin = '.5rem 0' }
  181. 'markdown-text h3,
  182. markdown-text h4,
  183. markdown-text h5' { margin = '.9rem 0 .4rem' lineHeight = '1.3' color = colorTextStrong }
  184. 'markdown-text h3' { fontSize = '1.15rem' }
  185. 'markdown-text h4' { fontSize = '1.02rem' }
  186. 'markdown-text h5' { fontSize = '.95rem' }
  187. 'markdown-text ul,
  188. markdown-text ol' { margin = '.5rem 0' paddingLeft = '1.4rem' }
  189. 'markdown-text li + li' { marginTop = '.15rem' }
  190. // inside the history (itself an <ol>) a list would get the nested markers (circles)
  191. 'markdown-text ul' { listStyleType = 'disc' }
  192. 'markdown-text ol' { listStyleType = 'decimal' }
  193. 'markdown-text strong' { color = colorTextStrong }
  194. 'markdown-text a' { textDecoration = 'underline' textUnderlineOffset = '.15em' overflowWrap = 'anywhere' }
  195. 'markdown-text code' { font = '.88em/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace' padding = '.05em .3em' color = colorTextStrong background = colorBackgroundSunken borderRadius = '.25rem' }
  196. 'markdown-text pre' { margin = '.5rem 0' padding = '.6rem .7rem' overflowX = 'auto' background = colorBackgroundSunken border = '1px solid ' + colorBorder borderRadius = '.4rem' }
  197. 'markdown-text pre code' { padding = '0' background = 'transparent' whiteSpace = 'pre' }
  198. '.message' { margin = '0' minHeight = '1.5em' color = colorDanger }
  199. // ---- ticket #12 (mission 024): <md-editor> (shared/md-editor.js, shadow DOM) takes the app's
  200. // tokens through its --md-* custom properties; headings look like the rendered ones (h3/h4/h5 above)
  201. mdEditor { '--md-background' = colorBackgroundSunken '--md-text' = colorText '--md-text-strong' = colorTextStrong '--md-text-muted' = colorTextMuted '--md-border' = colorBorder '--md-accent' = colorAccent '--md-accent-text' = colorAccentText '--md-link' = colorAccent '--md-code-background' = colorSurface '--md-toolbar-background' = colorSurface '--md-danger' = colorDanger '--md-h1-size' = '1.15rem' '--md-h2-size' = '1.02rem' '--md-h3-size' = '.95rem' '--md-min-height' = '2.6rem' color = colorText }
  202. // ---- ticket #4: relations (parent, children, blocked by, blocks) ---------------------------
  203. ticketRelations { display = 'grid' gap = '.8rem' padding = '.8rem' background = colorSurface border = '1px solid ' + colorBorder borderRadius = '.5rem' }
  204. 'ticket-relations h2' { margin = '0 0 .4rem' fontSize = '1rem' }
  205. 'ticket-relations p' { margin = '0' }
  206. '#parent a,
  207. .refs a' { fontWeight = '600' whiteSpace = 'nowrap' }
  208. '.refsubject' { color = colorTextStrong overflowWrap = 'anywhere' }
  209. '#childnote' { margin = '0 0 .4rem' fontSize = '.9rem' color = colorTextMuted }
  210. '#childnote.done' { fontWeight = '600' color = colorSuccess }
  211. '.refs' { listStyle = 'none' margin = '0' padding = '0' display = 'grid' gap = '.35rem' }
  212. '.refs li' { display = 'flex' flexWrap = 'wrap' alignItems = 'baseline' gap = '.2rem .6rem' }
  213. '.refs .unblock' { padding = '.1rem .6rem' fontSize = '.8rem' marginLeft = 'auto' }
  214. '#events > li.link' { background = 'transparent' padding = '.2rem .7rem' }
  215. '@media (min-width: 45rem)' = {
  216. main = { padding = '1.5rem 1rem' }
  217. h1 = { fontSize = '1.6rem' }
  218. '.tickets li' = { gridTemplateColumns = '8.5rem minmax(0, 1fr) auto' alignItems = 'baseline' gap = '1rem' }
  219. '#stateform' = { gridTemplateColumns = '14rem minmax(0, 1fr) auto' alignItems = 'end' }
  220. '#parentform,
  221. #blockerform' = { gridTemplateColumns = 'minmax(0, 1fr) auto' alignItems = 'end' }
  222. 'details form' = { maxWidth = '40rem' }
  223. userBox = { marginLeft = '0' }
  224. }

Branches

Latest commits

  • a75e0279mission 010 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (456 lets → plain declarations; Hybriel refuses a plain declaration inside a loop on its 2nd pass). gate 249/0, connect 60/0, real-data reads identical, a 50-step write sequence (API + faces) identical to the old codemre
  • e9d5c618mission 010 (code order) 2/4: one lib/ file per topic — store.hl split into projects / tickets (+ relations) / events / tickets-helpers, util.hl shared helpers (env, storage dir, URLs, sorts, Vienna time), the function routes out of project.hl into lib/api.hl (thin; auth/filters/Accept in api-helpers.hl), invite + member-removal logic out of the faces/routes into invites.hl / tickets.hl; project.hl is the map. /login/callback gets req + the session store by reference. gate 249/0, connect 60/0, real-data reads identicalmre
  • 97e269b5mission 010 (code order) 1/4: .hl files out of the root — lib/ (store, users, connections, invites, migrate, markdown, mdview, import = ticketfile, util = localtime, jsoncheck, api-helpers = api), tools/import.hl, components/styles.hl; import paths only. gate 249/0, connect 60/0, real-data reads identicalmre
  • 38f9d10ftickets: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gate 249/0, connect 60/0mre
  • d3db6139tickets: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gate 249/0, connect 60/0mre
  • bce182e3tickets: Hybriel master 7eea0d32 (#126 memory, #48 lambda copies its argument); migrate.hl lambdas take &logmre
  • 4137be0fantcolony#40: mission references point to the moved missionsmre
  • 9bfba36aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • c7bd2645tickets: Hybriel master 73267707 (#122 fixed); compactNow workaround removed (#110 covered)mre
  • 2ab91ee9tickets: gate checks rows appear once (session sync); re-vendor to ff51cf46 stopped on hybriel#122, stays 837fe120mre
  • e01c2b1dtickets#24: installable app (manifest, service worker, offline list), own icon; gate waits for the hello's pongmre
  • 752fbb7fdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • 38bdd5e4deploy.sh: never send .git or .gitignore to Byrodinmre
  • f12fa1bcState of 2026-09-27, before the move to gitoriamre