-*- mode: org -*-
#+TITLE:       spine (doc_manifest) metadata (multidocument) curates
#+DESCRIPTION: documents - structuring, various output representations & search
#+FILETAGS:    :spine:hub:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2023 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+PROPERTY:    header-args  :exports code
#+PROPERTY:    header-args+ :noweb yes
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no
#+PROPERTY:    header-args+ :mkdirp yes
#+OPTIONS:     H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t

- [[./doc-reform.org][doc-reform.org]]  [[./][org/]]

* document curate _summary_ :module:spine:metadoc_show_summary:

- html
  ~dr/bin/spine-ldc -v --html --html-link-curate --curate \
    --output=/var/www/html \
    ~grotto/repo/git.repo/code/project-spine/doc-reform-markup/markup_samples/markup/pod/*

** _module template_ metadoc curate

#+HEADER: :tangle "../src/doc_reform/meta/metadoc_curate.d"
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<doc_header_including_copyright_and_license>>
module doc_reform.meta.metadoc_curate;
template spineMetaDocCurate() {
  @safe auto spineMetaDocCurate(T,H)(
    T  doc_matters,
    H  hvst,
  ) {
    <<metadoc_curate_imports>>
    mixin InternalMarkup;
    <<metadoc_curate_initialize>>
    <<meta_metadoc_curate>>
  }
}
#+END_SRC

** init
*** imports

#+NAME: metadoc_curate_imports
#+BEGIN_SRC d
import
  doc_reform.meta.defaults,
  doc_reform.meta.rgx;
import
  std.array,
  std.exception,
  std.regex,
  std.stdio,
  std.string,
  std.typecons,
  std.uni,
  std.utf,
  std.conv : to;
#+END_SRC

*** initialize :report:

#+NAME: metadoc_curate_initialize
#+BEGIN_SRC d
static auto mkup = InlineMarkup();
#+END_SRC

** curate summary

#+NAME: meta_metadoc_curate_summary
#+BEGIN_SRC d
auto min_repeat_number = 66;
auto char_repeat_number = (doc_matters.conf_make_meta.meta.title_full.length
  + doc_matters.conf_make_meta.meta.creator_author.length + 4);
char_repeat_number = (char_repeat_number > min_repeat_number)
? char_repeat_number
: min_repeat_number;
writefln(
  "%s\n\"%s\", %s\n%s\n%s\n%s",
  mkup.repeat_character_by_number_provided("-", char_repeat_number),
  doc_matters.conf_make_meta.meta.title_full,
  doc_matters.conf_make_meta.meta.creator_author,
  doc_matters.src.filename,
  doc_matters.conf_make_meta.meta.classify_topic_register_arr,
  mkup.repeat_character_by_number_provided("-", char_repeat_number),
);
#+END_SRC

** return curate

#+NAME: meta_metadoc_curate
#+BEGIN_SRC d
import doc_reform.io_out.paths_output;
auto pth_html_abs                  = spinePathsHTML!()(doc_matters.output_path, doc_matters.src.language);
auto pth_html_rel                  = spineDocRootTreeHTML!()(doc_matters.src.language);
hvst.curate.title                 = doc_matters.conf_make_meta.meta.title_full;
hvst.curate.author                = doc_matters.conf_make_meta.meta.creator_author;
hvst.curate.author_surname        = doc_matters.conf_make_meta.meta.creator_author_surname;
hvst.curate.author_surname_fn     = doc_matters.conf_make_meta.meta.creator_author_surname_fn;
hvst.curate.author_arr            = doc_matters.conf_make_meta.meta.creator_author_arr;
hvst.curate.language_original     = doc_matters.conf_make_meta.meta.original_language;
hvst.curate.language              = doc_matters.src.language;
hvst.curate.uid                   = doc_matters.src.doc_uid;
hvst.curate.date_published        = doc_matters.conf_make_meta.meta.date_published;
hvst.curate.topic_register_arr    = doc_matters.conf_make_meta.meta.classify_topic_register_arr;
hvst.curate.path_html_metadata    = pth_html_rel.fn_metadata(doc_matters.src.filename);
hvst.curate.path_html_scroll      = pth_html_rel.fn_scroll(doc_matters.src.filename);
hvst.curate.path_html_segtoc      = pth_html_rel.fn_seg(doc_matters.src.filename, "toc");
hvst.curate.path_abs_html_scroll  = pth_html_abs.fn_scroll(doc_matters.src.filename);
hvst.curate.path_abs_html_segtoc  = pth_html_abs.fn_seg(doc_matters.src.filename, "toc");
return hvst.curate;
#+END_SRC

** _module template_ metadoc curate topics
*** _module template_ metadoc curate topics template

#+HEADER: :tangle "../src/doc_reform/meta/metadoc_curate_topics.d"
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<doc_header_including_copyright_and_license>>
module doc_reform.meta.metadoc_curate_topics;
  import
    std.algorithm,
    std.array,
    std.exception,
    std.regex,
    std.stdio,
    std.string,
    std.conv : to;
  import
    doc_reform.meta.defaults,
    doc_reform.meta.rgx;
  mixin spineCurateMetadata;
  mixin InternalMarkup;
template spineMetaDocCuratesTopics() {
  static auto mkup = InlineMarkup();
  void spineMetaDocCuratesTopics(H,M,O)(
    H  hvst,
    M  _make_and_meta_struct,
    O  _opt_action,
  ) {
      <<curated_html_search>>
      <<curated_topics>>
<<curated_html_themes_0>>
<<curated_html_themes_1>>
<<curated_topics_html_head_1>>
<<curated_html_head>>
<<curated_topics_html_head_2>>
<<curated_topics_html_head_theme>>
      <<curated_topics_html>>
      topics
<<curated_html_bottom>>
    <<curated_topics_html_write>>
  }
}
#+END_SRC

*** order topic register

#+NAME: curated_topics
#+BEGIN_SRC d
auto min_repeat_number = 42;
string[] _document_topic_register;
string[] _topic_register;
string[] _sub_topic_register;
string[] topics = [];
string _auth = "";
foreach(k, doc_curate; hvst.curates) {
  _topic_register = [];
  foreach(topic; doc_curate.topic_register_arr.sort) {
    _sub_topic_register = [];
    string _spaces;
    string[] subject_tree = topic.split(mkup.sep);
    switch (subject_tree.length) {
    case 1:
      hvst.subject_trees[subject_tree[0]]["_a"]["_a"]["_a"] ~= doc_curate;
      break;
    case 2:
      hvst.subject_trees[subject_tree[0]][subject_tree[1]]["_a"]["_a"] ~= doc_curate;
      break;
    case 3:
      hvst.subject_trees[subject_tree[0]][subject_tree[1]][subject_tree[2]]["_a"] ~= doc_curate;
      break;
    case 4:
      hvst.subject_trees[subject_tree[0]][subject_tree[1]][subject_tree[2]][subject_tree[3]] ~= doc_curate;
      break;
    default:
      break;
    }
    _topic_register ~= _sub_topic_register.join("\n");
  }
  auto char_repeat_number = (doc_curate.title.length
    + doc_curate.author.length + 16);
  char_repeat_number = (char_repeat_number > min_repeat_number)
  ? char_repeat_number
  : min_repeat_number;
  _document_topic_register ~= format(
    "\"%s\", %s%s\n%s",
    doc_curate.title,
    doc_curate.author,
    (doc_curate.date_published.length > 0) ? " (" ~ doc_curate.date_published ~ ")" : "",
    _topic_register.sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable).release.join("\n"),
  );
}
#+END_SRC

*** curated topics html head

#+NAME: curated_topics_html_head_1
#+BEGIN_SRC d
      topics ~= format(q"┃<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>⌘ Curated metadata - ⌘ Topics</title>
#+END_SRC

*** curated topics html head

#+NAME: curated_topics_html_head_2
#+BEGIN_SRC d
</head>
<body lang="en" xml:lang="en">
<a name="top" id="top"></a>
<a name="up" id="up"></a>
<a name="start" id="start"></a>
<h1>⌘ Curated metadata - ⌘ Topics (output organised by language &amp; filetype)</h1>
<div class="flex-menu-bar">
<div class="flex-menu-option">
<p class="icons">[<a href="../../index.html" class="lnkicon">&nbsp;⟰&nbsp;HOME&nbsp;</a>&nbsp;|&nbsp;<a href="../index.html" class="lnkicon">&nbsp;≅&nbsp;Collection&nbsp;</a>]
 [<a href="authors.html" class="lnkicon">&nbsp;⌘&nbsp;Curated&nbsp;metadata&nbsp;-&nbsp;&#x1F58B;&nbsp;Authors&nbsp;</a>]
</p>
</div>
 %s
</div>
<p><a href="#A" class="lnkicon">A</a>,&nbsp;<a href="#B" class="lnkicon">B</a>,&nbsp;<a href="#C" class="lnkicon">C</a>,&nbsp;<a href="#D" class="lnkicon">D</a>,&nbsp;<a href="#E" class="lnkicon">E</a>,&nbsp;<a href="#F" class="lnkicon">F</a>,&nbsp;<a href="#G" class="lnkicon">G</a>,&nbsp;<a href="#H" class="lnkicon">H</a>,&nbsp;<a href="#I" class="lnkicon">I</a>,&nbsp;<a href="#J" class="lnkicon">J</a>,&nbsp;<a href="#K" class="lnkicon">K</a>,&nbsp;<a href="#L" class="lnkicon">L</a>,&nbsp;<a href="#M" class="lnkicon">M</a>,&nbsp;<a href="#N" class="lnkicon">N</a>,&nbsp;<a href="#O" class="lnkicon">O</a>,&nbsp;<a href="#P" class="lnkicon">P</a>,&nbsp;<a href="#Q" class="lnkicon">Q</a>,&nbsp;<a href="#R" class="lnkicon">R</a>,&nbsp;<a href="#S" class="lnkicon">S</a>,&nbsp;<a href="#T" class="lnkicon">T</a>,&nbsp;<a href="#U" class="lnkicon">U</a>,&nbsp;<a href="#V" class="lnkicon">V</a>,&nbsp;<a href="#W" class="lnkicon">W</a>,&nbsp;<a href="#X" class="lnkicon">X</a>,&nbsp;<a href="#Y" class="lnkicon" class="lnkicon">Y</a>,&nbsp;<a href="#Z" class="lnkicon">Z</a>,&nbsp;
<p></p>
<hr />
#+END_SRC

*** curated topics html head theme insert

#+NAME: curated_topics_html_head_theme
#+BEGIN_SRC d
┃",
  _opt_action.css_theme_default ? theme_light_0 : theme_dark_0,
  _opt_action.css_theme_default ? theme_light_1 : theme_dark_1,
  inline_search_form(_make_and_meta_struct),
) ~ "\n";
#+END_SRC

*** curated topics html

#+NAME: curated_topics_html
#+BEGIN_SRC d
char _prev_k = "_".to!char;
int _kn;
foreach(k0;
  hvst.subject_trees.keys
  .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)
) {
  if (k0.toUpper.to!(char[])[0] != _prev_k) {
    topics ~= format(q"┃<p class="letter"><a name="%s">%s</a></p><p class="book_index_lev1"><a name="a"></a></p>┃",
      k0.toUpper.to!(char[])[0],
      k0.toUpper.to!(char[])[0],
    );
    _prev_k = k0.toUpper.to!(char[])[0];
  }
  if (k0 != "_a") {
    topics ~= format(q"┃<p class="lev0"><a name="%s" class="lev0">%s</a></p>┃",
      k0.translate([' ' : "_"]), k0,) ~ "\n";
    if (_opt_action.show_curate_topics) {
      writeln("", k0);
    }
    if ("_a" in hvst.subject_trees[k0]) {
      foreach (t_a_;
        hvst.subject_trees[k0]["_a"]["_a"]["_a"]
        .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable)
      ) {
        _auth = [];
        if (t_a_.author_arr.length < 2) {
          _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃",
            t_a_.author_surname.translate([' ' : "_"]),
            t_a_.author,
          );
        } else {
          foreach (a; t_a_.author_arr) {
            _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃",
              t_a_.author_surname.translate([' ' : "_"]),
              a,
            );
          }
        }
        topics ~= format(q"┃<p class="work"><a href="%s">"%s"</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
          t_a_.path_html_segtoc,
          t_a_.title,
          _auth,
          t_a_.path_html_metadata,
          t_a_.language,
        ) ~ "\n";
        if (_opt_action.show_curate_topics) {
          writeln("- ", t_a_.title, " - ", t_a_.author);
        }
      }
    }
    foreach(k1;
      hvst.subject_trees[k0].keys
      .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)
    ) {
      if (k1 != "_a") {
        topics ~= format(q"┃<p class="lev1"><a name="%s.%s" class="lev1">%s</a></p>┃",
          k0.translate([' ' : "_"]),
          k1.translate([' ' : "_"]), k1,) ~ "\n";
        if (_opt_action.show_curate_topics) {
          writeln("  ", k1);
        }
        if ("_a" in hvst.subject_trees[k0][k1]) {
          foreach (t_a_;
            hvst.subject_trees[k0][k1]["_a"]["_a"]
            .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable)
          ) {
            _auth = [];
            if (t_a_.author_arr.length < 2) {
              _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃",
                t_a_.author_surname.translate([' ' : "_"]),
                t_a_.author,
              );
            } else {
              foreach (a; t_a_.author_arr) {
                _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃",
                  t_a_.author_surname.translate([' ' : "_"]),
                  a,
                );
              }
            }
            topics ~= format(q"┃<p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
              t_a_.path_html_segtoc,
              t_a_.title,
              _auth,
              t_a_.path_html_metadata,
              t_a_.language,
            ) ~ "\n";
            if (_opt_action.show_curate_topics) {
              writeln("  - ", t_a_.title, " - ", t_a_.author);
            }
          }
        }
      }
      foreach(k2;
        hvst.subject_trees[k0][k1].keys
        .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)
      ) {
        if (k2 != "_a") {
          topics ~= format(q"┃<p class="lev2"><a name="%s.%s.%s" class="lev2">%s</a></p>┃",
            k0.translate([' ' : "_"]), k1.translate([' ' : "_"]),
            k2.translate([' ' : "_"]), k2,) ~ "\n";
          if (_opt_action.show_curate_topics) {
            writeln("    ", k2);
          }
          if ("_a" in hvst.subject_trees[k0][k1][k2]) {
            foreach (t_a_;
              hvst.subject_trees[k0][k1][k2]["_a"]
              .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable)
            ) {
              _auth = [];
              if (t_a_.author_arr.length < 2) {
                _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃",
                  t_a_.author_surname.translate([' ' : "_"]),
                  t_a_.author,
                );
              } else {
                foreach (a; t_a_.author_arr) {
                  _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃",
                    t_a_.author_surname.translate([' ' : "_"]),
                    a,
                  );
                }
              }
              topics ~= format(q"┃<p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                t_a_.path_html_segtoc,
                t_a_.title,
                _auth,
                t_a_.path_html_metadata,
                t_a_.language,
              ) ~ "\n";
              if (_opt_action.show_curate_topics) {
                writeln("    - ", t_a_.title, " - ", t_a_.author);
              }
            }
          }
        }
        foreach(k3;
          hvst.subject_trees[k0][k1][k2].keys
          .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)
        ) {
          if (k3 != "_a") {
            topics ~= format(q"┃<p class="lev3"><a name="%s.%s.%s.%s" class="lev3">%s</a></p>┃",
              k0.translate([' ' : "_"]), k1.translate([' ' : "_"]), k2.translate([' ' : "_"]),
              k3.translate([' ' : "_"]), k3,) ~ "\n";
            if (_opt_action.show_curate_topics) {
              writeln("      ", k3);
            }
            {
              foreach (t_a_;
                hvst.subject_trees[k0][k1][k2][k3]
                .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable)
              ) {
                _auth = [];
                if (t_a_.author_arr.length < 2) {
                  _auth = format(q"┃<a href="authors.html#%s">%s</a>┃",
                    t_a_.author_surname.translate([' ' : "_"]),
                    t_a_.author,
                  );
                } else {
                  foreach (a; t_a_.author_arr) {
                    _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃",
                      t_a_.author_surname.translate([' ' : "_"]),
                      a,
                    );
                  }
                }
                topics ~= format(q"┃ <p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                  t_a_.path_html_segtoc,
                  t_a_.title,
                  _auth,
                  t_a_.path_html_metadata,
                  t_a_.language,
                ) ~ "\n";
                if (_opt_action.show_curate_topics) {
                  writeln("      - ", t_a_.title, " - ", t_a_.author);
                }
              }
            }
          }
        }
      }
    }
  }
}
#+END_SRC

*** curated topics write

#+NAME: curated_topics_html_write
#+BEGIN_SRC d
import doc_reform.io_out.paths_output;
auto out_pth = spinePathsHTML!()(_make_and_meta_struct.conf.output_path, "");
try {
  auto f = File(out_pth.curate("topics.html"), "w");
  foreach (o; topics) {
    f.writeln(o);
  }
} catch (ErrnoException ex) {
  // Handle error
}
#+END_SRC

** _module template_ metadoc curates authors
*** _module template_ metadoc curate authors

#+HEADER: :tangle "../src/doc_reform/meta/metadoc_curate_authors.d"
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<doc_header_including_copyright_and_license>>
module doc_reform.meta.metadoc_curate_authors;
  import
    std.algorithm,
    std.array,
    std.exception,
    std.regex,
    std.stdio,
    std.string,
    std.conv : to;
  import
    doc_reform.meta.defaults,
    doc_reform.meta.rgx;
  mixin spineCurateMetadata;
  mixin InternalMarkup;
template spineMetaDocCuratesAuthors() {
  static auto mkup = InlineMarkup();
  void spineMetaDocCuratesAuthors(H,M,O)(
    H  curates,
    M  _make_and_meta_struct,
    O  _opt_action,
  ) {
      <<curated_html_search>>
<<curated_html_themes_0>>
<<curated_html_themes_1>>
<<curated_authors_html_head_1>>
<<curated_html_head>>
<<curated_authors_html_head_2>>
<<curated_authors_html_head_theme>>
      authors
<<curated_html_bottom>>
    <<curated_authors_html_write>>
  }
}
#+END_SRC

*** curated authors html head

#+NAME: curated_authors_html_head_1
#+BEGIN_SRC d
      string[] authors = [];
      authors ~= format(q"┃
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>⌘ Curated metadata - &#x1F58B; Authors</title>
#+END_SRC

*** curated authors html head

#+NAME: curated_authors_html_head_2
#+BEGIN_SRC d
</head>
<body lang="en" xml:lang="en">
<a name="top" id="top"></a>
<a name="up" id="up"></a>
<a name="start" id="start"></a>
<h1>⌘ Curated metadata - &#x1F58B; Authors (output organised by language &amp; filetype)</h1>
<div class="flex-menu-bar">
<div class="flex-menu-option">
<p class="icons">[<a href="../../index.html" class="lnkicon">&nbsp;⟰&nbsp;HOME&nbsp;</a>&nbsp;|&nbsp;<a href="../index.html" class="lnkicon">&nbsp;≅&nbsp;Collection&nbsp;</a>]
 [<a href="topics.html" class="lnkicon">&nbsp;⌘&nbsp;Curated&nbsp;metadata&nbsp;-&nbsp;⌘&nbsp;Topics&nbsp;</a>] </p>
</div>
%s
</div>
<p></p>
<hr />
<p><a href="#A" class="lnkicon">A</a>,&nbsp;<a href="#B" class="lnkicon">B</a>,&nbsp;<a href="#C" class="lnkicon">C</a>,&nbsp;<a href="#D" class="lnkicon">D</a>,&nbsp;<a href="#E" class="lnkicon">E</a>,&nbsp;<a href="#F" class="lnkicon">F</a>,&nbsp;<a href="#G" class="lnkicon">G</a>,&nbsp;<a href="#H" class="lnkicon">H</a>,&nbsp;<a href="#I" class="lnkicon">I</a>,&nbsp;<a href="#J" class="lnkicon">J</a>,&nbsp;<a href="#K" class="lnkicon">K</a>,&nbsp;<a href="#L" class="lnkicon">L</a>,&nbsp;<a href="#M" class="lnkicon">M</a>,&nbsp;<a href="#N" class="lnkicon">N</a>,&nbsp;<a href="#O" class="lnkicon">O</a>,&nbsp;<a href="#P" class="lnkicon">P</a>,&nbsp;<a href="#Q" class="lnkicon">Q</a>,&nbsp;<a href="#R" class="lnkicon">R</a>,&nbsp;<a href="#S" class="lnkicon">S</a>,&nbsp;<a href="#T" class="lnkicon">T</a>,&nbsp;<a href="#U" class="lnkicon">U</a>,&nbsp;<a href="#V" class="lnkicon">V</a>,&nbsp;<a href="#W" class="lnkicon">W</a>,&nbsp;<a href="#X" class="lnkicon">X</a>,&nbsp;<a href="#Y" class="lnkicon">Y</a>,&nbsp;<a href="#Z" class="lnkicon">Z</a>,&nbsp;
#+END_SRC

*** curated authors html theme inserts

#+NAME: curated_authors_html_head_theme
#+BEGIN_SRC d
┃",
  _opt_action.css_theme_default ? theme_light_0 : theme_dark_0,
  _opt_action.css_theme_default ? theme_light_1 : theme_dark_1,
  inline_search_form(_make_and_meta_struct),
) ~ "\n";
      string[string] _au;
      string[] _auth_date_title;
      string[] _author_date_title;
      string _prev_auth = "";
      char _prev_k = "_".to!char;
      foreach(doc_curate;
        curates
        .multiSort!(
          "toUpper(a.author_surname_fn) < toUpper(b.author_surname_fn)",
          "a.date_published < b.date_published",
          "a.title < b.title",
          SwapStrategy.unstable
        )
      ) {
        if (doc_curate.author_surname_fn != _prev_auth) {
          _au[doc_curate.author_surname_fn]
          = format(q"┃<p class="author"><a name="%s" class="lev0">%s</a></p> <p class="publication">%s "<a href="%s">%s</a>" [<a href="%s">&nbsp;%s&nbsp;</a>]</p>┃",
            doc_curate.author_surname.translate([' ' : "_"]),
            doc_curate.author_surname_fn,
            (doc_curate.date_published.length > 0)
              ? doc_curate.date_published : "",
            doc_curate.path_html_segtoc,
            doc_curate.title,
            doc_curate.path_html_metadata,
            doc_curate.language,
          );
          _prev_auth = doc_curate.author_surname_fn;
        } else {
          _au[doc_curate.author_surname_fn]
          ~= format(q"┃<p class="publication">%s "<a href="%s">%s</a>" [<a href="%s">&nbsp;%s&nbsp;</a>]</p>┃",
            (doc_curate.date_published.length > 0)
              ? doc_curate.date_published : "",
            doc_curate.path_html_segtoc,
            doc_curate.title,
            doc_curate.path_html_metadata,
            doc_curate.language,
          );
        }
        _author_date_title ~= format(q"┃%s %s "%s" [<a href="%s">&nbsp;%s&nbsp;</a>]%s┃",
          doc_curate.author_surname_fn,
          (doc_curate.date_published.length > 0)
            ? "(" ~ doc_curate.date_published ~ ")" : "",
          doc_curate.title,
          doc_curate.path_html_metadata,
          doc_curate.language,
          (_opt_action.show_curate_authors) ? "\n  " ~ doc_curate.path_abs_html_scroll : "",
        );
      }
      foreach (k; _au.keys.sort) {
        if (k.toUpper.to!(char[])[0] != _prev_k) {
          authors ~= format(q"┃<p class="letter"><a name="%s">%s</a></p><p class="book_index_lev1"><a name="a"></a></p>┃",
            k.toUpper.to!(char[])[0],
            k.toUpper.to!(char[])[0],
          );
          _prev_k = k.toUpper.to!(char[])[0];
        }
        authors ~= _au[k];
      }
#+END_SRC

*** curated authors write

#+NAME: curated_authors_html_write
#+BEGIN_SRC d
import doc_reform.io_out.paths_output;
auto out_pth = spinePathsHTML!()(_make_and_meta_struct.conf.output_path, "");
try {
  auto f = File(out_pth.curate("authors.html"), "w");
  foreach (o; authors) {
    f.writeln(o);
  }
} catch (ErrnoException ex) {
  // Handle error
}
if (_opt_action.show_curate_authors) {
  foreach(_adt; _author_date_title.sort) {
    writeln(_adt);
  }
}
#+END_SRC

** curated authors & topics shared html
*** themes
**** head

#+NAME: curated_html_themes_0
#+BEGIN_SRC d
string theme_dark_0 = format(q"┃
  body {
    color                    : #CCCCCC;
    background               : #000000;
    background-color         : #000000;
  }
  a:link {
    color                    : #FFFFFF;
    text-decoration          : none;
  }
  a:visited {
    color                    : #999999;
    text-decoration          : none;
  }
  a:hover {
    color                    : #000000;
    background-color         : #555555;
  }
  a:hover img {
    background-color         : #000000;
  }
  a:active {
    color                    : #888888;
    text-decoration          : underline;
  }
  a.lev0:hover {
    color                    : #FFFFFF;
    background-color         : #000000;
  }
  a.lev1:hover {
    color                    : #FFFFFF;
    background               : #333333;
  }
  a.lev2:hover {
    color                    : #FFFFFF;
    background               : #555555;
  }
  a.lev3:hover {
    color                    : #FFFFFF;
    background               : #777777;
  }
  a.lnkicon:link {
    text-decoration          : none;
  }
  a.lnkicon:visited {
    text-decoration          : none;
  }
  a.lnkicon:hover {
    font-size                : 160%%;
  }
  a:hover img {
    background-color         : #FFFFFF;
  }
  input, select, textarea {
    font-size                : 150%%;
  }
  input {
    color                    : #FFFFFF;
    background-color         : #777777;
  }
┃");
string theme_light_0 = format(q"┃
  body {
    color                    : #000000;
    background               : #FFFFFF;
    background-color         : #FFFFFF;
  }
  a:link {
    color                    : #003399;
    text-decoration          : none;
  }
  a:visited {
    color                    : #003399;
    text-decoration          : none;
  }
  a:hover {
    color                    : #000000;
    background-color         : #f9f9aa;
  }
  a:hover img {
    background-color         : #FFFFFF;
  }
  a:active {
    color                    : #003399;
    text-decoration          : underline;
  }
  a.lev0:hover {
    color                    : #000000;
    background-color         : #FFFFFF;
  }
  a.lev1:hover {
    color                    : #FFFFFF;
    background               : #444444;
  }
  a.lev2:hover {
    background               : #888888;
  }
  a.lev3:hover {
    background               : #BBBBBB;
  }
  a.lnkicon:link {
    text-decoration          : none;
  }
  a.lnkicon:visited {
    text-decoration          : none;
  }
  a.lnkicon:hover {
    font-size                : 160%%;
  }
  a:hover img {
    background-color         : #FFFFFF;
  }
  input, select, textarea {
    font-size                : 150%%;
  }
  input {
    color                    : #000000;
    background-color         : #FFFFFF;
  }
┃");
#+END_SRC

**** levels

#+NAME: curated_html_themes_1
#+BEGIN_SRC css
string theme_dark_1 = format(q"┃
  h1 {
    color                    : #FFFFFF;
    background               : #000000;
  }
  p.letter {
    color                    : #FFFFFF;
    background               : #333333;
  }
  p.lev0 {
    color                    : #FFFFFF;
    background               : #000000;
  }
  p.lev1 {
    color                    : #FFFFFF;
    background               : #333333;
  }
  p.lev2 {
    background               : #555555;
  }
  p.lev3 {
    background               : #777777;
  }
  p.lev4 {
    background               : #AAAAAA;
  }
  p.lev5 {
  }
┃");
string theme_light_1 = format(q"┃
  h1 {
    color                    : #FFFFFF;
    background               : #1A3A7A;
  }
  p.letter {
    color                    : #FFFFFF;
    background               : #1A3A7A;
  }
  p.lev0 {
    color                    : #FFFFFF;
    background               : #000000;
  }
  p.lev1 {
    color                    : #FFFFFF;
    background               : #444444;
  }
  p.lev2 {
    background               : #888888;
  }
  p.lev3 {
    background               : #BBBBBB;
  }
  p.lev4 {
    background               : #EEEEEE;
  }
  p.lev5 {
  }
┃");
#+END_SRC

*** search form

#+NAME: curated_html_search
#+BEGIN_SRC d
@safe string inline_search_form(M)(
  M  _make_and_meta_truct,
) {
  string o;
  string _form;
  if (_opt_action.html_link_search) {
    o = format(q"┃
<div class="flex-menu-option">
<!-- SiSU Spine Search -->
<form action="%s" target="_top" method="POST" accept-charset="UTF-8" id="search">
<font size="2">
<input type="text" name="sf" size="24" maxlength="255">%s
<input type="hidden" name="sml" value="1000">
<input type="hidden" name="ec" value="on">
<input type="hidden" name="url" value="on">
<button type="submit" form="search">㏈ ፨</button>
</font></form>
<!-- SiSU Spine Search -->
</div>┃",
    _make_and_meta_struct.conf.w_srv_cgi_action,
    (_make_and_meta_struct.conf.w_srv_db_sqlite_filename.empty)
      ? ""
      : "\n    <input type=\"hidden\" name=\"db\" value=\""
        ~ _make_and_meta_struct.conf.w_srv_db_sqlite_filename
        ~ "\">",
    );
  } else {
    o = "";
  }
  return o;
}
#+END_SRC

*** curated html head

#+NAME: curated_html_head
#+BEGIN_SRC d
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="dc.title" content= "metadata curate, Authors & Topics - information Structuring Universe, Structured information Serialised Units" />
<meta name="dc.subject" content= "document structuring, ebook, publishing, PDF, LaTeX, XML, ODF, SQL, postgresql, sqlite, electronic book, electronic publishing, electronic document, electronic citation, data structure, citation systems, granular search, digital library" />
<meta name="generator" content="spine" />
<link rel="generator" href="https://sisudoc.org" />
<link href="./css/curate.css" rel="stylesheet">
<style TYPE="text/css">
/* spine curate css default stylesheet */%s
  .norm, .bold {
    line-height              : 150%%;
    margin-left              : 1em;
    margin-right             : 2em;
    margin-top               : 10px;
    margin-bottom            : 0px;
    text-indent              : 0mm;
  }
  p, h0, h1, h2, h3, h4, h5, h6, h7 {
    display                  : block;
    font-family              : verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
    font-size                : 100%%;
    font-weight              : normal;
    line-height              : 150%%;
    /* text-align            : justify; */
    margin-left              : 1em;
    text-indent              : 0mm;
    margin-top               : 2px;
    margin-bottom            : 2px;
    margin-right             : 6px;
    text-align               : left;
  }
  h0, h1, h2, h3, h4, h5, h6, h7 { text-shadow: .2em .2em .3em #999999; }
  h1 {
    font-size                : 120%%;
    font-weight              : bold;
    color                    : #FFFFFF;
    background               : #000088;
    margin-left              : 0em;
  }
  p.work {
    font-size                : 80%%;
    margin-left              : 5em;
    margin-top               : 0px;
    margin-bottom            : 0px;
    margin-right             : 6px;
    text-align               : left;
  }
  p.author {
    font-size                : 100%%;
    margin-left              : 2em;
    margin-top               : 0px;
    margin-bottom            : 0px;
    margin-right             : 6px;
    text-align               : left;
  }
  p.publication {
    font-size                : 90%%;
    margin-left              : 4em;
    margin-top               : 0px;
    margin-bottom            : 0px;
    margin-right             : 6px;
    text-align               : left;
  }
  p.letter {
    font-weight              : bold;
    font-size                : 80%%;
    margin-left              : 1em;
    margin-top               : 0px;
    margin-bottom            : 0px;
    margin-right             : 6px;
    text-align               : left;
  }
  p.icons, .icons_center {
    font-size                : 100%%;
    margin-top               : 0px;
    margin-bottom            : 0px;
    margin-right             : 6px;
  }
  p.icons {
    text-align               : left;
  }
  p.lev0 {
    font-size                : 120%%;
    margin-left              : 1em;
  }
  p.lev1 {
    font-size                : 115%%;
    margin-left              : 2em;
  }
  p.lev2 {
    font-size                : 110%%;
    margin-left              : 3em;
  }
  p.lev3 {
    font-size                : 105%%;
    margin-left              : 4em;
  }
  p.lev4 {
    font-size                : 100%%;
    margin-left              : 5em;
  }
  p.lev5 {
    font-size                : 95%%;
    margin-left              : 6em;
  }%s
  /* flex */
  .flex-menu-bar {
    display                  : -webkit-flex;
    display                  : flex;
    -webkit-flex-wrap        : wrap;
    -webkit-align-items      : center;
    align-items              : center;
    width                    : 100%%;
    margin-left              : 0%%;
    margin-right             : 2%%;
    background-color         : inherited;
  }
  .flex-menu-option {
    background-color         : inherited;
    margin-right             : 4px;
  }
  .flex-list {
    display                  : -webkit-flex;
    display                  : flex;
    -webkit-align-items      : center;
    display                  : block;
    align-items              : center;
    width                    : 100%%;
    background-color         : inherited;
  }
  .flex-list-item {
    background-color         : inherited;
    margin                   : 4px;
  }
</style>
<link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
#+END_SRC

*** curated html bottom

#+NAME: curated_html_bottom
#+BEGIN_SRC d
      ~= format(q"┃
<hr />
<a name="bottom" id="bottom"></a>
<a name="down" id="down"></a>
<a name="end" id="end"></a>
<a name="finish" id="finish"></a>
<a name="stop" id="stop"></a>
<a name="credits"></a>
</body>
</html>
┃") ~ "\n";
#+END_SRC

* document header including copyright & license

#+NAME: doc_header_including_copyright_and_license
#+BEGIN_SRC txt
/+
- Name: Spine, Doc Reform [a part of]
  - Description: documents, structuring, processing, publishing, search
    - static content generator

  - Author: Ralph Amissah
    [ralph.amissah@gmail.com]

  - Copyright: (C) 2015 - 2023 Ralph Amissah, All Rights Reserved.

  - License: AGPL 3 or later:

    Spine (SiSU), a framework for document structuring, publishing and
    search

    Copyright (C) Ralph Amissah

    This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU AFERO General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    more details.

    You should have received a copy of the GNU General Public License along with
    this program. If not, see [https://www.gnu.org/licenses/].

    If you have Internet connection, the latest version of the AGPL should be
    available at these locations:
    [https://www.fsf.org/licensing/licenses/agpl.html]
    [https://www.gnu.org/licenses/agpl.html]

  - Spine (by Doc Reform, related to SiSU) uses standard:
    - docReform markup syntax
      - standard SiSU markup syntax with modified headers and minor modifications
    - docReform object numbering
      - standard SiSU object citation numbering & system

  - Homepages:
    [https://www.doc_reform.org]
    [https://www.sisudoc.org]

  - Git
    [https://git.sisudoc.org/projects/?p=software/spine.git;a=summary]

+/
#+END_SRC

* __END__