split tags and ehtags, separate listings from hierarchical views

This commit is contained in:
Mirek Kratochvil 2023-06-18 17:02:51 +02:00
parent 3b13dd8353
commit 4a7dcc2dbe
6 changed files with 147 additions and 51 deletions

View file

@ -36,6 +36,9 @@ data SiteState =
-- | Map of tags, assigning to each tag sequence a list of -- | Map of tags, assigning to each tag sequence a list of
-- tagged page mounts -- tagged page mounts
, _htags :: M.Map [String] [FilePath] , _htags :: M.Map [String] [FilePath]
-- | Map of tags, assigning to each tag sequence a list of tagged page
-- mounts. This one is expanded (tags imply parent categories).
, _ehtags :: M.Map [String] [FilePath]
-- | List of installed files (enables sharing) -- | List of installed files (enables sharing)
, _installs :: S.Set (String, FilePath) , _installs :: S.Set (String, FilePath)
-- | List of installed files (prevents overwriting) -- | List of installed files (prevents overwriting)
@ -50,7 +53,8 @@ data SiteState =
, _templateDir :: FilePath -- ^ Path to template directory , _templateDir :: FilePath -- ^ Path to template directory
, _defaultTemplate :: FilePath -- ^ Name of the default template , _defaultTemplate :: FilePath -- ^ Name of the default template
, _redirectTemplate :: FilePath -- ^ Name of the template for redirect pages , _redirectTemplate :: FilePath -- ^ Name of the template for redirect pages
, _tagTemplate :: FilePath -- ^ Name of the template for tag listing pages , _tagTemplate :: FilePath -- ^ Name of the template for category pages
, _listTemplate :: FilePath -- ^ Name of the template for listing pages
, _urlBase :: FilePath -- ^ "Root route" to prepend to all absolute links. , _urlBase :: FilePath -- ^ "Root route" to prepend to all absolute links.
, _dumpFinalState :: Bool -- ^ Triggers printing out the structure when the processing finishes. , _dumpFinalState :: Bool -- ^ Triggers printing out the structure when the processing finishes.
} }
@ -105,8 +109,13 @@ siteOptions' = do
_tagTemplate <- _tagTemplate <-
strOption $ strOption $
long "tag-template" <> long "tag-template" <>
help "Template for making tag-listing pages" <> help "Template for making category view pages" <>
value "tag.html" <> showDefault value "tag.html" <> showDefault
_listTemplate <-
strOption $
long "list-template" <>
help "Template for making tag-listing pages" <>
value "list.html" <> showDefault
_urlBase <- _urlBase <-
strOption $ strOption $
long "url-base" <> long "url-base" <>
@ -121,6 +130,7 @@ siteOptions' = do
{ _pages = M.empty { _pages = M.empty
, _redirects = M.empty , _redirects = M.empty
, _htags = M.empty , _htags = M.empty
, _ehtags = M.empty
, _installs = S.empty , _installs = S.empty
, _targets = S.empty , _targets = S.empty
, _templates = M.empty , _templates = M.empty

View file

@ -13,9 +13,8 @@ redirects:
- internal/internal/publication/codeCheck - internal/internal/publication/codeCheck
tags: tags:
- publication/ppc/code - publication/ppc/code
- code/conventions - it/conventions
- code/licensing - it/licensing
- tto/code
--- ---
# How-to: Pass a PPC code check # How-to: Pass a PPC code check

View file

@ -5,11 +5,10 @@ redirects:
- mypage - mypage
- old:mypage - old:mypage
tags: tags:
- yyy - about/test
- topic1/xxx
--- ---
# My Page # My Testing Page
something something something something

109
site.hs
View file

@ -91,7 +91,8 @@ pageTemplates :: Site [FilePath]
pageTemplates = do pageTemplates = do
rt <- use redirectTemplate rt <- use redirectTemplate
tt <- use tagTemplate tt <- use tagTemplate
nub . ([rt, tt] ++) <$> lt <- use listTemplate
nub . ([rt, tt, lt] ++) <$>
(gets (^.. pages . traverse) >>= traverse pageTemplate) (gets (^.. pages . traverse) >>= traverse pageTemplate)
-- | Compile a single template in a directory -- | Compile a single template in a directory
@ -166,7 +167,8 @@ addGlobalMeta (Y.Object m) = do
addPageMeta :: PageInfo -> Y.Value -> Site Y.Value addPageMeta :: PageInfo -> Y.Value -> Site Y.Value
addPageMeta pi (Y.Object m) = do addPageMeta pi (Y.Object m) = do
htagMeta <- htagMeta <-
traverse makeHTagMeta . sort $ pi ^.. pageMeta . key "tags" . values . traverse (makeHTagMeta tagLink) . sort $ pi ^.. pageMeta . key "tags" .
values .
_String . _String .
to T.unpack . to T.unpack .
to splitDirectories to splitDirectories
@ -272,18 +274,27 @@ sourceTags = do
(^.. pageMeta . key "tags" . values . _String . to T.unpack)) . (^.. pageMeta . key "tags" . values . _String . to T.unpack)) .
M.assocs <$> M.assocs <$>
use pages use pages
ehtags .= M.fromList (invExpandTags sgat)
htags .= M.fromList (invTags sgat) htags .= M.fromList (invTags sgat)
-- | Organize a list of pages with hierarchical tags to a list with -- | Organize a list of pages with hierarchical tags to a list with
-- hierarchical tags with pages attached. -- hierarchical tags with pages attached; with tags implying parents.
invTags :: [(FilePath, [[String]])] -> [([String], [FilePath])] invExpandTags :: [(FilePath, [[String]])] -> [([String], [FilePath])]
invTags x = invExpandTags x =
map (fmap nub) $ groupSort [(t, p) | (p, htl) <- x, ht <- htl, t <- inits ht] map (fmap nub) $ groupSort [(t, p) | (p, htl) <- x, ht <- htl, t <- inits ht]
-- | Like `invExpandTags` but without the expansion.
invTags :: [(FilePath, [[String]])] -> [([String], [FilePath])]
invTags x = map (fmap nub) $ groupSort [(t, p) | (p, htl) <- x, t <- htl]
-- | Get the destination for the tag page. -- | Get the destination for the tag page.
tagFilename :: FilePath -> Site FilePath tagFilename :: FilePath -> Site FilePath
tagFilename tag = indexFilename $ "tag" </> tag tagFilename tag = indexFilename $ "tag" </> tag
-- | Get the destination for the tag page.
listFilename :: FilePath -> Site FilePath
listFilename tag = indexFilename $ "list" </> tag
-- | Fold the hierarchical tag bits to a slashed path. -- | Fold the hierarchical tag bits to a slashed path.
tagPath :: [String] -> FilePath tagPath :: [String] -> FilePath
tagPath = foldr (</>) "" tagPath = foldr (</>) ""
@ -292,21 +303,22 @@ tagPath = foldr (</>) ""
tagLink :: [String] -> Site FilePath tagLink :: [String] -> Site FilePath
tagLink = rootUrl . ("tag" </>) . tagPath tagLink = rootUrl . ("tag" </>) . tagPath
-- | Fold the hierarchical tag bits to a slashed path.
listPath :: [String] -> FilePath
listPath = foldr (</>) ""
-- | Make a link to the tag page
listLink :: [String] -> Site FilePath
listLink = rootUrl . ("list" </>) . tagPath
-- | Make metadata for printing out a single hierarchical tag (all levels clickable) -- | Make metadata for printing out a single hierarchical tag (all levels clickable)
makeHTagMeta :: [String] -> Site Y.Value makeHTagMeta :: ([String] -> Site FilePath) -> [String] -> Site Y.Value
makeHTagMeta tag = do makeHTagMeta lf tag = do
links <- links <-
zip (Y.Null : map fromString tag) . map fromString <$> zip (Y.Null : map fromString tag) . map fromString <$>
traverse tagLink (inits tag) traverse lf (inits tag)
pure . Y.array $ map (\(t, p) -> Y.object [("tag", t), ("href", p)]) links pure . Y.array $ map (\(t, p) -> Y.object [("tag", t), ("href", p)]) links
-- | Make metadata for printing out a single tag as-is, without levels
makeHTagLinkMeta :: [String] -> Site Y.Value
makeHTagLinkMeta tag = do
link <- tagLink tag
pure $
Y.object [("href", fromString link), ("tags", Y.array $ map fromString tag)]
-- | Make metadata for printing out a link to a page -- | Make metadata for printing out a link to a page
makePageLinkMeta :: FilePath -> Site Y.Value makePageLinkMeta :: FilePath -> Site Y.Value
makePageLinkMeta mount = do makePageLinkMeta mount = do
@ -314,20 +326,55 @@ makePageLinkMeta mount = do
meta <- use $ pages . to (M.! mount) . pageMeta meta <- use $ pages . to (M.! mount) . pageMeta
pure $ Y.object [("href", fromString link), ("meta", meta)] pure $ Y.object [("href", fromString link), ("meta", meta)]
-- | Create the complete metadata structure for the template that renders a given tag page -- | Create the complete metadata structure for the template that renders a given categorical tag pages
makeTagMeta :: [String] -> Site Y.Value makeTagMeta :: [String] -> Site Y.Value
makeTagMeta tag = do makeTagMeta tag = do
taggedPages <- use $ htags . to (M.! tag) taggedPages <- use $ htags . to (M.!? tag) . to (maybe [] id)
subtags <- subtags <-
gets gets
(^.. htags . to M.keys . each . filtered (not . null) . (^.. ehtags . to M.keys . each . filtered (not . null) .
filtered ((== tag) . init)) filtered ((== tag) . init))
htagMeta <- makeHTagMeta tag htagMeta <- makeHTagMeta tagLink tag
subtagsMeta <- Y.array <$> traverse makeHTagLinkMeta subtags subtagsMeta <- Y.array <$> traverse makeTagMeta subtags
pagesMeta <- Y.array <$> traverse makePageLinkMeta taggedPages pagesMeta <- Y.array <$> traverse makePageLinkMeta taggedPages
link <- tagLink tag
listlink <- listLink tag
addGlobalMeta $ addGlobalMeta $
Y.object Y.object
[("htag", htagMeta), ("subtags", subtagsMeta), ("pages", pagesMeta)] [ ("href", fromString link)
, ("tags", Y.array $ map fromString tag)
, ("htag", htagMeta)
, ("subtags", subtagsMeta)
, ("pages", pagesMeta)
, ("listhref", fromString listlink)
]
-- | Make metadata for printing out a single tag as-is, without levels
makeHTagLinkMeta :: [String] -> Site Y.Value
makeHTagLinkMeta tag = do
link <- listLink tag
pure $
Y.object [("href", fromString link), ("tags", Y.array $ map fromString tag)]
-- | Create the structure for rendering a complete listing of one hierarchical tag.
makeListMeta :: [String] -> Site Y.Value
makeListMeta tag = do
taggedPages <- use $ ehtags . to (M.! tag)
subtags <-
gets
(^.. ehtags . to M.keys . each . filtered (not . null) .
filtered ((== tag) . init))
htagMeta <- makeHTagMeta listLink tag
subtagsMeta <- Y.array <$> traverse makeHTagLinkMeta subtags
pagesMeta <- Y.array <$> traverse makePageLinkMeta taggedPages
tl <- tagLink tag
addGlobalMeta $
Y.object
[ ("htag", htagMeta)
, ("subtags", subtagsMeta)
, ("pages", pagesMeta)
, ("taghref", fromString tl)
]
-- | Render a site for a given tag string. -- | Render a site for a given tag string.
renderTag :: [String] -> Site () renderTag :: [String] -> Site ()
@ -344,7 +391,24 @@ renderTag tag = do
-- | Render all tag sites. -- | Render all tag sites.
renderTags :: Site () renderTags :: Site ()
renderTags = use (htags . to M.keys) >>= traverse_ renderTag renderTags = use (ehtags . to M.keys) >>= traverse_ renderTag
-- | Render a site for a given tag string.
renderList :: [String] -> Site ()
renderList tag = do
tname <- use listTemplate
templ <- use $ templates . to (M.! fromString tname)
file <- listFilename (listPath tag)
checkTarget file
meta <- makeListMeta tag
io $ do
putStrLn $ "* -> " ++ file
makeDirectories file
checkedSubstitute templ meta >>= TIO.writeFile file
-- | Render all tag sites.
renderLists :: Site ()
renderLists = use (ehtags . to M.keys) >>= traverse_ renderList
-- | Transform one mounted PageInfo to the base search data -- | Transform one mounted PageInfo to the base search data
mkSearchData :: FilePath -> PageInfo -> Site [Y.Value] mkSearchData :: FilePath -> PageInfo -> Site [Y.Value]
@ -388,6 +452,7 @@ main = do
use templateDir >>= sourceTemplates use templateDir >>= sourceTemplates
use pages >>= traverse (uncurry installPage) . M.assocs use pages >>= traverse (uncurry installPage) . M.assocs
renderTags renderTags
renderLists
renderSearchData renderSearchData
io $ putStrLn "OK" io $ putStrLn "OK"
whenM (use dumpFinalState) $ get >>= io . print whenM (use dumpFinalState) $ get >>= io . print

View file

@ -4,10 +4,10 @@
<div class="footer-lcsb"></div> <div class="footer-lcsb"></div>
<div class="footer-text"> <div class="footer-text">
<div> <div>
The contents are available under the <a href="{root}license">Creative Commons Attribution-ShareAlike License (CC-BY-SA 4.0)</a>. The contents are available under the <a href="{{root}}license">Creative Commons Attribution-ShareAlike License (CC-BY-SA 4.0)</a>.
</div> </div>
<div> <div>
<a href="{root}privacy-policy">Privacy Policy</a> (Only necessary cookies accepted — <a href="#">change</a>) <a href="{{root}}privacy-policy">Privacy Policy</a> (Only necessary cookies accepted — <a href="#">change</a>)
</div> </div>
</div> </div>
<div class="flex-fill"></div> <div class="flex-fill"></div>

View file

@ -4,32 +4,55 @@
<body> <body>
{{> header.html}} {{> header.html}}
<h1> <h1>
{{?htag}} Cards in category:
Category: {{#htag}}
{{#htag}} <a class="cards-tagpiece" href="{{href}}">
<a class="cards-tagpiece" href="{{href}}">
{{^tag}}all{{/tag}} {{^tag}}all{{/tag}}
{{?tag}}» {{tag}}{{/tag}} {{?tag}}» {{tag}}{{/tag}}
</a> </a>
{{/htag}}
{{/htag}} {{/htag}}
{{^htag}}All cards{{/htag}}
</h1> </h1>
{{?subtags}}<h2>Sub-categories</h2> <p>See the <a href="{{listhref}}">complete listing of all pages in this category</a>.</p>
<ul class="cards-subcategories"> <ul class="cards-list">
{{#subtags}}
<li><a href="{{href}}">{{#tags}} » {{.}} {{/tags}}</a></li>
{{/subtags}}
</ul>
{{/subtags}}
{{?pages}} {{?pages}}
<h2>Cards</h2>
<ul class="cards-list">
{{#pages}} {{#pages}}
<li><a href="{{href}}">{{meta.title}}</a></li> <li><a href="{{href}}">{{meta.title}}</a></li>
{{/pages}} {{/pages}}
</ul>
{{/pages}} {{/pages}}
{{?subtags}}
{{#subtags}}
<li>
<a href="{{href}}">{{#tags}} » {{.}} {{/tags}}</a>
<ul>
{{?pages}}
{{#pages}}
<li><a href="{{href}}">{{meta.title}}</a></li>
{{/pages}}
{{/pages}}
{{?subtags}}
{{#subtags}}
<li>
<a href="{{href}}">{{#tags}} » {{.}} {{/tags}}</a>
<ul>
{{?pages}}
{{#pages}}
<li><a href="{{href}}">{{meta.title}}</a></li>
{{/pages}}
{{/pages}}
{{?subtags}}
{{#subtags}}
<li><a href="{{href}}">{{#tags}} » {{.}} {{/tags}}</a> (click to expand)</li>
{{/subtags}}
{{/subtags}}
</ul>
</li>
{{/subtags}}
{{/subtags}}
</ul>
</li>
{{/subtags}}
{{/subtags}}
</ul>
{{> footer.html}} {{> footer.html}}
</body> </body>
</html> </html>