Procházet zdrojové kódy

Rough content model doc generator.

scossu před 1 týdnem
rodič
revize
35c195c3a7
44 změnil soubory, kde provedl 333 přidání a 94 odebrání
  1. 8 7
      config/app.lua
  2. 0 17
      doc/example_bricks.txt
  3. 3 3
      doc/glossary.md
  4. 2 9
      doc/remote_submission.md
  5. 20 18
      doc/roadmap.md
  6. 2 1
      pocket_archive-scm-1.rockspec
  7. 2 2
      scratch.lua
  8. 108 0
      src/cmdoc.lua
  9. 1 1
      src/core.lua
  10. 1 3
      src/model.lua
  11. 31 20
      src/presentation.lua
  12. 0 1
      src/submission.lua
  13. 54 9
      src/util/pkar.lua
  14. 3 2
      src/util/watcher.lua
  15. 0 1
      src/validator.lua
  16. 0 0
      templates/cmdoc/head_common.html
  17. 38 0
      templates/cmdoc/index.html
  18. 51 0
      templates/cmdoc/schema.html
  19. 0 0
      templates/pres/assets/css/milligram.min.css
  20. 0 0
      templates/pres/assets/css/normalize.min.css
  21. 0 0
      templates/pres/assets/css/pkar.css
  22. 0 0
      templates/pres/assets/icons/anything.svg
  23. 0 0
      templates/pres/assets/icons/artifact.svg
  24. 0 0
      templates/pres/assets/icons/book.svg
  25. 0 0
      templates/pres/assets/icons/collection.svg
  26. 0 0
      templates/pres/assets/icons/document.svg
  27. 0 0
      templates/pres/assets/icons/info.txt
  28. 0 0
      templates/pres/assets/icons/postcard.svg
  29. 0 0
      templates/pres/assets/icons/round-search.svg
  30. 0 0
      templates/pres/assets/icons/still_image.svg
  31. 0 0
      templates/pres/assets/icons/still_image_file.svg
  32. 0 0
      templates/pres/assets/icons/text_file.svg
  33. 0 0
      templates/pres/assets/icons/video.svg
  34. 0 0
      templates/pres/assets/icons/video_file.svg
  35. 0 0
      templates/pres/assets/js/fuse.basic.min.js
  36. 0 0
      templates/pres/assets/js/fuse.min.js
  37. 0 0
      templates/pres/assets/js/fuse_init.js
  38. 0 0
      templates/pres/assets/js/search.js
  39. 0 0
      templates/pres/coll.html
  40. 0 0
      templates/pres/dres.html
  41. 9 0
      templates/pres/head_common.html
  42. 0 0
      templates/pres/header.html
  43. 0 0
      templates/pres/index.html
  44. 0 0
      templates/pres/ores.html

+ 8 - 7
config/app.lua

@@ -75,14 +75,15 @@ return {
         xsd = "http://www.w3.org/2001/XMLSchema#",
     },
 
