Fosi Fossil Service
Small teams. Open source. Built on Fossil.

CaaS / Lamina

Unified Management for Fossil Repositories

Public | Owner: CaaS | Default branch: trunk | Last update: 2026-10-25 00:41

Artifact af71119a3ac0dc8463c73b79fb94391bc3ba5756f33da8c7274884692bb1e123:


;; 公开 Library。/library 打开第一条;/library/名称/文章 阅读对应仓库。
(defmodule lamina_library_pages
  (export all))

(defun show (req)
  (if (=:= 'true (lamina_setup:installed?))
      (render req)
      `#(redirect "/setup")))

(defun render (req)
  (let (((tuple name article) (locate req))
        (entries (lamina_library:entries)))
    (cond
      ((=:= '() entries)
       (lamina_docs_pages:html 200 (message-page req "Library" "Library has not been configured yet.")))
      ((and (=:= "" name) (=:= "" article))
       `#(redirect ,(lamina_library:entry-prefix (hd entries))))
      ('true (render-entry req entries name article)))))

(defun render-entry (req entries name article)
  (case (lamina_library:find-entry name)
    ('false
     (lamina_docs_pages:html
      404
      (shell req entries "" "Not found"
             "<article class=\"docs-body\"><h1>Page not found</h1><p>That section is not in the Library.</p></article>"
             (not-found-fragment "Not found"))))
    (`#(value ,entry)
     (case (lamina_docs:find-repo (maps:get 'repo_id entry))
       ('false
        (lamina_docs_pages:html
         200
         (shell req entries name "Library"
                "<article class=\"docs-body\"><h1>Repository missing</h1><p>The repository for this section is no longer available.</p></article>"
                (not-found-fragment "Library"))))
       (`#(value ,repo)
        (show-tree req entries entry name article repo))))))

(defun show-tree (req entries entry name article repo)
  (case (lamina_docs:serve (maps:get 'path repo)
                           (maps:get 'branch entry)
                           (lamina_library:entry-prefix entry)
                           article)
    (`#(file ,mime ,bytes)
     `#(status 200
               #M(#"content-type" ,(list_to_binary mime)
                  #"x-content-type-options" #"nosniff"
                  #"content-security-policy" #"default-src 'none'")
               ,bytes))
    (`#(article ,tree ,doc)
     (let ((title (maps:get 'title doc "")))
       (lamina_docs_pages:html
        200
        (if (fragment? req)
            (article-fragment title doc)
            (shell req entries name title
                   (list (lamina_docs_pages:sidebar (maps:get 'categories tree '()) (maps:get 'path doc))
                         (lamina_docs_pages:article-html doc))
                   (article-fragment title doc))))))
    ('unconfigured
     (lamina_docs_pages:html 200 (message-page req "Library" "Library has not been configured yet.")))
    (`#(empty ,_tree)
     (lamina_docs_pages:html
      200
      (shell req entries name name
             "<article class=\"docs-body\"><h1>No articles</h1><p>This repository has no Markdown files on the selected branch.</p></article>"
             (not-found-fragment name))))
    (`#(not-found ,tree)
     (lamina_docs_pages:html
      404
      (if (fragment? req)
          (not-found-fragment "Not found")
          (shell req entries name "Not found"
                 (list (lamina_docs_pages:sidebar (maps:get 'categories tree '()) "")
                       "<article class=\"docs-body\"><h1>Page not found</h1><p>That document is not in the selected repository.</p></article>")
                 (not-found-fragment "Not found")))))
    (`#(error ,message)
     (lamina_docs_pages:html 200 (message-page req "Library" message)))
    (_
     (lamina_docs_pages:html 200 (message-page req "Library" "The documentation could not be read.")))))

(defun locate (req)
  (let ((path (lamina_docs:decode-url-path (decode-path (cowboy_req:path req)))))
    (cond
      ((lists:prefix "/library/" path) (split-rest (lists:nthtail 9 path)))
      ('true (tuple "" "")))))

(defun split-rest (rest)
  (case (string:split rest "/" 'leading)
    (`(,name ,article) (tuple name article))
    (`(,name) (tuple name ""))
    (_ (tuple "" ""))))

(defun decode-path (path)
  (case (unicode:characters_to_list path)
    (`#(error ,_ ,_) (lamina_ui:to-str path))
    (`#(incomplete ,_ ,_) (lamina_ui:to-str path))
    (chars chars)))

(defun fragment? (req)
  (=:= "fragment" (string:lowercase (lamina_ui:to-str (cowboy_req:header #"x-lamina-docs" req #"")))))

(defun message-page (req title message)
  (shell req '() "" title
         (list "<article class=\"docs-body\"><h1>" (lamina_ui:escape title) "</h1><p>"
               (lamina_ui:escape message) "</p></article>")
         ""))

(defun shell (req entries current title inner _fragment)
  (if (fragment? req)
      (if (=:= "" _fragment) inner _fragment)
      (let* ((site (lamina_site_mgr:all))
             (site-name (maps:get 'site_name site "lamina"))
             (session (lamina_auth:verify-request req)))
        (list
         (lamina_ui:public-head (lists:flatten (list title " - Library - " site-name)) "shell docs-shell")
         (lamina_ui:public-nav site-name session 'library)
         (lamina_ui:public-tagline (maps:get 'site_tagline site ""))
         (switcher entries current)
         "<main class=\"docs\">" inner "</main>"
         (lamina_docs_pages:nav-script)
         (lamina_ui:public-footer site)
         "</div></body></html>"))))

(defun switcher (entries current)
  (if (=:= '() entries)
      ""
      (list "<nav class=\"library-nav\">"
            (lists:map
             (lambda (item)
               (let ((name (maps:get 'name item)))
                 (list "<a href=\"" (lamina_ui:escape (lamina_library:entry-prefix item)) "\""
                       (if (=:= name current) " class=\"active\"" "")
                       ">" (lamina_ui:escape name) "</a>")))
             entries)
            "</nav>")))

(defun article-fragment (title article)
  (let ((site-name (maps:get 'site_name (lamina_site_mgr:all) "lamina")))
    (list "<title>" (lamina_ui:escape (lists:flatten (list title " - Library - " site-name))) "</title>"
          (lamina_docs_pages:article-html article))))

(defun not-found-fragment (title)
  (let ((site-name (maps:get 'site_name (lamina_site_mgr:all) "lamina")))
    (list "<title>" (lamina_ui:escape (lists:flatten (list title " - Library - " site-name))) "</title>"
          "<article class=\"docs-body\"><h1>Page not found</h1><p>That document is not in the selected repository.</p></article>")))

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/CaaS/Lamina

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.