host: type pages are self-documenting — definition + POPULATION
Every type post reads as schema + extension. Added host/blog--type-population (host/blog--take helper): a type's page shows its instances (posts is-a it, first 24 + count) and its subtypes (is-a / subtype-of inverses), next to the read-only type definition. Injected in host/blog-post when host/blog--is-type?. So /article/ shows what an article IS *and* which posts are articles; /card/ shows its subtypes; every card type / tag / type reads its own definition (all are is-type?). blog 194/194 (+ tests: population lists instances + count, a parent type lists subtypes, GET /article/ shows Population). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1927,6 +1927,29 @@
|
||||
(cons (quote ul) (append (quasiquote (:style "margin:0.3em 0")) rows))
|
||||
(quote (p :style "color:#999;margin:0" "No declared fields."))))
|
||||
(p :style "margin:0.4em 0 0" (b "Instances may be linked by: ") (unquote (join ", " rels)))))))))
|
||||
;; the first n elements of a list.
|
||||
(define host/blog--take
|
||||
(fn (xs n) (let loop ((ys xs) (k n) (acc (list)))
|
||||
(if (or (empty? ys) (<= k 0)) acc (loop (rest ys) (- k 1) (concat acc (list (first ys))))))))
|
||||
;; a type's POPULATION — its instances (posts is-a this type) + subtypes — shown on the type's
|
||||
;; public page next to its definition (schema + extension). Durable reads: call in a handler.
|
||||
(define host/blog--type-population
|
||||
(fn (slug)
|
||||
(let ((instances (host/blog-in slug "is-a"))
|
||||
(subtypes (host/blog-in slug "subtype-of")))
|
||||
(let ((inst-links (map (fn (s) (quasiquote (li (a :href (unquote (str "/" s "/")) (unquote s)))))
|
||||
(host/blog--take instances 24))))
|
||||
(quasiquote
|
||||
(aside :style "margin-top:1em;border:1px solid #ccc;background:#fafafa;padding:0.8em 1em;border-radius:4px"
|
||||
(h3 :style "margin:0 0 0.4em;font-size:1em"
|
||||
(unquote (str "Population — " (len instances) " instance" (if (= (len instances) 1) "" "s"))))
|
||||
(unquote (if (> (len subtypes) 0)
|
||||
(quasiquote (p :style "margin:0.2em 0" (b "Subtypes: ") (unquote (join ", " subtypes))))
|
||||
""))
|
||||
(unquote (if (> (len instances) 0)
|
||||
(cons (quote ul) (append (quasiquote (:style "margin:0.3em 0")) inst-links))
|
||||
(quote (p :style "color:#999;margin:0" "No instances yet."))))
|
||||
(unquote (if (> (len instances) 24) (quote (p :style "color:#999;margin:0" "… (showing first 24)")) ""))))))))
|
||||
|
||||
;; ── read handlers ───────────────────────────────────────────────────
|
||||
;; Post body is rendered per-block (a guarded HTML string) then injected raw.
|
||||
@@ -1957,6 +1980,7 @@
|
||||
;; a TYPE post shows its definition (fields + grammar + relations) publicly —
|
||||
;; read-only; the edit page has the writable form.
|
||||
(type-def-view (if (host/blog--is-type? slug) (host/blog--type-def-view slug) ""))
|
||||
(type-population (if (host/blog--is-type? slug) (host/blog--type-population slug) ""))
|
||||
(auth-foot (host/auth-footer req)))
|
||||
(host/blog--resp req 200
|
||||
(host/blog--page req (get r :title)
|
||||
@@ -1965,6 +1989,7 @@
|
||||
(unquote typed-block)
|
||||
(article (raw! (unquote body-html)))
|
||||
(unquote type-def-view)
|
||||
(unquote type-population)
|
||||
(unquote relations)
|
||||
(p :style "margin-top:2em;font-size:0.9em;opacity:0.8"
|
||||
(a :href (unquote (str "/" slug "/source")) "view source")
|
||||
|
||||
Reference in New Issue
Block a user