-    -- Static and dynamic site settings.
-    site = {
-        title = "Pocket Archive demo site"
+    -- Static site (presentation) generation settings.
+    pres_gen = {
+        title = "Pocket Archive demo site",
+        out_dir = plpath.join(ROOT, "out", "pres"),
+        max_homepage_items = 12,
     },
 
-    -- Static site generation settings.
-    htmlgen = {
-        out_dir = plpath.join(ROOT, "out", "html"),
-        max_homepage_items = 12,
+    -- Content model doc generation settings.
+    cmdoc_gen = {
+        out_dir = plpath.join(ROOT, "out", "cmdoc"),
     },
 }

+ 0 - 17
doc/example_bricks.txt

@@ -1,17 +0,0 @@
-artifact01
-  |  |
-  |  *
-  |  [has_member]---------------+----------+-----------+
-  |                             |          |           |
-  *                             v          |           |
-  [first]--->page01---*[ref]--->file01     |           |
-              |                            |           |
-              |                            |           |
-              *                            v           |
-              [next]--->page02---*[ref]--->file02      |
-                         |                             |
-                         |                             |
-                         *                             v
-                         [next]--->page03---*[ref]--->file03
-
-

+ 3 - 3
doc/glossary.md

@@ -310,9 +310,9 @@ to medium size with predefined content can take advantage of a simple and
 economical static site, that needs only a simple web server to run.
 
 Pocket Archive generates static sites for presentation. It also has the option
-[*WORK IN PROGRESS*] to generate contents that can be viewed directly on the
-user's local computer with a web browser, without any web server or even any
-Internet connection.
+to generate contents that can be viewed directly on the user's local computer
+with a web browser, without any web server or even any Internet connection [WIP
+note: serverless option is not yet implemented].
 
 ## \*Submission
 

+ 2 - 9
doc/remote_submission.md

@@ -29,13 +29,6 @@ other transfer service mapping directly to a local file system is a quite
 standard and straightforward way to expose a deposit endpoint and manage
 its permissions.
 
-The other way around is also possible, i.e., mounting the watched folder on the
-machine running Pocket Archive using a network protocol (SMB, NFS). This
-obviously works well only for a single-depositor scenario, in which the mounted
-folder is always accessible to the watchdog process. Note that if the depositor
-has to mount the foler remotely as well, two network transfers are necessary to
-process the SIP.
-
 ### Note on S3
 
 S3 is not a good choice for this setup because it complicates things
@@ -58,9 +51,9 @@ pkar_watch [options] path
 ```
 
 `path` points the folder to watch. It must be a local folder or a locally
-mounted network folder (*TODO the latter is not yet tested*).
+mounted network folder [WIP note: the latter is not yet tested].
 
-Other options include: 
+Other options include:
 
 ```
     -l, --loglevel <number> (default: 3)

+ 20 - 18
doc/roadmap.md

@@ -50,10 +50,12 @@ usage and opportunities for expanding adoption in relevant areas.
 
 - ✖︎ Management UI & API
   - ✖︎ Deposit via single tar or zip file submission
-- ✓ Deposit via local hot folder
-  - ✓ Watch local folder and trigger deposit
-  - ✓ Option to regenerate site after deposit
-  - ✓ Option to clean up sources & LL on success
+- ⚒ submission
+  - ✓ Watch local folder and trigger submission
+    - ✓ Option to regenerate site after submission
+    - ✓ Option to clean up sources & LL on success
+  - ❏ Submission report
+  - ❏ Deleting resources
 - ✓ Proper collection handling
   - ✓ Dedicated template
   - ✓ Link to markdown doc for presentation page
@@ -62,15 +64,12 @@ usage and opportunities for expanding adoption in relevant areas.
   - ✓ Dump archive RDF
   - ❏ Backup full environment (including config)
   - ❏ Restore whole archive from RDF & data folder
-- ❏ Submission
-  - ❏ Deleting resources
-- ❏ Content model
+- ⚒ Content model
+  - ⚒ Generate content model documentation (HTML)
   - ❏ Multilingual support
-  - ❏ Content model dump for users (CSV?)
+  - ⚒ Content model dump (CLI)
   - ❏ Local overrides
-  - ❏ Relatioships inference
-  - ❏ Markdown support for individual fields
-- ⚒ Generator
+- ⚒ Presentation
   - ⎊ Generate site for one collection only
   - ✓ Generate LL for submission
   - ❏ htmlgen option for local file or webserver URL generation
@@ -81,25 +80,28 @@ usage and opportunities for expanding adoption in relevant areas.
   - ❏ Category browsing
   - ❏ Improve search indexing
 - ❏ Testing
-    - ❏ Unit tests
+    - ❏ Unit tests (Busted)
     - ⚒ Roundtrip submission, download LL, update, resubmission
     - ⚒ >100 resource data set
 - ⚒ Documentation
   - ✓ Break main sections off README
   - ✓ Watchdog process guide
-  -  Submission guide
-  -  Content modeling primer (archivist)
+  -  Submission guide
+  -  Content modeling primer (archivist)
   - ⚒ Content modeling manual (sysadmin)
-  -  Glossary
+  -  Glossary
   - ❏ Site generation guide
+  - ❏ API documentation (ldoc)
 
-## Post-release
+## Post-release wishlist
 
 - ✖︎ Deposit via remote hot folder
   - FTP [Addressed by separate FTP server]
-  - S3 [Not a good choice - implementations such as MinIO mangle all files and an additional S3 pull is required to get the deposited files. Not efficient.]
+  - S3 [Not a good choice - See remote deposit guide]
+- Schema definition validator
 - Incremental build
 - Rebuild only site assets
 - Custom templating
-- Deposit via S3 source pointer
+- Auto relatioships inference
+- Markdown support for property values
 

+ 2 - 1
pocket_archive-scm-1.rockspec

@@ -44,7 +44,8 @@ build = {
         ["pocket_archive.validator"] = "src/validator.lua",
         ["pocket_archive.submission"] = "src/submission.lua",
         ["pocket_archive.repo"] = "src/repo.lua",
-        ["pocket_archive.generator"] = "src/generator.lua",
+        ["pocket_archive.presentation"] = "src/presentation.lua",
+        ["pocket_archive.cmdoc"] = "src/cmdoc.lua",
         ["pocket_archive.transformers"] = "src/transformers.lua",
         ["pocket_archive.monocypher"] = {
             "ext/monocypher/monocypher.c",

+ 2 - 2
scratch.lua

@@ -5,9 +5,9 @@ local graph = require "volksdata.graph"
 local store = require "volksdata.store"
 
 local pkar = require "pocket_archive"
+local pres = require "pocket_archive.presentation"
 local sub = require "pocket_archive.submission"
 local val = require "pocket_archive.validator"
-local hgen = require "pocket_archive.html_generator"
 
 
 --[[
@@ -19,4 +19,4 @@ sip = sub.generate_sip(
 sub.deposit(sip)
 --]]
 
-html = hgen.generate_site()
+html = pres.generate_site()

+ 108 - 0
src/cmdoc.lua

@@ -0,0 +1,108 @@
+--[[--
+Content model documentation generator module.
+
+This module contains functions to generate HTML documentation pages for the
+archive's content model, that can be distributed to archivists tasked with
+submitting content.
+
+@module pocket_archive.cmdoc
+]]
+
+
+local datafile = require "datafile"
+local etlua = require "etlua"
+local dir = require "pl.dir"
+local path = require "pl.path"
+local pp = require "pl.pretty"
+
+local pkar = require "pocket_archive"
+local logger = pkar.logger
+local model = require "pocket_archive.model"
+
+
+-- HTML templates. Compile them only once.
+-- TODO Add override for user-maintained templates.
+local templates = {
+    idx     = {file = "index.html"},
+    schema  = {file = "schema.html"},
+    head    = {file = "head_common.html"},
+}
+for _, tpl in pairs(templates) do
+    local fh = datafile.open(path.join("templates", "cmdoc", tpl.file))
+    tpl.data = assert(etlua.compile(fh:read("a")))
+end
+
+
+-- cmdoc module.
+local M = {
+    out_dir = pkar.config.cmdoc_gen.out_dir,
+}
+
+
+M.generate_schema = function(id)
+    local tpl = templates.schema
+
+    local schema = model.types[id]
+    local schema_pres = {
+        attr = {
+            id = id,
+            label = schema.label,
+            uri = schema.uri,
+            description = schema.description,
+            broader = schema.broader,
+            abstract = schema.abstract or false,
+        },
+        properties = {},
+    }
+
+    -- Sort properties alphabetically.
+    for k, v in pairs(schema.properties) do
+        table.insert(schema_pres.properties, {k, v})
+    end
+    table.sort(schema.properties, function(a, b) return a[1] < b[1] end)
+    logger:debug("Generating doc for schema:")
+    logger:debug(pp.write(schema_pres))
+
+    data = tpl.data({
+        site_title = pkar.config.pres_gen.title,
+        schema = schema_pres,
+        head_tpl = templates.head.data,
+    })
+    local ofh = assert(io.open(
+        path.join(M.out_dir, "schema", id .. ".html"), "w"))
+    ofh:write(data)
+    ofh:close()
+
+    return true
+end
+
+
+M.generate_index = function()
+    local tpl = templates.idx
+    local types = {}
+    for tname, schema in pairs(model.types) do
+        table.insert(types, {id = tname, label = schema.label})
+    end
+    table.sort(types, function(a, b) return a.label < b.label end)
+
+    data = tpl.data({
+        site_title = pkar.config.pres_gen.title,
+        types = types,
+        head_tpl = templates.head.data,
+    })
+    local ofh = assert(io.open(path.join(M.out_dir, tpl.file), "w"))
+    ofh:write(data)
+    ofh:close()
+
+    return true
+end
+
+
+M.generate_doc = function()
+    dir.makepath(path.join(M.out_dir, "schema"))
+    for id in pairs(model.types) do assert(M.generate_schema(id)) end
+    assert(M.generate_index())
+end
+
+
+return M

+ 1 - 1
src/core.lua

@@ -1,8 +1,8 @@
 local datafile = require "datafile"
 local dir = require "pl.dir"
 local path = require "pl.path"
-local store = require "volksdata.store"
 
+local store = require "volksdata.store"
 local term = require "volksdata.term"
 local nsm = require "volksdata.namespace"
 

+ 1 - 3
src/model.lua

@@ -7,8 +7,6 @@ local nsm = require "volksdata.namespace"
 local pkar = require "pocket_archive"
 local logger = pkar.logger
 
-local dbg = require "debugger"
-
 
 -- "nil" table.
 local NT = {}
@@ -40,7 +38,7 @@ local M = {
 }
 
 M.from_uri = function(type_uri)
-    dbg.assert(type_uri)
+    assert(type_uri)
     return M.types[M.uri_to_id[nsm.denormalize_uri(type_uri.data)]]
 end
 

+ 31 - 20
src/generator.lua → src/presentation.lua

@@ -1,3 +1,13 @@
+--[[--
+Presentation generator module.
+
+This module contains all functions to generate HTML pages and all other assets
+required to run a static site from an archive.
+
+@module pocket_archive.presentation
+]]
+
+
 local csv = require "ftcsv"
 local datafile = require "datafile"
 local dir = require "pl.dir"
@@ -19,8 +29,6 @@ local repo = require "pocket_archive.repo"
 local get_single_v = repo.get_single_v
 local transformers = require "pocket_archive.transformers"
 
-local dbg = require "debugger"
-
 
 -- "nil" table - for missing key fallback in chaining.
 local NT = {}
@@ -28,7 +36,8 @@ local NT = {}
 -- Extension for type-based icon files.
 local ICON_EXT = ".svg"
 
-local asset_dir = pkar.config.htmlgen.out_dir
+local src_asset_dir = datafile.path("templates/pres/assets")
+local asset_dir = pkar.config.pres_gen.out_dir
 local index_path = path.join(asset_dir, "js", "fuse_index.json")
 local keys_path = path.join(asset_dir, "js", "fuse_keys.json")
 local idx_ignore = {first = true, next = true}
@@ -46,23 +55,24 @@ local templates = {
     header  = {file = "header.html"},
 }
 for _, tpl in pairs(templates) do
-    local fh = datafile.open(path.join("templates", tpl.file))
+    local fh = datafile.open(path.join("templates", "pres", tpl.file))
     tpl.data = assert(etlua.compile(fh:read("a")))
 end
 
 
--- HTML generator module.
+-- Presentation generator module.
 local M = {
-    res_dir = path.join(pkar.config.htmlgen.out_dir, "res"),
+    res_dir = path.join(pkar.config.pres_gen.out_dir, "res"),
+    src_asset_dir = src_asset_dir,
     asset_dir = asset_dir,
     icon_dir = path.join(asset_dir, "icons"),
-    media_dir = path.join(pkar.config.htmlgen.out_dir, "media"),
+    media_dir = path.join(pkar.config.pres_gen.out_dir, "media"),
     webroot = "",  -- TODO switch depending on local FS or webserver generation.
 }
 
-local MEDIA_WEB_PATH = M.media_dir:gsub(pkar.config.htmlgen.out_dir, "")
+local MEDIA_WEB_PATH = M.media_dir:gsub(pkar.config.pres_gen.out_dir, "")
 local TN_FS_PATH = path.join(M.media_dir, "thumbnail")
-local TN_WEB_PATH = TN_FS_PATH:gsub(pkar.config.htmlgen.out_dir, "")
+local TN_WEB_PATH = TN_FS_PATH:gsub(pkar.config.pres_gen.out_dir, "")
 
 
 -- Get model configuration from subject URI.
@@ -207,7 +217,7 @@ local function generate_coll(s, mconf)
 
     out_html = templates.coll.data({
         --webroot = M.webroot,
-        site_title = pkar.config.site.title,
+        site_title = pkar.config.pres_gen.title,
         title = (title or NT).data or "[No title]",
         description = (description or NT).data,
         body = body,
@@ -341,7 +351,7 @@ local function generate_dres(s, mconf)
 
     out_html = templates.dres.data({
         --webroot = M.webroot,
-        site_title = pkar.config.site.title,
+        site_title = pkar.config.pres_gen.title,
         title = title or s.data,
         head_tpl = templates.head.data,
         header_tpl = templates.header.data,
@@ -434,7 +444,7 @@ local function generate_ores(s, mconf)
     dest = path.join(dest_dir, dest_fname)
     assert(transformers[pres_conf.fn](
             res_path[1], dest, table.unpack(pres_conf or NT)))
-    local pres = dest:gsub(pkar.config.htmlgen.out_dir, "")
+    local pres = dest:gsub(pkar.config.pres_gen.out_dir, "")
     logger:debug("Presentation file: ", pres)
 
     -- Thumbnail.
@@ -452,7 +462,7 @@ local function generate_ores(s, mconf)
 
     out_html = templates.ores.data({
         --webroot = M.webroot,
-        site_title = pkar.config.site.title,
+        site_title = pkar.config.pres_gen.title,
         fname = path.basename(techmd.source_path[1]),
         head_tpl = templates.head.data,
         header_tpl = templates.header.data,
@@ -679,7 +689,7 @@ M.generate_homepage = function()
     )
     local i = 1
     for s in s_ts:iter() do
-        if i > (pkar.config.htmlgen.max_homepage_items or 10) then break end
+        if i > (pkar.config.pres_gen.max_homepage_items or 10) then break end
 
         table.insert(idx_data.objects, {
             href = pkar.gen_pairtree("/res", s.data, ".html", true),
@@ -715,14 +725,14 @@ M.generate_homepage = function()
 
     out_html = templates.idx.data({
         webroot = M.webroot,
-        site_title = pkar.config.site.title,
+        site_title = pkar.config.pres_gen.title,
         head_tpl = templates.head.data,
         header_tpl = templates.header.data,
         nsm = nsm,
         idx_data = idx_data,
     })
 
-    local idx_path = path.join(pkar.config.htmlgen.out_dir, "index.html")
+    local idx_path = path.join(pkar.config.pres_gen.out_dir, "index.html")
     local ofh = assert(io.open(idx_path, "w"))
 
     logger:debug("Writing info at ", idx_path)
@@ -737,9 +747,9 @@ M.reset_site = function()
     -- Reset target folders.
     -- TODO for larger sites, a selective update should be implemented by
     -- comparing RDF resource timestamps with HTML page timestamps. Post-MVP.
-    if path.isdir(pkar.config.htmlgen.out_dir) then
+    if path.isdir(pkar.config.pres_gen.out_dir) then
         logger:warn("Removing existing web site.")
-        dir.rmtree(pkar.config.htmlgen.out_dir)
+        dir.rmtree(pkar.config.pres_gen.out_dir)
     end
 
     -- Recreate asset dir.
@@ -750,9 +760,10 @@ M.reset_site = function()
     dir.makepath(M.asset_dir)
 
     -- Copy static assets.
-    logger:info("Copying templates dir " .. datafile.path("templates/assets") .. " to " .. M.asset_dir)
+    logger:info(
+        "Copying templates dir " .. M.src_asset_dir .. " to " .. M.asset_dir)
     assert(dir.clonetree(
-        datafile.path("templates/assets"),
+        M.src_asset_dir,
         M.asset_dir, dir.copyfile)
     )
 end

+ 0 - 1
src/submission.lua

@@ -41,7 +41,6 @@ local repo = require "pocket_archive.repo"
 local validator = require "pocket_archive.validator"
 
 local logger = pkar.logger
-local dbg = require "debugger"
 
 -- "nil" table - for missing key fallback in chaining.
 local NT = {}

+ 54 - 9
src/util/pkar.lua

@@ -1,6 +1,7 @@
 #!/usr/bin/lua
 
 local cli = require "cli"
+local json = require "cjson"
 local plpath = require "pl.path"
 
 local nsm = require "volksdata.namespace"
@@ -9,11 +10,11 @@ local triple = require "volksdata.triple"
 local graph = require "volksdata.graph"
 
 local pkar = require "pocket_archive"
-local sub = require "pocket_archive.submission"
+local cmdoc = require "pocket_archive.cmdoc"
+local model = require "pocket_archive.model"
+local pres = require "pocket_archive.presentation"
 local repo = require "pocket_archive.repo"
-local gen = require "pocket_archive.generator"
-
-local dbg = require "debugger"
+local sub = require "pocket_archive.submission"
 
 
 cli.locale "en_US"  -- TODO set with multilingual support.
@@ -29,7 +30,7 @@ init = cli.command {
             io.write("Alright, you asked for it.\n")
             repo.reset_store()
             sub.reset_ores()
-            gen.reset_site()
+            pres.reset_site()
         else io.write("Chicken out.\n")
         end
     end
@@ -63,7 +64,7 @@ deposit = cli.command {
 gen_site = cli.command {
     "Generate a static site from the archive.",
 
-    function(args) gen.generate_site() end
+    function(args) pres.generate_site() end
 }
 
 dump_res = cli.command {
@@ -117,17 +118,17 @@ dump_ll = cli.command {
         if args.id:find("^sub:") then
             -- Dump whole submission.
             --[[
-            local co = coroutine.create(gen.generate_sub_ll)
+            local co = coroutine.create(pres.generate_sub_ll)
             while true do
                 local r, res = coroutine.resume(co, s)
                 if not r then break end
                 if res then io.write(res) end
             end
             --]]
-            io.write(gen.generate_sub_ll(s))
+            io.write(pres.generate_sub_ll(s))
         else
             -- One resource only.
-            io.write(gen.generate_res_ll(s))
+            io.write(pres.generate_res_ll(s))
         end
         io.close()  -- This will fail for io.stdout, but it's OK.
         if args.output ~= io.stdout then
@@ -156,6 +157,50 @@ dump_archive = cli.command {
 }
 
 
+list_ctypes = cli.command {
+    "List all content types.",
+
+    function(args)
+        for tname in pairs(model.types) do
+            io.write(tname)
+            io.write("\n")
+        end
+    end,
+}
+
+
+dump_schema = cli.command {
+    "Generate a structured representation ofa content type schema as JSON.",
+
+    cli.positional "ctype" {
+        "Content type name.",
+        type = cli.string,
+    },
+
+    function(args)
+        local schema = model.types[args.ctype]
+        if not schema then
+            print("No such content type: ", ctype)
+            return 1
+        end
+
+        io.write(json.encode(schema))
+        io.write("\n")
+    end,
+}
+
+
+gen_cmdoc = cli.command {
+    "Generate a static website with content model documentation.",
+
+    function(args)
+        cmdoc.generate_doc()
+
+        io.write("Documentation generated at " .. cmdoc.out_dir .. "\n")
+    end,
+}
+
+
 cli.program {
     "Pocket Archive command line interface.",
 }

+ 3 - 2
src/util/watcher.lua

@@ -2,14 +2,15 @@
 
 local cli = require "cli"
 local plpath = require "pl.path"
+local posix = require "posix"
 local signal = require "posix.signal"
 local sllog = require "sllog"
 local watchdog = require "watchdog"
 
 local pkar = require "pocket_archive"
 local logger = pkar.logger
+local pres = require "pocket_archive.presntation"
 local sub = require "pocket_archive.submission"
-local gen = require "pocket_archive.generator"
 
 
 local running = true
@@ -68,7 +69,7 @@ cli.program {
         logger:info("D-Res path: ", pkar.config.fs.dres_path)
         logger:info("O-Res path: ", pkar.config.fs.ores_path)
         if args.gen_site then
-            logger:info("Generating website at: ", pkar.config.htmlgen.out_dir)
+            logger:info("Generating website at: ", pkar.config.pres_gen.out_dir)
         end
         logger:info("* * * * * * * * * *")
 

+ 0 - 1
src/validator.lua

@@ -5,7 +5,6 @@ local pkar = require "pocket_archive"
 local model = require "pocket_archive.model"
 
 local logger = pkar.logger
-local dbg = require "debugger"
 
 
 local E_TYPE = "Type error"

+ 0 - 0
templates/head_common.html → templates/cmdoc/head_common.html


+ 38 - 0
templates/cmdoc/index.html

@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <%- head_tpl({site_title = site_title, title = "Content model documentation"}) %>
+    </head>
+    <body>
+        <main>
+            <h1 class="title"><%= site_title %>: Content model documentation</h1>
+            <section id="descr">
+                <p>This is the content model documentation for the currently
+                running instance of Pocket Archive. Each instance may have its
+                own content model.</p>
+                <p>If you are an archivist looking for instructions on how to
+                use the content model for submissions, see the <a
+                href="https://git.knowledgetx.com/scossu/pocket_archive/src/master/doc/content_model_primer.md">content
+                modeling primer</a> documentation.</p>
+                <p>If you are a system administrator looking for a guide to setting up
+                a content model, see the
+                <a href="https://git.knowledgetx.com/scossu/pocket_archive/src/master/doc/content_model_manual.md">content
+                model guide</a> (work in progress).</p>
+            </section>
+            <section id="cm_list">
+                <h2>Content types</h2>
+                <p>Below are the content types defined for this archive and
+                the links to their schema definitions:</p>
+                <ul>
+                <% for _, schema in ipairs(types) do %>
+                    <li><a href="schema/<%= schema.id -%>.html">
+                        <%= schema.label %>
+                    </a></li>
+                <% end %>
+                </ul>
+            </section>
+        </main>
+        <footer></footer>
+    </body>
+</html>
+

+ 51 - 0
templates/cmdoc/schema.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <%- head_tpl({
+            site_title = site_title,
+            title = "Schema: " .. schema.attr.label,
+        }) %>
+    </head>
+    <body>
+        <main>
+            <h1 class="title">Schema: <%= schema.attr.label %></h1>
+            <section id="schema_attr">
+                <h2>Attributes</h1>
+                <dl class="schema_md">
+                <% for k, v in pairs(schema.attr) do %>
+                    <dt><%= k %></dt>
+                    <dd><%= v %></dd>
+                <% end %>
+                </dl>
+            </section>
+            <section id="schema_prop">
+                <h2>properties</h1>
+                <dl class="schema_md">
+                <% for _, prop in ipairs(schema.properties) do %>
+                    <% local k, def = table.unpack(prop) %>
+                    <dt><%= k %></dt>
+                    <dd>
+                        <dl>
+                        <% for def_n, def_v in pairs(def) do %>
+                            <dt><%= def_n %></dt>
+                            <% if type(def_v) == "table" then %>
+                                <% for def_kk in pairs(def_v) do %>
+                                    <dd><%= def_kk %></dd>
+                                <% end %>
+                                <% for _, def_vv in ipairs(def_v) do %>
+                                    <dd><%= def_vv %></dd>
+                                <% end %>
+                            <% else %>
+                                <dd><%= def_v %></dd>
+                            <%end %>
+                        <% end %>
+                        </dl>
+                    </dd>
+                <% end %>
+                </dl>
+            </section>
+        </main>
+        <footer></footer>
+    </body>
+</html>
+

+ 0 - 0
templates/assets/css/milligram.min.css → templates/pres/assets/css/milligram.min.css


+ 0 - 0
templates/assets/css/normalize.min.css → templates/pres/assets/css/normalize.min.css


+ 0 - 0
templates/assets/css/pkar.css → templates/pres/assets/css/pkar.css


+ 0 - 0
templates/assets/icons/anything.svg → templates/pres/assets/icons/anything.svg


+ 0 - 0
templates/assets/icons/artifact.svg → templates/pres/assets/icons/artifact.svg


+ 0 - 0
templates/assets/icons/book.svg → templates/pres/assets/icons/book.svg


+ 0 - 0
templates/assets/icons/collection.svg → templates/pres/assets/icons/collection.svg


+ 0 - 0
templates/assets/icons/document.svg → templates/pres/assets/icons/document.svg


+ 0 - 0
templates/assets/icons/info.txt → templates/pres/assets/icons/info.txt


+ 0 - 0
templates/assets/icons/postcard.svg → templates/pres/assets/icons/postcard.svg


+ 0 - 0
templates/assets/icons/round-search.svg → templates/pres/assets/icons/round-search.svg


+ 0 - 0
templates/assets/icons/still_image.svg → templates/pres/assets/icons/still_image.svg


+ 0 - 0
templates/assets/icons/still_image_file.svg → templates/pres/assets/icons/still_image_file.svg


+ 0 - 0
templates/assets/icons/text_file.svg → templates/pres/assets/icons/text_file.svg


+ 0 - 0
templates/assets/icons/video.svg → templates/pres/assets/icons/video.svg


+ 0 - 0
templates/assets/icons/video_file.svg → templates/pres/assets/icons/video_file.svg


+ 0 - 0
templates/assets/js/fuse.basic.min.js → templates/pres/assets/js/fuse.basic.min.js


+ 0 - 0
templates/assets/js/fuse.min.js → templates/pres/assets/js/fuse.min.js


+ 0 - 0
templates/assets/js/fuse_init.js → templates/pres/assets/js/fuse_init.js


+ 0 - 0
templates/assets/js/search.js → templates/pres/assets/js/search.js


+ 0 - 0
templates/coll.html → templates/pres/coll.html


+ 0 - 0
templates/dres.html → templates/pres/dres.html


+ 9 - 0
templates/pres/head_common.html

@@ -0,0 +1,9 @@
+<meta charset="utf-8"/>
+<!-- Milligram CSS -->
+<link rel="stylesheet" href="/css/normalize.min.css">
+<link rel="stylesheet" href="/css/milligram.min.css">
+<link rel="stylesheet" href="/css/pkar.css">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title><%= title %>&emsp;&#x2741;&emsp;<%= site_title %></title>
+

+ 0 - 0
templates/header.html → templates/pres/header.html


+ 0 - 0
templates/index.html → templates/pres/index.html


+ 0 - 0
templates/ores.html → templates/pres/ores.html