2020-07-16 10:07:28 -04:00
|
|
|
module GalleryPage (make) where
|
|
|
|
|
2020-09-25 17:08:44 -04:00
|
|
|
import BuilderQQ
|
|
|
|
import Date
|
|
|
|
import Info
|
2020-10-06 16:07:39 -04:00
|
|
|
import qualified NsfwWarning
|
2020-09-25 17:08:44 -04:00
|
|
|
|
2022-01-03 14:45:55 -05:00
|
|
|
import Control.Monad
|
2020-08-03 17:07:59 -04:00
|
|
|
import Data.Foldable
|
2024-07-07 10:22:14 -04:00
|
|
|
import Data.Function ((&))
|
2020-08-03 17:07:59 -04:00
|
|
|
import qualified Data.HashMap.Strict as HashMap
|
2020-08-03 20:27:19 -04:00
|
|
|
import Data.HashSet (HashSet)
|
|
|
|
import qualified Data.HashSet as HashSet
|
2024-07-07 10:22:14 -04:00
|
|
|
import Data.List (intersperse, sort, sortOn)
|
2022-02-27 17:48:35 -05:00
|
|
|
import Data.Maybe
|
2024-07-07 10:22:14 -04:00
|
|
|
import Data.Ord (Down (..))
|
2020-07-16 10:07:28 -04:00
|
|
|
import qualified Data.Text.Lazy as Lazy
|
2020-08-11 14:29:54 -04:00
|
|
|
import System.FilePath (takeDirectory, joinPath, splitPath)
|
2020-07-16 10:07:28 -04:00
|
|
|
|
2020-08-11 14:29:54 -04:00
|
|
|
make :: Text -> GalleryInfo -> [(FilePath, Info)] -> Lazy.Text
|
|
|
|
make root ginfo infos = toLazyText $ make' root ginfo infos
|
2020-07-16 10:07:28 -04:00
|
|
|
|
2020-08-03 20:25:59 -04:00
|
|
|
|
2020-08-11 14:29:54 -04:00
|
|
|
make' :: Text -> GalleryInfo -> [(FilePath, Info)] -> Builder
|
2024-08-18 01:37:58 -04:00
|
|
|
make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|
|
2020-07-16 10:07:28 -04:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang=en>
|
|
|
|
<meta charset=utf-8>
|
2020-08-04 17:12:58 -04:00
|
|
|
<link rel=stylesheet href=/style/shiny/gallery.css>
|
2020-08-04 18:52:56 -04:00
|
|
|
<link rel=icon href=/style/niss.svg>
|
2020-07-19 12:04:40 -04:00
|
|
|
<link rel=alternate href=rss.xml type=application/rss+xml>
|
2020-07-16 10:07:28 -04:00
|
|
|
|
2020-08-11 14:29:54 -04:00
|
|
|
<meta property=og:type content=og:website>
|
2020-08-30 13:13:40 -04:00
|
|
|
<meta property=og:title content="$title">
|
|
|
|
<meta property=og:site_name content="$title">
|
|
|
|
<meta property=og:description content="$desc">
|
2024-08-18 00:22:55 -04:00
|
|
|
<meta property=og:image content="$url/style/card.png">
|
2020-08-11 14:29:54 -04:00
|
|
|
<meta property=og:url content="$url">
|
2020-09-19 02:13:13 -04:00
|
|
|
<meta name=twitter:site content=@2_gecs>
|
2020-08-11 14:29:54 -04:00
|
|
|
<meta name=twitter:card content=summary>
|
|
|
|
|
2022-11-12 06:14:42 -05:00
|
|
|
<meta name=robots content='noai,noimageai'>
|
|
|
|
|
2023-09-06 19:17:21 -04:00
|
|
|
<script src=/script/gallery.js type=module></script>
|
2024-08-18 01:37:58 -04:00
|
|
|
$nsfwScript
|
2020-08-03 17:11:15 -04:00
|
|
|
|
2020-08-30 13:13:40 -04:00
|
|
|
<title>$title</title>
|
2020-07-16 10:07:28 -04:00
|
|
|
|
2024-08-18 01:37:58 -04:00
|
|
|
$nsfwDialog
|
2020-10-06 16:07:39 -04:00
|
|
|
|
|
|
|
<div class=page>
|
|
|
|
<header>
|
|
|
|
<h1>$title</h1>
|
2023-06-21 13:58:01 -04:00
|
|
|
<a class="right corner" href=rss.xml>rss</a>
|
|
|
|
<a class="left corner" href=$undir>back</a>
|
2020-10-06 16:07:39 -04:00
|
|
|
</header>
|
|
|
|
|
|
|
|
<nav id=filters>
|
|
|
|
<details id=filters-details>
|
|
|
|
<summary><h2>filters</h2></summary>
|
|
|
|
<div>
|
|
|
|
<h3>show only</h3>
|
2022-12-29 21:19:33 -05:00
|
|
|
<ul id=require class=filterlist>
|
2024-08-18 01:37:58 -04:00
|
|
|
$requireFilters
|
2020-10-06 16:07:39 -04:00
|
|
|
</ul>
|
|
|
|
|
|
|
|
<h3>exclude</h3>
|
2022-12-29 21:19:33 -05:00
|
|
|
<ul id=exclude class=filterlist>
|
2024-08-18 01:37:58 -04:00
|
|
|
$excludeFilters
|
2020-10-06 16:07:39 -04:00
|
|
|
</ul>
|
|
|
|
|
2022-11-12 06:13:44 -05:00
|
|
|
<ul id=filterstuff>
|
|
|
|
<li><a href=# id=clear>clear</a>
|
|
|
|
<li><a href=# id=sortalpha>sort by name</a>
|
|
|
|
<li><a href=# id=sortuses>sort by uses</a>
|
|
|
|
<li><a href=# id=singles>toggle single-use tags</a>
|
|
|
|
</ul>
|
2020-10-06 16:07:39 -04:00
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
<main>
|
2024-08-21 02:22:28 -04:00
|
|
|
$items
|
2020-10-06 16:07:39 -04:00
|
|
|
</main>
|
|
|
|
</div>
|
2020-07-16 10:07:28 -04:00
|
|
|
|]
|
|
|
|
where
|
2020-07-18 05:43:35 -04:00
|
|
|
items = map (uncurry $ makeYearItems nsfw) infosByYear
|
2020-08-03 20:25:59 -04:00
|
|
|
|
2024-07-07 10:22:14 -04:00
|
|
|
infosByYear :: [(Int, [(FilePath, Info)])]
|
|
|
|
infosByYear = infos &
|
2024-07-11 16:00:00 -04:00
|
|
|
filter (not . (.unlisted) . snd) &
|
2024-07-07 10:22:14 -04:00
|
|
|
sortOn (Down . compareKeyFor nsfw . snd) &
|
2024-07-11 16:00:00 -04:00
|
|
|
groupOnKey (\(_, i) -> latestYearFor nsfw i)
|
2020-08-03 20:25:59 -04:00
|
|
|
|
2020-07-23 13:51:53 -04:00
|
|
|
undir = joinPath (replicate (length (splitPath prefix)) "..")
|
2020-08-03 20:25:59 -04:00
|
|
|
|
2020-08-03 17:07:59 -04:00
|
|
|
allTags = infos
|
2024-11-03 18:55:07 -05:00
|
|
|
& concatMap (map (,1) . HashSet.toList . tagsFor nsfw . snd)
|
2020-08-03 17:07:59 -04:00
|
|
|
& HashMap.fromListWith (+) & HashMap.toList
|
2023-06-21 13:58:01 -04:00
|
|
|
& sort
|
2020-08-03 20:27:19 -04:00
|
|
|
|
|
|
|
requireFilters = map (uncurry $ makeFilter "require" mempty) allTags
|
|
|
|
excludeFilters = map (uncurry $ makeFilter "exclude" hidden) allTags
|
2020-07-18 05:43:35 -04:00
|
|
|
|
2024-07-11 16:00:00 -04:00
|
|
|
nsfw = filters.nsfw /= NoNsfw
|
2020-08-03 20:25:59 -04:00
|
|
|
|
2020-08-30 13:13:40 -04:00
|
|
|
url = [b|$root/$prefix|]
|
2020-08-11 14:29:54 -04:00
|
|
|
|
2022-01-03 14:45:55 -05:00
|
|
|
nsfw' = NsfwWarning.Gallery <$ guard nsfw
|
|
|
|
nsfwScript = NsfwWarning.script nsfw'
|
|
|
|
nsfwDialog = NsfwWarning.dialog nsfw'
|
2020-10-06 16:07:39 -04:00
|
|
|
|
2024-07-07 10:22:14 -04:00
|
|
|
-- from @extra@
|
|
|
|
groupOnKey :: Eq k => (a -> k) -> [a] -> [(k, [a])]
|
|
|
|
groupOnKey _ [] = []
|
|
|
|
groupOnKey f (x:xs) = (fx, x:yes) : groupOnKey f no where
|
|
|
|
fx = f x
|
|
|
|
(yes, no) = span (\y -> fx == f y) xs
|
|
|
|
|
2020-08-03 20:27:19 -04:00
|
|
|
makeFilter :: Text -> HashSet Text -> Text -> Int -> Builder
|
2024-08-18 01:37:58 -04:00
|
|
|
makeFilter prefix initial tag count = [b|
|
2021-03-12 23:29:57 -05:00
|
|
|
<li$hidden>
|
2020-08-30 13:13:40 -04:00
|
|
|
<input type=checkbox id="$id'" value="$tag"$checked>
|
2020-09-17 13:12:48 -04:00
|
|
|
<label for="$id'" data-count=$count>$tag</label>
|
2020-08-03 17:10:52 -04:00
|
|
|
|]
|
2020-08-03 20:27:19 -04:00
|
|
|
where
|
2020-08-30 13:13:40 -04:00
|
|
|
id' = [b|$prefix$&_$tag'|]
|
2020-08-03 20:27:19 -04:00
|
|
|
tag' = escId tag
|
2024-08-21 01:40:28 -04:00
|
|
|
checked = if HashSet.member tag initial then [b|$& checked|] else ""
|
|
|
|
hidden = if count <= 1 then [b|$& hidden|] else ""
|
2020-08-03 17:10:52 -04:00
|
|
|
|
2020-07-18 05:43:35 -04:00
|
|
|
makeYearItems :: Bool -- ^ nsfw
|
2020-09-25 17:08:44 -04:00
|
|
|
-> Int -- ^ year
|
2020-07-18 05:43:35 -04:00
|
|
|
-> [(FilePath, Info)]
|
|
|
|
-> Builder
|
2024-08-18 01:37:58 -04:00
|
|
|
makeYearItems nsfw year infos = [b|
|
2024-08-21 02:22:28 -04:00
|
|
|
<h2 class="item year-marker" id="marker-$year" aria-label=$year>
|
|
|
|
$year'
|
|
|
|
</h2>
|
2024-08-18 01:37:58 -04:00
|
|
|
$items
|
2020-07-18 05:43:35 -04:00
|
|
|
|]
|
2020-07-20 16:40:34 -04:00
|
|
|
where
|
|
|
|
items = map (uncurry $ makeItem nsfw) infos
|
2020-08-30 13:13:40 -04:00
|
|
|
year' = show year & foldMap \c -> [b|<span class=y>$c</span>|]
|
2020-07-16 10:07:28 -04:00
|
|
|
|
2020-07-18 05:40:56 -04:00
|
|
|
makeItem :: Bool -> FilePath -> Info -> Builder
|
2024-08-18 01:37:58 -04:00
|
|
|
makeItem nsfw file info@(Info {bg}) = [b|
|
2024-08-21 02:22:28 -04:00
|
|
|
<figure class="item post$nsfw'" data-year=$year' data-updated="$updated'"
|
2020-09-19 01:51:52 -04:00
|
|
|
data-tags="$tags'">
|
2023-06-21 13:58:01 -04:00
|
|
|
<a href="$dir">
|
2024-07-11 16:00:00 -04:00
|
|
|
<img src="$thumbnail" loading=lazy$bgStyle
|
2023-06-21 16:38:34 -04:00
|
|
|
width=200 height=200
|
2024-10-21 08:24:17 -04:00
|
|
|
alt="$title" title="$tooltip">
|
2023-06-21 13:58:01 -04:00
|
|
|
</a>
|
2024-08-21 02:22:28 -04:00
|
|
|
</figure>
|
2020-07-16 10:07:28 -04:00
|
|
|
|]
|
|
|
|
where
|
2024-10-21 08:36:11 -04:00
|
|
|
title = escAttr $ fromMaybe info.title info.galleryTitle
|
2024-07-11 16:00:00 -04:00
|
|
|
dir = takeDirectory file
|
|
|
|
thumbnail = getThumb dir info
|
2024-08-21 01:40:28 -04:00
|
|
|
nsfw' = if nsfw && anyNsfw info then [b|$& nsfw|] else ""
|
2024-11-03 18:55:07 -05:00
|
|
|
tags' = fold $ intersperse ";" $ map fromText $
|
|
|
|
sort $ HashSet.toList $ tagsFor nsfw info
|
2024-07-11 16:00:00 -04:00
|
|
|
date = latestDateFor nsfw info
|
|
|
|
date' = formatTooltip date
|
|
|
|
year' = date.year
|
|
|
|
updated' = if hasUpdatesFor nsfw info then [b|true|] else [b|false|]
|
2024-08-21 01:40:28 -04:00
|
|
|
bgStyle = case bg of Other col -> [b|$& style="background: $col"|]; _ -> ""
|
2024-07-11 16:00:00 -04:00
|
|
|
tooltip = [b|$title ($upd$date')|]
|
|
|
|
where upd = if hasUpdatesFor nsfw info then "updated " else "" :: Builder
|