forked from Fediversity/Fediversity
override page template for articles
This commit is contained in:
parent
00e3cfcb52
commit
9b74458a8c
|
@ -9,6 +9,7 @@
|
||||||
let
|
let
|
||||||
cfg = config;
|
cfg = config;
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
inherit (types) submodule;
|
||||||
|
|
||||||
# https://html.spec.whatwg.org/multipage/dom.html#content-models
|
# https://html.spec.whatwg.org/multipage/dom.html#content-models
|
||||||
# https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content
|
# https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content
|
||||||
|
@ -43,7 +44,7 @@ let
|
||||||
|
|
||||||
# options with types for all the defined DOM elements
|
# options with types for all the defined DOM elements
|
||||||
element-types = lib.mapAttrs
|
element-types = lib.mapAttrs
|
||||||
(name: value: mkOption { type = types.submodule value; })
|
(name: value: mkOption { type = submodule value; })
|
||||||
elements;
|
elements;
|
||||||
|
|
||||||
# attrset of categories, where values are module options with the type of the
|
# attrset of categories, where values are module options with the type of the
|
||||||
|
@ -52,7 +53,7 @@ let
|
||||||
genAttrs
|
genAttrs
|
||||||
content-categories
|
content-categories
|
||||||
(category:
|
(category:
|
||||||
(mapAttrs (_: e: mkOption { type = types.submodule e; })
|
(mapAttrs (_: e: mkOption { type = submodule e; })
|
||||||
# HACK: don't evaluate the submodule types, just grab the config directly
|
# HACK: don't evaluate the submodule types, just grab the config directly
|
||||||
(filterAttrs (_: e: elem category (e { name = "dummy"; config = { }; }).config.categories) elements))
|
(filterAttrs (_: e: elem category (e { name = "dummy"; config = { }; }).config.categories) elements))
|
||||||
);
|
);
|
||||||
|
@ -118,7 +119,7 @@ let
|
||||||
|
|
||||||
mkAttrs = attrs: with lib;
|
mkAttrs = attrs: with lib;
|
||||||
mkOption {
|
mkOption {
|
||||||
type = types.submodule {
|
type = submodule {
|
||||||
options = global-attrs // attrs;
|
options = global-attrs // attrs;
|
||||||
};
|
};
|
||||||
default = { };
|
default = { };
|
||||||
|
@ -147,12 +148,21 @@ let
|
||||||
|
|
||||||
print-element = name: attrs: content:
|
print-element = name: attrs: content:
|
||||||
with lib;
|
with lib;
|
||||||
|
# TODO: be smarter about content to save some space and repetition at the call sites
|
||||||
squash (trim ''
|
squash (trim ''
|
||||||
<${name}${print-attrs attrs}>
|
<${name}${print-attrs attrs}>
|
||||||
${lib.indent " " content}
|
${lib.indent " " content}
|
||||||
</${name}>
|
</${name}>
|
||||||
'');
|
'');
|
||||||
|
|
||||||
|
toString-unwrap = e:
|
||||||
|
with lib;
|
||||||
|
if isAttrs e
|
||||||
|
then toString (head (attrValues e))
|
||||||
|
else if isList e
|
||||||
|
then toString (map toString-unwrap e)
|
||||||
|
else e;
|
||||||
|
|
||||||
elements = rec {
|
elements = rec {
|
||||||
document = { ... }: {
|
document = { ... }: {
|
||||||
imports = [ element ];
|
imports = [ element ];
|
||||||
|
@ -206,7 +216,7 @@ let
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#viewport_width_and_screen_width
|
# https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#viewport_width_and_screen_width
|
||||||
# this should not exist and no one should ever have to think about it
|
# this should not exist and no one should ever have to think about it
|
||||||
meta.viewport = mkOption {
|
meta.viewport = mkOption {
|
||||||
type = types.submodule ({ ... }: {
|
type = submodule ({ ... }: {
|
||||||
# TODO: figure out how to render only non-default values
|
# TODO: figure out how to render only non-default values
|
||||||
options = {
|
options = {
|
||||||
width = mkOption {
|
width = mkOption {
|
||||||
|
@ -422,21 +432,13 @@ let
|
||||||
|
|
||||||
config.categories = [ ];
|
config.categories = [ ];
|
||||||
config.__toString = self: with lib;
|
config.__toString = self: with lib;
|
||||||
print-element name self.attrs (
|
print-element name self.attrs (join "\n" (map toString-unwrap self.content));
|
||||||
join "\n" (map
|
|
||||||
(e:
|
|
||||||
if isAttrs e
|
|
||||||
then toString (lib.head (attrValues e))
|
|
||||||
else e
|
|
||||||
)
|
|
||||||
self.content)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
section = { config, name, ... }: {
|
section = { config, name, ... }: {
|
||||||
imports = [ element ];
|
imports = [ element ];
|
||||||
options = {
|
options = {
|
||||||
# setting to an attribute set will wrap the section in <section>
|
# setting to an attribute set will wrap the section in `<section>`
|
||||||
attrs = mkOption {
|
attrs = mkOption {
|
||||||
type = with types; nullOr (submodule { options = global-attrs; });
|
type = with types; nullOr (submodule { options = global-attrs; });
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -450,14 +452,18 @@ let
|
||||||
# such an outline is rather meaningless without headings for navigation,
|
# such an outline is rather meaningless without headings for navigation,
|
||||||
# which is why we enforce headings in sections.
|
# which is why we enforce headings in sections.
|
||||||
# arguably, and this is encoded here, a section *is defined* by its heading.
|
# arguably, and this is encoded here, a section *is defined* by its heading.
|
||||||
type = with types; submodule ({ ... }: {
|
type = with types; submodule ({ config, ... }: {
|
||||||
imports = [ element ];
|
imports = [ element ];
|
||||||
options = {
|
options = {
|
||||||
attrs = mkAttrs { };
|
attrs = mkAttrs { };
|
||||||
# TODO: make `before`/`after` wrap the heading in `<hgroup>` if non-empty
|
# setting to an attribute set will wrap the section in `<hgroup>`
|
||||||
|
hgroup.attrs = mkOption {
|
||||||
|
type = with types; nullOr (submodule { options = global-attrs; });
|
||||||
|
default = with lib; mkIf (!isNull config.before || !isNull config.after) { };
|
||||||
|
};
|
||||||
# https://html.spec.whatwg.org/multipage/sections.html#the-hgroup-element
|
# https://html.spec.whatwg.org/multipage/sections.html#the-hgroup-element
|
||||||
before = mkOption {
|
before = mkOption {
|
||||||
type = with types; listOf (attrTag ({ inherit p; } // categories.scripting));
|
type = with types; listOf (attrTag ({ inherit (element-types) p; } // categories.scripting));
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
content = mkOption {
|
content = mkOption {
|
||||||
|
@ -466,7 +472,7 @@ let
|
||||||
};
|
};
|
||||||
after = mkOption {
|
after = mkOption {
|
||||||
type = with types;
|
type = with types;
|
||||||
listOf (attrTag ({ inherit p; } // categories.scripting));
|
listOf (attrTag ({ inherit (element-types) p; } // categories.scripting));
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -489,20 +495,32 @@ let
|
||||||
__toString = self: with lib;
|
__toString = self: with lib;
|
||||||
let
|
let
|
||||||
n = toString config.heading-level;
|
n = toString config.heading-level;
|
||||||
content = ''<h${n}${print-attrs self.heading.attrs}>${self.heading.content}</h${n}>
|
heading = ''<h${n}${print-attrs self.heading.attrs}>${self.heading.content}</h${n}>'';
|
||||||
'' + join "\n" (map
|
hgroup = with lib; print-element "hgroup" self.heading.hgroup.attrs (squash ''
|
||||||
(e:
|
${optionalString (!isNull self.heading.before) (toString-unwrap self.heading.before)}
|
||||||
if isAttrs e
|
${heading}
|
||||||
then toString (lib.head (attrValues e))
|
${optionalString (!isNull self.heading.after) (toString-unwrap self.heading.after)}
|
||||||
else e
|
'');
|
||||||
)
|
content = if isNull self.heading.hgroup.attrs then heading else hgroup
|
||||||
self.content);
|
+ join "\n" (map toString-unwrap self.content);
|
||||||
in
|
in
|
||||||
if !isNull self.attrs
|
if !isNull self.attrs
|
||||||
then print-element name self.attrs content
|
then print-element name self.attrs content
|
||||||
else content;
|
else content;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
p = { name, ... }: {
|
||||||
|
imports = [ element ];
|
||||||
|
options = {
|
||||||
|
attrs = mkAttrs { };
|
||||||
|
content = mkOption {
|
||||||
|
type = with types; either str (listOf (attrTag categories.phrasing));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.categories = [ "flow" "palpable" ];
|
||||||
|
config.__toString = self: print-element name self.attrs (toString self.content);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,17 +27,21 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config.name = lib.slug config.title;
|
config.name = lib.slug config.title;
|
||||||
config.outputs.html = lib.mkForce (cfg.templates.html.dom {
|
config.outputs.html = lib.mkForce ((cfg.templates.html.page config).override {
|
||||||
html = {
|
html = {
|
||||||
head = {
|
# TODO: make authors always a list
|
||||||
title.text = config.title;
|
head.meta.authors = if lib.isList config.author then config.author else [ config.author ];
|
||||||
meta.description = config.description;
|
body.content = lib.mkForce [
|
||||||
meta.authors = if lib.isList config.author then config.author else [ config.author ];
|
|
||||||
link.canonical = lib.head config.locations;
|
|
||||||
};
|
|
||||||
body.content = [
|
|
||||||
(cfg.menus.main.outputs.html config)
|
(cfg.menus.main.outputs.html config)
|
||||||
{ section.heading.content = config.title; }
|
{
|
||||||
|
section.heading = {
|
||||||
|
# TODO: i18n support
|
||||||
|
# TODO: structured dates
|
||||||
|
before = [{ p.content = "Published ${config.date}"; }];
|
||||||
|
content = config.title;
|
||||||
|
after = [{ p.content = "Written by ${config.author}"; }];
|
||||||
|
};
|
||||||
|
}
|
||||||
(cfg.templates.html.markdown { inherit (config) name body; })
|
(cfg.templates.html.markdown { inherit (config) name body; })
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue