gallery/make-pages/SinglePage.hs

218 lines
5.7 KiB
Haskell
Raw Normal View History

2020-07-09 00:20:09 -04:00
module SinglePage (make) where
2020-07-07 23:28:09 -04:00
2020-07-16 10:07:28 -04:00
import Depend (pageFile)
2020-07-07 23:28:09 -04:00
import Info hiding (Text)
2020-07-15 15:31:46 -04:00
import BuilderQQ
2020-07-16 10:07:28 -04:00
import Records ()
2020-07-12 22:01:31 -04:00
import Control.Exception
import Control.Monad
2020-07-21 19:48:29 -04:00
import Data.Maybe (fromMaybe)
2020-07-07 23:28:09 -04:00
import qualified Data.Text as Strict
import qualified Data.Text.Lazy as Lazy
2020-07-31 20:27:24 -04:00
import qualified Data.Time.Calendar as Time
2020-07-07 23:28:09 -04:00
import qualified Data.Char as Char
import qualified Data.List as List
2020-07-21 18:13:02 -04:00
import System.FilePath (joinPath, splitPath)
2020-07-12 23:02:16 -04:00
-- | e.g. only nsfw images are present for a non-nsfw page
data NoEligibleImages = NoEligibleImages {title :: !Strict.Text}
deriving stock Eq deriving anyclass Exception
instance Show NoEligibleImages where
show (NoEligibleImages {title}) =
Strict.unpack title <> ": no images selected\n" <>
" (probably a nsfw-only work without --nsfw set)"
2020-07-07 23:28:09 -04:00
2020-07-21 18:13:02 -04:00
make :: Bool -> FilePath -> Info -> Lazy.Text
make nsfw dir = toLazyText . make' nsfw dir
2020-07-07 23:28:09 -04:00
2020-07-21 18:13:02 -04:00
make' :: Bool -> FilePath -> Info -> Builder
make' nsfw dir (Info {date, title, artist, tags, nsfwTags,
2020-07-25 07:58:53 -04:00
desc, nsfwDesc, images = allImages, links}) = [b|@0
2020-07-12 22:01:31 -04:00
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content='width=1200,viewport-fit=cover'>
2020-07-21 03:16:05 -04:00
<link rel=stylesheet href=/style/shiny/single.css title=shiny>
<link rel='alternate stylesheet' href=/style/tum/single.css title=tummy>
2020-07-17 06:29:13 -04:00
2020-07-25 07:59:04 -04:00
$0.prefetches
2020-07-19 11:58:19 -04:00
<title>$*title</title>
2020-07-12 22:01:31 -04:00
<header>
2020-07-19 11:58:19 -04:00
<h1>$*title</h1>
2020-07-14 00:51:46 -04:00
$artistTag
2020-07-19 12:03:24 -04:00
<h2 id=date class="right corner">$formattedDate</h2>
2020-07-12 22:01:31 -04:00
$buttonBar
</header>
2020-07-17 06:29:13 -04:00
<script async src=/script/single.js></script>
2020-07-12 22:01:31 -04:00
<main>
<figure id=mainfig>
2020-07-17 06:29:13 -04:00
$warning'
2020-07-21 19:48:29 -04:00
<a id=mainlink href="$@download0">
2020-07-17 06:29:13 -04:00
<img id=mainimg src="$@path0'">
</a>
</figure>
2020-07-12 22:01:31 -04:00
2020-07-17 06:29:13 -04:00
<section class=info>
$descSection
2020-07-12 22:01:31 -04:00
2020-07-17 06:29:13 -04:00
$tagsList
2020-07-12 22:01:31 -04:00
2020-07-17 06:29:13 -04:00
$linksList
</section>
2020-07-12 22:01:31 -04:00
</main>
<footer>
<nav class=back>
2020-07-21 18:13:02 -04:00
<a href=$@undir>back to gallery</a>
2020-07-12 22:01:31 -04:00
</nav>
</footer>
|]
where
2020-07-14 00:51:46 -04:00
artistTag = ifJust artist makeArtist
2020-07-25 07:58:53 -04:00
images | nsfw = allImages
| otherwise = filter #sfw allImages
2020-07-12 22:01:31 -04:00
formattedDate = formatDate date
2020-07-13 02:33:27 -04:00
2020-07-25 07:58:53 -04:00
buttonBar = makeButtonBar title images
2020-07-17 06:29:13 -04:00
image0 = head images
path0 = #path image0
2020-07-21 19:48:29 -04:00
download0 = fromMaybe path0 (#download image0)
2020-07-16 10:07:28 -04:00
path0' = pageFile path0
2020-07-12 22:01:31 -04:00
2020-07-24 19:17:47 -04:00
descSection = makeDesc nsfw desc nsfwDesc
2020-07-13 02:32:59 -04:00
tagsList = makeTags nsfw tags nsfwTags
linksList = extLinks nsfw links
2020-07-12 22:01:31 -04:00
2020-07-25 07:59:04 -04:00
prefetches = map makePrefetch $ tail images
makePrefetch (Image {path}) = [b|<link rel=prefetch href=$@path>|]
2020-07-17 06:29:13 -04:00
warning' = ifJust (#warning image0) \w -> [b|@4
<figcaption id=cw>
2020-07-18 05:45:59 -04:00
<span id=cw-text>cw: <b>$*w</b></span>
2020-07-17 06:29:13 -04:00
</figcaption>
|]
2020-07-21 18:13:02 -04:00
undir = joinPath (replicate (length (splitPath dir)) "..")
2020-07-17 06:29:13 -04:00
2020-07-14 00:51:46 -04:00
makeArtist :: Artist -> Builder
makeArtist (Artist {name, url}) =
2020-07-19 12:03:24 -04:00
[b|<h2 id=artist class="left corner">by $artistLink</h2>|]
2020-07-14 00:51:46 -04:00
where
artistLink = case url of
Just u -> [b|<a href="$*u">$*name</a>|]
Nothing -> [b|$*name|]
makeDesc :: Bool -> Maybe Strict.Text -> Maybe Strict.Text -> Builder
makeDesc nsfw desc nsfwDesc = [b|@4
2020-07-17 06:29:13 -04:00
<section class=desc>
<h2>about</h2>
<div>
$8*desc'
$8*nsfwDesc'
2020-07-17 06:29:13 -04:00
</div>
</section>
2020-07-12 22:01:31 -04:00
|]
where
desc' = fromMaybe "" desc
nsfwDesc' = fromMaybe "" $ guard nsfw *> nsfwDesc
2020-07-07 23:28:09 -04:00
2020-07-25 07:58:53 -04:00
makeButtonBar :: Strict.Text -> [Image] -> Builder
makeButtonBar title images =
2020-07-12 22:01:31 -04:00
case length images of
0 -> throw $ NoEligibleImages title
1 -> ""
_ -> [b|@2
2020-07-17 06:29:13 -04:00
<nav class=alts>
<ul id=altlist>
2020-07-12 22:01:31 -04:00
$6.alts
</ul>
</nav>
|]
2020-07-25 07:58:53 -04:00
where alts = map (uncurry altButton) $ zip [0..] images
2020-07-07 23:28:09 -04:00
altButton :: Int -> Image -> Builder
2020-07-17 06:29:13 -04:00
altButton i (Image {label, path, nsfw, warning}) = [b|@6
2020-07-12 22:01:31 -04:00
<li$nsfwClass>
<input type=radio$checked id="$idLabel" name=variant
2020-07-17 06:29:13 -04:00
autocomplete=off value="$@path'"
data-link="$@path"$warning'>
2020-07-12 22:01:31 -04:00
<label for="$idLabel">$*label</label>
|]
2020-07-07 23:28:09 -04:00
where
2020-07-09 00:19:19 -04:00
nsfwClass = if nsfw then " class=nsfw" else ""
2020-07-16 10:07:28 -04:00
checked = if i == 0 then " checked" else ""
idLabel = escId label
path' = pageFile path
2020-07-17 06:29:13 -04:00
warning' = ifJust warning \w -> [b| data-warning="$*w"|]
2020-07-07 23:28:09 -04:00
escId :: Strict.Text -> Builder
escId = foldMap esc1 . Strict.unpack where
esc1 c
| Char.isSpace c = ""
| c < 'ÿ' && not (Char.isAlphaNum c || c == '-') = "_"
2020-07-16 10:07:28 -04:00
| otherwise = [b|$'c|]
2020-07-07 23:28:09 -04:00
2020-07-11 23:42:31 -04:00
makeTags :: Bool -> [Strict.Text] -> [Strict.Text] -> Builder
2020-07-13 02:32:59 -04:00
makeTags nsfw sfwTags nsfwTags =
2020-07-17 06:29:13 -04:00
if null tags then "" else [b|@4
<section class=tags>
2020-07-12 22:01:31 -04:00
<h2>tags</h2>
<ul>
2020-07-17 06:29:13 -04:00
$8.tagList
2020-07-12 22:01:31 -04:00
</ul>
2020-07-17 06:29:13 -04:00
</section>
2020-07-12 22:01:31 -04:00
|]
2020-07-11 23:42:31 -04:00
where
2020-07-12 22:01:31 -04:00
tagList = map makeTag tags
makeTag t = [b|<li>$*t|]
2020-07-17 10:00:55 -04:00
tags = List.nub $ if nsfw then sfwTags <> nsfwTags else sfwTags
2020-07-11 23:42:31 -04:00
extLinks :: Bool -> [Link] -> Builder
2020-07-13 02:32:59 -04:00
extLinks nsfw allLinks =
2020-07-17 06:29:13 -04:00
if null links then "" else [b|@4
<section class=links>
2020-07-12 22:01:31 -04:00
<h2>links</h2>
<ul>
2020-07-17 06:29:13 -04:00
$8.linkList
2020-07-12 22:01:31 -04:00
</ul>
2020-07-17 06:29:13 -04:00
</section>
2020-07-12 22:01:31 -04:00
|]
where
2020-07-13 02:33:27 -04:00
links = if nsfw then allLinks else filter #sfw allLinks
2020-07-12 22:01:31 -04:00
linkList = map extLink links
2020-07-07 23:28:09 -04:00
extLink :: Link -> Builder
2020-07-12 22:01:31 -04:00
extLink (Link {title, url}) = [b|@6
<li>
<a href="$*url">
$*title
</a>
|]
2020-07-31 20:27:24 -04:00
formatDate :: Day -> Builder
formatDate date = [b|$*week $day $*month $^year|] where
(year, month', day') = Time.toGregorian date
week' = Time.dayOfWeek date
day = nth day'
month = Strict.words "january february march april may june july \
\august september october november december"
!! (month' - 1)
week = Strict.words "mon tue wed thu fri sat sun" !! (fromEnum week' - 1)
nth :: Int -> Builder
nth n = [b|$^n$suf|] where
suf | n >= 10, n <= 19 = "th"
| n `mod` 10 == 1 = "st"
| n `mod` 10 == 2 = "nd"
| n `mod` 10 == 3 = "rd"
| otherwise = "th"