Compare commits

..

No commits in common. "7745722009e371a71f5fd6f8048234b8f7303a10" and "fa0b826c26c94649f8bd6a9d81c87414cdd7af1a" have entirely different histories.

7 changed files with 269 additions and 148 deletions

View file

@ -1,72 +1,184 @@
{-# LANGUAGE PatternSynonyms, TemplateHaskell #-} {-# LANGUAGE PatternSynonyms, TemplateHaskell #-}
module BuilderQQ module BuilderQQ
(b, Builder, toStrictText, toLazyText, fromText, fromString, (b,
ifJust, escId, escAttr, CanBuild (..)) Builder, toStrictText, toLazyText, fromText, fromString, fromChar,
textMap, ifJust, escId, escAttr, CanBuild (..))
where where
import Data.Char (isSpace, isAlphaNum) import Data.Char (isLower, isSpace, isDigit, isAlphaNum)
import Language.Haskell.TH import Language.Haskell.TH
import Language.Haskell.TH.Quote import Language.Haskell.TH.Quote
import Data.List (dropWhileEnd) import Data.List (intersperse)
import Data.Maybe (mapMaybe, fromMaybe) import Data.Maybe (mapMaybe, fromMaybe)
import Data.Text.Lazy.Builder import Data.Text.Lazy.Builder
(Builder, fromText, fromLazyText, fromString, singleton, toLazyText) (Builder, fromText, fromLazyText, fromString, singleton, toLazyText)
import qualified Data.Text as Strict import Text.Read (readMaybe)
import qualified Data.Text.Lazy as Lazy import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LText
import Data.Text.Lazy (toStrict) import Data.Text.Lazy (toStrict)
import Data.List.NonEmpty (NonEmpty, toList) import Data.Foldable
import Data.Semigroup
import Data.List.NonEmpty (NonEmpty)
data Chunk = Lit String | Var String data ChunkType = Lit | Var VarType deriving Show
data VarType =
Plain
| Reindent !Int
deriving Show
type Chunk = (ChunkType, Text)
parseB :: String -> ExpQ indent :: Int -> LText.Text -> Builder
parseB = toExpQ . reverse . go "" [] . dropWhileEnd isSpace where indent i str
go acc cs [] = addLit acc cs | LText.all isSpace str = ""
go acc cs ('$':'&':rest) = go acc cs rest -- $&: expands to nothing | otherwise = replicateB i ' ' <> fromLazyText str
go acc cs ('$':'$':rest) = go ('$' : acc) cs rest -- $$: expands to one $
go acc cs ('$':rest) = go "" (Var var : addLit acc cs) rest' -- $var
where (var, rest') = span isIdChar rest
go acc cs (c:rest) = go (c : acc) cs rest
addLit l cs = if null l then cs else Lit (reverse l) : cs reindentB :: Int -> Builder -> Builder
isIdChar c = isAlphaNum c || c `elem` ("_'" :: String) reindentB i (toLazyText -> str) =
fold $ intersperse "\n" $
map2 (fromLazyText . dropIndent) (indent i . dropIndent) ls
where
ls = dropWhile (LText.all isSpace) $ LText.lines str
ls' = filter (LText.any $ not . isSpace) ls
toExpQ cs = [|mconcat $(listE $ mapMaybe chunk1 cs) :: Builder|] dropIndent = LText.drop minIndent
chunk1 (Lit lit) = Just $ stringE lit
chunk1 (Var name) = Just $ [|build $(varE $ mkName name)|] minIndent =
getMin $ fromMaybe 0 $ foldMap (Just . Min . indentOf) ls'
indentOf = go 0 where
go n (' ' :.. cs) = go (n + 1) cs
go n ('\t' :.. cs) = go (((n `mod` 8) + 1) * 8) cs
go n _ = n
map2 _ _ [] = []
map2 f g (x:xs) = f x : map g xs
toStrictText :: Builder -> Strict.Text chunks :: Text -> [Chunk]
chunks = reverse . go "" [] . trimEnd where
go acc cs NilT = if Text.null acc' then cs else (Lit, acc') : cs
where acc' = toStrictText acc
-- $&: expands to nothing
go acc cs ('$' :. '&' :. rest) = go acc cs rest
-- $$: expands to one $
go acc cs ('$' :. '$' :. rest) = go (acc <> "$") cs rest
-- $n.var (n a number): expands to builder var indented by n
go acc cs ('$' :. rest@(d :. _)) | isDigit d =
go "" ((Var (Reindent n), var) : lit acc : cs) rest3
where
(read . Text.unpack -> n, rest2) = Text.span isDigit rest
(var, rest3) = splitVar $ Text.tail rest2
-- $var: expands to that var's contents
go acc cs ('$' :. rest) =
go "" ((Var Plain, var) : lit acc : cs) rest2
where (var, rest2) = splitVar rest
go acc cs (c :. rest) = go (acc <> singleton c) cs rest
splitVar s
| (var@(v :. _), s') <- Text.span isIdChar s,
isLower v || v == '_'
= (var, s')
splitVar _ = error "invalid variable name"
isIdChar c = isAlphaNum c || c `elem` ("_'" :: String)
lit s = (Lit, toStrictText s)
trimEnd = Text.dropWhileEnd isSpace
chunksWithReindent :: String -> [Chunk]
chunksWithReindent ('@':str)
| [(n',rest)] <- lex str,
Just n <- readMaybe n'
= chunks $ toStrictText $ reindent n $ Text.pack rest
chunksWithReindent str = chunks $ Text.pack str
toStrictText :: Builder -> Text
toStrictText = toStrict . toLazyText toStrictText = toStrict . toLazyText
b :: QuasiQuoter
b = QuasiQuoter parseB undefined undefined undefined
chunksToExpQ :: [Chunk] -> ExpQ
chunksToExpQ cs = [|mconcat $es :: Builder|] where
es = listE $ mapMaybe chunk1 cs
chunk1 (Lit, "") = Nothing
chunk1 (Lit, lit) = Just $ stringE $ Text.unpack lit
chunk1 (Var t, name) = Just $ case t of
Plain -> [|build $var|]
Reindent n -> [|reindent n $var|]
where var = varE (mkName $ Text.unpack name)
replicateB :: Int -> Char -> Builder
replicateB n c = fromText $ Text.replicate n $ Text.singleton c
b :: QuasiQuoter
b = QuasiQuoter {
quoteExp = chunksToExpQ . chunksWithReindent,
quotePat = error "can't use in a pattern",
quoteType = error "can't use in a type",
quoteDec = error "can't use at top level"
}
pattern NilT :: Text
pattern NilT <- (Text.null -> True)
where NilT = ""
infixr 5 :.
pattern (:.) :: Char -> Text -> Text
pattern c :. t <- (Text.uncons -> Just (c, t))
where c :. t = Text.cons c t
{-# COMPLETE NilT, (:.) :: Text #-}
infixr 5 :..
pattern (:..) :: Char -> LText.Text -> LText.Text
pattern c :.. t <- (LText.uncons -> Just (c, t))
where c :.. t = LText.cons c t
fromChar :: Char -> Builder
fromChar = singleton
textMap :: (Char -> Builder) -> Text -> Builder
textMap f = Text.foldl' (\buf c -> buf <> f c) mempty
ifJust :: Monoid b => Maybe a -> (a -> b) -> b ifJust :: Monoid b => Maybe a -> (a -> b) -> b
ifJust x f = maybe mempty f x ifJust x f = maybe mempty f x
escId :: Strict.Text -> Builder escId :: Text -> Builder
escId = foldMap esc1 . Strict.unpack where escId = foldMap esc1 . Text.unpack where
esc1 c | isSpace c = "" esc1 c | isSpace c = ""
| latin1Special c = "_" | latin1Special c = "_"
| otherwise = singleton c | otherwise = fromChar c
latin1Special c = latin1Special c =
c <= 'ÿ' && not (isAlphaNum c) && c /= '-' c <= 'ÿ' && not (isAlphaNum c) && c /= '-'
escAttr :: Strict.Text -> Builder escAttr :: Text -> Builder
escAttr = foldMap esc1 . Strict.unpack where escAttr = foldMap esc1 . Text.unpack where
esc1 c = fromMaybe (singleton c) $ lookup c esc1 '<' = "&lt;"
[('<', "&lt;"), ('>', "&gt;"), ('"', "&quot;"), ('\'', "&apos;")] esc1 '>' = "&gt;"
esc1 '"' = "&quot;"
esc1 '\'' = "&apos;"
esc1 c = fromChar c
class CanBuild a where build :: a -> Builder class CanBuild a where
build :: a -> Builder
reindent :: Int -> a -> Builder
reindent i = reindentB i . build
instance CanBuild Builder where build = id instance CanBuild Builder where build = id
instance CanBuild Strict.Text where build = fromText instance CanBuild Text where build = fromText
instance CanBuild Lazy.Text where build = fromLazyText instance CanBuild LText.Text where build = fromLazyText
instance CanBuild Char where build = singleton instance CanBuild Char where build = singleton
instance CanBuild String where build = fromString instance CanBuild String where build = fromString
newtype ShowBuild a = ShowBuild a deriving newtype Show newtype ShowBuild a = ShowBuild a deriving newtype Show
instance Show a => CanBuild (ShowBuild a) where build = build . show instance Show a => CanBuild (ShowBuild a) where build = build . show
@ -76,5 +188,8 @@ deriving via ShowBuild Integer instance CanBuild Integer
instance {-# OVERLAPPABLE #-} CanBuild a => CanBuild [a] where instance {-# OVERLAPPABLE #-} CanBuild a => CanBuild [a] where
build = foldMap \x -> build x <> "\n" build = foldMap \x -> build x <> "\n"
reindent n = fold . intersperse ("\n" <> replicateB n ' ') . map build
instance CanBuild a => CanBuild (NonEmpty a) where build = build . toList instance CanBuild a => CanBuild (NonEmpty a) where
build = build . toList
reindent n = reindent n . toList

View file

@ -56,19 +56,19 @@ dependGallery ginfo index infos build data_ tmp =
dependGallery' :: GalleryInfo -> FilePath -> [(FilePath, Info)] dependGallery' :: GalleryInfo -> FilePath -> [(FilePath, Info)]
-> FilePath -> FilePath -> FilePath -> Builder -> FilePath -> FilePath -> FilePath -> Builder
dependGallery' (GalleryInfo {prefix, filters}) dependGallery' (GalleryInfo {prefix, filters})
indexFile infos' build data_ tmp = [b| indexFile infos' build data_ tmp = [b|@0
$index: $gallery $index: $gallery
$gallery: $pages' $files' $rss $indexFile $$(MAKEPAGES) $gallery: $pages' $files' $rss $indexFile $$(MAKEPAGES)
$$(call gallery,$indexFile,$prefix) $$(call gallery,$indexFile,$prefix)
$rss: $files' $indexFile $$(MAKEPAGES) $rss: $files' $indexFile $$(MAKEPAGES)
$$(call rss,$indexFile,$prefix,$data_) $$(call rss,$indexFile,$prefix,$data_)
$rules $rules
$incs $incs
|] |]
where where
infos = filter (matchFilters filters . snd) infos' infos = filter (matchFilters filters . snd) infos'
@ -96,19 +96,19 @@ makeRules :: FilePath -- ^ prefix
-> FilePath -- ^ data dir -> FilePath -- ^ data dir
-> FilePath -- ^ tmp dir -> FilePath -- ^ tmp dir
-> Builder -> Builder
makeRules prefix indexFile filters build data_ tmp = [b| makeRules prefix indexFile filters build data_ tmp = [b|@0
$buildPrefix/%/index.html: $data_/%/info.yaml $$(MAKEPAGES) $buildPrefix/%/index.html: $data_/%/info.yaml $$(MAKEPAGES)
$$(call single,$data_,$prefix,$indexFile,$flags) $$(call single,$data_,$prefix,$indexFile,$flags)
$tmpPrefix/%.mk: $data_/%/info.yaml $$(MAKEPAGES) $tmpPrefix/%.mk: $data_/%/info.yaml $$(MAKEPAGES)
$$(call depend-single,$prefix,$indexFile,$build,$data_,$flags) $$(call depend-single,$prefix,$indexFile,$build,$data_,$flags)
$buildPrefix/%: $tmp/% $buildPrefix/%: $tmp/%
$$(call copy,-l) $$(call copy,-l)
$buildPrefix/%: $data_/% $buildPrefix/%: $data_/%
$$(call copy) $$(call copy)
|] |]
where where
buildPrefix = build </> prefix buildPrefix = build </> prefix
tmpPrefix = tmp </> prefix tmpPrefix = tmp </> prefix

View file

@ -22,7 +22,7 @@ make root ginfo infos = toLazyText $ make' root ginfo infos
make' :: Text -> GalleryInfo -> [(FilePath, Info)] -> Builder make' :: Text -> GalleryInfo -> [(FilePath, Info)] -> Builder
make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b| make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
<!DOCTYPE html> <!DOCTYPE html>
<html lang=en> <html lang=en>
<meta charset=utf-8> <meta charset=utf-8>
@ -42,11 +42,11 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|
<meta name=robots content='noai,noimageai'> <meta name=robots content='noai,noimageai'>
<script src=/script/gallery.js type=module></script> <script src=/script/gallery.js type=module></script>
$nsfwScript $0.nsfwScript
<title>$title</title> <title>$title</title>
$nsfwDialog $0.nsfwDialog
<div class=page> <div class=page>
<header> <header>
@ -61,12 +61,12 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|
<div> <div>
<h3>show only</h3> <h3>show only</h3>
<ul id=require class=filterlist> <ul id=require class=filterlist>
$requireFilters $10.requireFilters
</ul> </ul>
<h3>exclude</h3> <h3>exclude</h3>
<ul id=exclude class=filterlist> <ul id=exclude class=filterlist>
$excludeFilters $10.excludeFilters
</ul> </ul>
<ul id=filterstuff> <ul id=filterstuff>
@ -81,7 +81,7 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|
<main> <main>
<ul class=grid> <ul class=grid>
$items $6.items
</ul> </ul>
</main> </main>
</div> </div>
@ -121,7 +121,7 @@ groupOnKey f (x:xs) = (fx, x:yes) : groupOnKey f no where
(yes, no) = span (\y -> fx == f y) xs (yes, no) = span (\y -> fx == f y) xs
makeFilter :: Text -> HashSet Text -> Text -> Int -> Builder makeFilter :: Text -> HashSet Text -> Text -> Int -> Builder
makeFilter prefix initial tag count = [b| makeFilter prefix initial tag count = [b|@0
<li$hidden> <li$hidden>
<input type=checkbox id="$id'" value="$tag"$checked> <input type=checkbox id="$id'" value="$tag"$checked>
<label for="$id'" data-count=$count>$tag</label> <label for="$id'" data-count=$count>$tag</label>
@ -136,17 +136,17 @@ makeYearItems :: Bool -- ^ nsfw
-> Int -- ^ year -> Int -- ^ year
-> [(FilePath, Info)] -> [(FilePath, Info)]
-> Builder -> Builder
makeYearItems nsfw year infos = [b| makeYearItems nsfw year infos = [b|@0
<li class="item year-marker" id="marker-$year"> <li class="item year-marker" id="marker-$year">
<span class=year-text>$year'</span> <span class=year-text>$year'</span>
$items $0.items
|] |]
where where
items = map (uncurry $ makeItem nsfw) infos items = map (uncurry $ makeItem nsfw) infos
year' = show year & foldMap \c -> [b|<span class=y>$c</span>|] year' = show year & foldMap \c -> [b|<span class=y>$c</span>|]
makeItem :: Bool -> FilePath -> Info -> Builder makeItem :: Bool -> FilePath -> Info -> Builder
makeItem nsfw file info@(Info {bg}) = [b| makeItem nsfw file info@(Info {bg}) = [b|@0
<li class="item post$nsfw'" data-year=$year' data-updated="$updated'" <li class="item post$nsfw'" data-year=$year' data-updated="$updated'"
data-tags="$tags'"> data-tags="$tags'">
<a href="$dir"> <a href="$dir">

View file

@ -9,7 +9,7 @@ make :: Text -> IndexInfo -> Lazy.Text
make root info = toLazyText $ make' root info make root info = toLazyText $ make' root info
make' :: Text -> IndexInfo -> Builder make' :: Text -> IndexInfo -> Builder
make' root (IndexInfo {title, desc, galleries, links, footer}) = [b| make' root (IndexInfo {title, desc, galleries, links, footer}) = [b|@0
<!DOCTYPE html> <!DOCTYPE html>
<html lang=en> <html lang=en>
<meta charset=utf-8> <meta charset=utf-8>
@ -37,47 +37,47 @@ make' root (IndexInfo {title, desc, galleries, links, footer}) = [b|
</header> </header>
<main> <main>
$galleryList $4.galleryList
$linkList $4.linkList
</main> </main>
$footer' $2.footer'
</div> </div>
|] |]
where where
galleryList = if null galleries then "" else [b| galleryList = if null galleries then "" else [b|@0
<nav aria-label="gallery list"> <nav aria-label="gallery list">
<ul id=gallery-list class=list> <ul id=gallery-list class=list>
$items $4.items
</ul> </ul>
</nav> </nav>
|] |]
where items = map makeItem galleries where items = map makeItem galleries
linkList = if null links then "" else [b| linkList = if null links then "" else [b|@0
<nav aria-label="other links"> <nav aria-label="other links">
<ul id=link-list class=list> <ul id=link-list class=list>
$items $4.items
</ul> </ul>
</nav> </nav>
|] |]
where items = map makeLink links where items = map makeLink links
footer' = case footer of footer' = case footer of
Nothing -> "" Nothing -> ""
Just f -> [b| Just f -> [b|@0
<footer> <footer>
$f $2.f
</footer> </footer>
|] |]
url = [b|$root|] url = [b|$root|]
makeItem :: GalleryInfo -> Builder makeItem :: GalleryInfo -> Builder
makeItem (GalleryInfo {title, desc, prefix, filters}) = [b| makeItem (GalleryInfo {title, desc, prefix, filters}) = [b|@0
<li$nsfw><a href=$prefix title="$desc">$title</a></li> <li$nsfw><a href=$prefix title="$desc">$title</a></li>
|] |]
where nsfw = if hasNsfw filters then [b| class=nsfw|] else "" where nsfw = if hasNsfw filters then [b| class=nsfw|] else ""
makeLink :: Link -> Builder makeLink :: Link -> Builder
makeLink (Link {title, url, nsfw}) = [b| makeLink (Link {title, url, nsfw}) = [b|@0
<li$nsfw'><a href=$url>$title</a> <li$nsfw'><a href=$url>$title</a>
|] |]
where nsfw' = if nsfw then [b| class=nsfw|] else "" where nsfw' = if nsfw then [b| class=nsfw|] else ""

View file

@ -16,7 +16,7 @@ script (Just _) = [b|<script src=/script/nsfw-warning.js type=module></script>|]
dialog :: Maybe What -> Builder dialog :: Maybe What -> Builder
dialog Nothing = "" dialog Nothing = ""
dialog (Just what) = [b| dialog (Just what) = [b|@0
<dialog id=nsfw-dialog> <dialog id=nsfw-dialog>
<h1>cw: lewd art</h1> <h1>cw: lewd art</h1>
<img src=/style/stop_hand.svg> <img src=/style/stop_hand.svg>

View file

@ -10,7 +10,6 @@ import Data.Function (on)
import qualified Data.Text as Strict import qualified Data.Text as Strict
import qualified Data.Text.Lazy as Lazy import qualified Data.Text.Lazy as Lazy
import System.FilePath (takeDirectory) import System.FilePath (takeDirectory)
import Control.Monad
make :: Strict.Text -- ^ website root e.g. @https://gallery.niss.website@ make :: Strict.Text -- ^ website root e.g. @https://gallery.niss.website@
@ -24,7 +23,7 @@ make root name ginfo output infos =
make' :: Strict.Text -> Strict.Text -> GalleryInfo make' :: Strict.Text -> Strict.Text -> GalleryInfo
-> Maybe FilePath -> [(FilePath, Info)] -> Builder -> Maybe FilePath -> [(FilePath, Info)] -> Builder
make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b| make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|@0
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"> <rss version="2.0">
<channel> <channel>
@ -33,7 +32,7 @@ make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|
<description>$desc</description> <description>$desc</description>
$selflink $selflink
$items $4.items
</channel> </channel>
</rss> </rss>
|] |]
@ -48,9 +47,9 @@ make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|
Just o -> [b|<link href="$link/$o" rel="self" />|] Just o -> [b|<link href="$link/$o" rel="self" />|]
makeItem :: Strict.Text -> FilePath -> Bool -> FilePath -> Info -> Builder makeItem :: Strict.Text -> FilePath -> Bool -> FilePath -> Info -> Builder
makeItem root prefix nsfw path info@(Info {title}) = [b| makeItem root prefix nsfw path i@(Info {title, artist}) = [b|@4
<item> <item>
<title>$title$suffix</title> <title>$title$suf</title>
<link>$link</link> <link>$link</link>
<guid>$link</guid> <guid>$link</guid>
$body $body
@ -58,39 +57,46 @@ makeItem root prefix nsfw path info@(Info {title}) = [b|
</item> </item>
|] |]
where where
body = [b| suf = let parts = catMaybes [o18, cnt, up] in
<description> <![CDATA[ if null parts then ""
$image else " (" <> mconcat (intersperse ", " parts) <> ")"
$artist up = if hasUpdatesFor nsfw i then Just "updated" else Nothing
$desc o18 = if nsfw && anyNsfw i then Just "🔞" else Nothing
]]> </description> cnt = let len = maybe 0 length $ allImages <$> imagesFor nsfw i in
|] if len == 1 then Nothing else Just [b|$len images|]
suffix = if null parts then ""
else " (" <> mconcat (intersperse ", " parts) <> ")"
parts = catMaybes [o18, cnt, up]
up = do guard $ hasUpdatesFor nsfw info; Just "updated"
o18 = do guard $ nsfw && anyNsfw info; Just "🔞"
cnt = do let len = maybe 0 length $ allImages <$> imagesFor nsfw info
guard $ len /= 1; Just [b|$len images|]
dir = takeDirectory path dir = takeDirectory path
link = [b|$root/$prefix/$dir|] link = [b|$root/$prefix/$dir|]
date = formatRSS $ latestDateFor nsfw info date = formatRSS $ latestDateFor nsfw i
artist = ifJust info.artist \case artist' = ifJust artist \case
Artist name Nothing -> [b|<p>by $name|] Artist {name, url = Nothing} -> [b|<p>by $name|]
Artist name (Just url) -> [b|<p>by <a href="$url">$name</a>|] Artist {name, url = Just url} -> [b|<p>by <a href="$url">$name</a>|]
desc = makeDesc $ descFor nsfw info desc = descFor nsfw i
desc' = makeDesc desc
image = case previewImage info of body = [b|@6
Just (PFull img) -> figure $ pageFile img <description> <![CDATA[
Just (PThumb th) -> figure $ thumbFile th $8.image
Nothing -> "" $8.artist'
figure p = [b|<figure> <a href="$link"><img src="$link/$p"></a> </figure>|] $8.desc'
]]> </description>
|]
image = case previewImage i of
Just (PFull img) -> go $ pageFile img
Just (PThumb th) -> go $ thumbFile th
Nothing -> ""
where go p = [b|@0
<figure>
<a href="$link"><img src="$link/$p"></a>
</figure>
|]
makeDesc :: Desc -> Builder makeDesc :: Desc -> Builder
makeDesc NoDesc = "" makeDesc NoDesc = ""
makeDesc (TextDesc txt) = [b|$txt|] makeDesc (TextDesc txt) = [b|$txt|]
makeDesc (LongDesc fs) = [b|<dl>$fields</dl>|] makeDesc (LongDesc fs) = [b|<dl>$fields</dl>|]
where fields = map (\(DescField {name, text}) -> [b|<dt>$name <dd>$text|]) fs where
fields = map makeField fs
makeField (DescField {name, text}) = [b|<dt>$name <dd>$text|]

View file

@ -66,7 +66,7 @@ make' root siteName prefix nsfw _dataDir dir
where path' = bigFile img where path' = bigFile img
let prefetches = map makePrefetch otherImages let prefetches = map makePrefetch otherImages
let makeWarning w = [b| let makeWarning w = [b|@0
<figcaption id=cw aria-role=button tabindex=0> <figcaption id=cw aria-role=button tabindex=0>
<span id=cw-text>$w</span> <span id=cw-text>$w</span>
</figcaption> </figcaption>
@ -77,7 +77,7 @@ make' root siteName prefix nsfw _dataDir dir
let bgStyle = case bg of let bgStyle = case bg of
Default -> "" Default -> ""
NoBorder -> [b| NoBorder -> [b|@0
<style> <style>
#mainfig { #mainfig {
background: transparent; background: transparent;
@ -86,7 +86,7 @@ make' root siteName prefix nsfw _dataDir dir
} }
</style> </style>
|] |]
Other col -> [b| Other col -> [b|@0
<style> #mainfig { background: $col; } </style> <style> #mainfig { background: $col; } </style>
|] |]
@ -104,18 +104,18 @@ make' root siteName prefix nsfw _dataDir dir
let nsfwDialog = NsfwWarning.dialog nsfw' let nsfwDialog = NsfwWarning.dialog nsfw'
let imageMeta = case previewImage info of let imageMeta = case previewImage info of
Just (PFull (Image {path})) -> [b| Just (PFull (Image {path})) -> [b|@0
<meta property=og:image content="$url/$path"> <meta property=og:image content="$url/$path">
<meta name=twitter:card content=summary_large_image> <meta name=twitter:card content=summary_large_image>
<meta name=twitter:image content="$url/$path"> <meta name=twitter:image content="$url/$path">
|] |]
Just (PThumb path) -> [b| Just (PThumb path) -> [b|@0
<meta property=og:image content="$url/$path"> <meta property=og:image content="$url/$path">
<meta name=twitter:card content=summary> <meta name=twitter:card content=summary>
|] |]
Nothing -> throw $ NoThumb dir Nothing -> throw $ NoThumb dir
pure [b| pure [b|@0
<!DOCTYPE html> <!DOCTYPE html>
<html lang=en> <html lang=en>
<meta charset=utf-8> <meta charset=utf-8>
@ -136,7 +136,7 @@ make' root siteName prefix nsfw _dataDir dir
$nsfwScript $nsfwScript
$bgStyle $bgStyle
$prefetches $0.prefetches
<title>$title</title> <title>$title</title>
@ -153,7 +153,7 @@ make' root siteName prefix nsfw _dataDir dir
</h2> </h2>
</header> </header>
$buttonBar $2.buttonBar
<main> <main>
<figure id=mainfig> <figure id=mainfig>
@ -164,15 +164,15 @@ make' root siteName prefix nsfw _dataDir dir
</figure> </figure>
<div id=info> <div id=info>
$artistSection $6.artistSection
$descSection $6.descSection
$updatesList $6.updatesList
$linksList $6.linksList
$tagsList $6.tagsList
</div> </div>
</main> </main>
</div> </div>
@ -187,7 +187,7 @@ last' xs = if null xs then Nothing else Just $ last xs
makeArtist :: Maybe Artist -> Builder makeArtist :: Maybe Artist -> Builder
makeArtist Nothing = "" makeArtist Nothing = ""
makeArtist (Just (Artist {name, url})) = [b| makeArtist (Just (Artist {name, url})) = [b|@0
<section id=desc class=info-section> <section id=desc class=info-section>
<h2>by</h2> <h2>by</h2>
<div>$artistLink</div> <div>$artistLink</div>
@ -200,25 +200,25 @@ makeArtist (Just (Artist {name, url})) = [b|
makeDesc :: Desc -> Builder makeDesc :: Desc -> Builder
makeDesc NoDesc = "" makeDesc NoDesc = ""
makeDesc (TextDesc desc) = [b| makeDesc (TextDesc desc) = [b|@0
<section id=desc class=info-section> <section id=desc class=info-section>
<h2>about</h2> <h2>about</h2>
<div> <div>
$desc $4.desc
</div> </div>
</section> </section>
|] |]
makeDesc (LongDesc fs) = [b| makeDesc (LongDesc fs) = [b|@0
<section id=desc class=info-section> <section id=desc class=info-section>
$fields $2.fields
</section> </section>
|] |]
where where
fields = map makeField fs fields = map makeField fs
makeField (DescField {name, text}) = [b| makeField (DescField {name, text}) = [b|@0
<h2>$name</h2> <h2>$name</h2>
<div> <div>
$text $4.text
</div> </div>
|] |]
@ -262,25 +262,25 @@ makeButtonBar title images =
makeNav "cat" $ fmap (uncurry makeCat) cats makeNav "cat" $ fmap (uncurry makeCat) cats
where where
makeNav :: CanBuild b => Text -> b -> Builder makeNav :: CanBuild b => Text -> b -> Builder
makeNav cls inner = [b| makeNav cls inner = [b|@0
<nav id=alts class=$cls aria-label="alternate versions"> <nav id=alts class=$cls aria-label="alternate versions">
$inner $2.inner
$skipAll $2.skipAll
</nav> |] </nav> |]
makeCat lbl imgs = [b| makeCat lbl imgs = [b|@0
<section> <section>
<h3 class=alt-cat>$lbl</h3> <h3 class=alt-cat>$lbl</h3>
$alts $0.alts
</section> |] </section> |]
where alts = makeAlts imgs where alts = makeAlts imgs
makeAlts imgs = [b| makeAlts imgs = [b|@0
<ul class="buttonbar bb-choice"> <ul class="buttonbar bb-choice">
$elems $2.elems
</ul> |] </ul> |]
where elems = fmap (uncurry altButton) imgs where elems = fmap (uncurry altButton) imgs
skipAll = skipAll =
if any (isJust . (.warning) . fst) images then if any (isJust . (.warning) . fst) images then
[b| [b|@0
<div class=buttonbar id=skipAllDiv> <div class=buttonbar id=skipAllDiv>
<input type=checkbox name=skipAll id=skipAll> <input type=checkbox name=skipAll id=skipAll>
<label for=skipAll>skip warnings</label> <label for=skipAll>skip warnings</label>
@ -294,7 +294,7 @@ flatten =
fmap (\(t, is) -> fmap (\(i, _) -> i {label = t}) is) fmap (\(t, is) -> fmap (\(i, _) -> i {label = t}) is)
altButton :: Image -> Text -> Builder altButton :: Image -> Text -> Builder
altButton img i = [b| altButton img i = [b|@0
<li$nsfwClass> <li$nsfwClass>
<input type=radio name=variant id="$i" value="$path'" <input type=radio name=variant id="$i" value="$path'"
data-link="$link"$warning'> data-link="$link"$warning'>
@ -310,11 +310,11 @@ altButton img i = [b|
makeTags :: FilePath -> [Strict.Text] -> Builder makeTags :: FilePath -> [Strict.Text] -> Builder
makeTags undir tags = makeTags undir tags =
if null tags then "" else [b| if null tags then "" else [b|@0
<nav id=tags class=info-section> <nav id=tags class=info-section>
<h2>tags</h2> <h2>tags</h2>
<ul> <ul>
$tagList $4.tagList
</ul> </ul>
</nav> </nav>
|] |]
@ -325,18 +325,18 @@ makeTags undir tags =
extLinks :: [Link] -> Builder extLinks :: [Link] -> Builder
extLinks links = extLinks links =
if null links then "" else [b| if null links then "" else [b|@0
<nav id=links class=info-section> <nav id=links class=info-section>
<h2>links</h2> <h2>links</h2>
<ul> <ul>
$linkList $4.linkList
</ul> </ul>
</nav> </nav>
|] |]
where linkList = map extLink links where linkList = map extLink links
extLink :: Link -> Builder extLink :: Link -> Builder
extLink (Link {title, url}) = [b| extLink (Link {title, url}) = [b|@8
<li> <li>
<a href="$url"> <a href="$url">
$title $title
@ -345,18 +345,18 @@ extLink (Link {title, url}) = [b|
makeUpdates :: [(Date, NonEmpty Update)] -> Builder makeUpdates :: [(Date, NonEmpty Update)] -> Builder
makeUpdates ups = makeUpdates ups =
if all (null . snd) ups then "" else [b| if all (null . snd) ups then "" else [b|@4
<section id=updates class=info-section> <section id=updates class=info-section>
<h2>updates</h2> <h2>updates</h2>
<dl> <dl>
$updateList $8.updateList
</dl> </dl>
</section> </section>
|] |]
where updateList = fmap (uncurry makeUpdate) ups where updateList = fmap (uncurry makeUpdate) ups
makeUpdate :: Date -> NonEmpty Update -> Builder makeUpdate :: Date -> NonEmpty Update -> Builder
makeUpdate date ups = [b| makeUpdate date ups = [b|@8
<dt>$date' <dt>$date'
<dd>$desc <dd>$desc
|] where |] where