Type: list

A list is the minimal container: a plain list-group-flush rendering of sibling slugs, each as a hyperlink. No icons, no per-row description, no markdown blurb — list pages stay simple text. Rendering lives in src/content/list.rs.

If you want icons and descriptions in the index, use a board instead. The two types share field shapes (name, desc, icon, content) but differ in rendering.

Rendering style

<ul class="list-group list-group-flush" id="name">
    <li class="list-group-item"><h5 class="mb-0">Policies</h5></li>
    <li class="list-group-item"><a href="constitution/">Constitution</a></li>
    ...
</ul>

This is the original list-group-flush chrome. The only deliberate change from the older <b>-wrapped title is the <h5 class="mb-0"> tag, so the title typography lines up with board cards across pages. Beyond that, list rendering stays simple — by design: full board-card chrome was considered and explicitly not applied to lists.

The name of the list itself (from its Header) is shown as the first <li>, even though the parent that linked to this list already displays the same name. The list’s own desc and icon are not rendered on the list page itself; they exist so a parent board / board_group row can show this list with the right name, icon, and one-line blurb.

ctx.json shape

{
    "type": "list",
    "name": {
        "en": "Policies",
        "ja": "規約",
        "zh": "政策"
    },
    "desc": {
        "en": "Rules and agreements that govern FDS — charter, copyright, administration, and membership.",
        "ja": "FDSを定める規約・契約 — 基本法、著作権、管理、加入。",
        "zh": "FDS 的规则与协议 —— 基本法、版权、管理与加入。"
    },
    "icon": "/images/svg/policy/",
    "content": [
        "constitution",
        "default_copyright",
        "admin",
        "join",
        "members"
    ]
}

Field reference

FieldTypeRequiredNotes
type"list"yesExact discriminator string.
namestring or LangDictyesSee Common: Header and LangDict.
descstring or LangDictnoStored but not rendered on the list page itself; used by a parent that references this list.
iconstringnoSame resolution rules as board; used by a parent that references this list.
contentarray of stringsyesSibling subdirectory slugs.

content semantics

Same as board: a flat array of slug strings, each matching a sibling subdirectory that contains its own ctx.json. Parsing goes through the shared parse_slug_list helper, so the legacy {file: "slug"} shape also works. New entries should always be plain strings.

Render flow

  1. List::read(path) reads ctx.json, builds a Header, and parses the slug list.
  2. List::render opens the <ul>, writes the title <li>, then for each slug:
    • reads the child’s ctx.json if present, falling back to Header::fallback(slug) if missing or unparseable.
    • writes <li><a href="slug/">name</a></li> using the child’s resolved name. No icon, no description.

Editor capabilities

The edit route supports, against a List:

  • rename(lang, new_name) — per-lang rename.
  • set_icon(icon) — empty clears.
  • set_desc(lang, desc) — empty clears that lang; emptying all langs drops desc from disk.
  • add_item(slug), remove_item(idx), move_item(from, to) — manipulate the slug list.

Because the list page itself does not render icon or desc, those fields only matter when this list is referenced by a parent — but editing them is still supported and useful for that purpose.

Save

List::save() rebuilds ctx.json from scratch:

let mut ctx = object!({});
ctx.set("type", "list");
self.header.write_into(&mut ctx);  // drops empty icon / desc
ctx.set("content", <slugs as JSON array>);
fop::write_json_file(ctx_path, &ctx);

Rebuilding from scratch is the only reliable way to drop a cleared optional field. The comment on List::save() explicitly calls this out — without the rebuild, a cleared icon, desc, or banner would linger on disk.

Gotchas

  • remove_item / move_item return Err(io::Error{InvalidInput}) for out-of-range indices — same contract as board.
  • content must be a string array. The shared parse_slug_list will also accept {file: "slug"} objects, but the board_group / board_list section-object shape ({name, items}) will silently parse to empty here — set type correctly so the right reader runs.
  • The list’s own desc / icon are not visible on the list page itself. Editors confused that “I set a desc and nothing changed” should be pointed at the parent container.
  • The list’s title is rendered as <h5 class="mb-0">, matching board card headings. Don’t add Markdown to name expecting it to compile — name is treated as a plain string, only desc is markdown-compiled (and only on pages where it is rendered, which is not this one).