add support for structured descriptions
This commit is contained in:
parent
519a50489f
commit
5c3ca348c2
3 changed files with 76 additions and 13 deletions
|
@ -2,7 +2,7 @@
|
||||||
module Info
|
module Info
|
||||||
(Info (..),
|
(Info (..),
|
||||||
tagsFor, descFor, imagesFor, linksFor, updatesFor, compareFor, sortFor,
|
tagsFor, descFor, imagesFor, linksFor, updatesFor, compareFor, sortFor,
|
||||||
Artist (..), Image (..), Link (..), Update (..),
|
Artist (..), Image (..), Desc (..), DescField (..), Link (..), Update (..),
|
||||||
GalleryInfo (..), GalleryFilters (..), ArtistFilter (..), NsfwFilter (..),
|
GalleryInfo (..), GalleryFilters (..), ArtistFilter (..), NsfwFilter (..),
|
||||||
IndexInfo (..),
|
IndexInfo (..),
|
||||||
readArtistFilter, matchArtist, readNsfwFilter, matchNsfw, matchFilters,
|
readArtistFilter, matchArtist, readNsfwFilter, matchNsfw, matchFilters,
|
||||||
|
@ -15,14 +15,13 @@ import Date
|
||||||
import Records
|
import Records
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Monad
|
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
import Data.Foldable (find)
|
import Data.Foldable (find)
|
||||||
import Data.Hashable (Hashable)
|
import Data.Hashable (Hashable)
|
||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
import qualified Data.HashSet as HashSet
|
import qualified Data.HashSet as HashSet
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Maybe (isJust, isNothing)
|
import Data.Maybe (isJust, isNothing, fromMaybe)
|
||||||
import Data.List (nub, sortBy)
|
import Data.List (nub, sortBy)
|
||||||
import Data.Ord (comparing)
|
import Data.Ord (comparing)
|
||||||
import Data.String (IsString)
|
import Data.String (IsString)
|
||||||
|
@ -48,8 +47,8 @@ data Info =
|
||||||
nsfwOnly :: !Bool,
|
nsfwOnly :: !Bool,
|
||||||
tags :: ![Text],
|
tags :: ![Text],
|
||||||
nsfwTags :: ![Text],
|
nsfwTags :: ![Text],
|
||||||
desc :: !(Maybe Text),
|
desc :: !Desc,
|
||||||
nsfwDesc :: !(Maybe Text),
|
nsfwDesc :: !Desc,
|
||||||
bg :: !(Maybe Text),
|
bg :: !(Maybe Text),
|
||||||
images :: ![Image],
|
images :: ![Image],
|
||||||
thumb' :: !(Maybe FilePath),
|
thumb' :: !(Maybe FilePath),
|
||||||
|
@ -58,6 +57,15 @@ data Info =
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data Desc =
|
||||||
|
NoDesc
|
||||||
|
| TextDesc !Text
|
||||||
|
| LongDesc ![DescField]
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data DescField = DescField {name, text :: !Text}
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
data Artist =
|
data Artist =
|
||||||
Artist {
|
Artist {
|
||||||
name :: !Text,
|
name :: !Text,
|
||||||
|
@ -132,8 +140,26 @@ instance HasField "updated" Info (Bool -> Bool) where
|
||||||
getField (Info {updates, showUpdated}) nsfw = showUpdated && updated
|
getField (Info {updates, showUpdated}) nsfw = showUpdated && updated
|
||||||
where updated = if nsfw then not $ null updates else any #sfw updates
|
where updated = if nsfw then not $ null updates else any #sfw updates
|
||||||
|
|
||||||
descFor :: Bool -> Info -> Maybe Text
|
defDescKey :: Text
|
||||||
descFor nsfw (Info {desc, nsfwDesc}) = desc <> (guard nsfw *> nsfwDesc)
|
defDescKey = "about"
|
||||||
|
|
||||||
|
instance Semigroup Desc where
|
||||||
|
NoDesc <> d2 = d2
|
||||||
|
d1 <> NoDesc = d1
|
||||||
|
(TextDesc t1) <> (TextDesc t2) = TextDesc $ t1 <> t2
|
||||||
|
(LongDesc m1) <> (TextDesc t2) = LongDesc $ m1 <> [DescField defDescKey t2]
|
||||||
|
(TextDesc t1) <> (LongDesc m2) = LongDesc $ [DescField defDescKey t1] <> m2
|
||||||
|
(LongDesc m1) <> (LongDesc m2) = LongDesc $ m1 <> m2
|
||||||
|
|
||||||
|
instance Monoid Desc where
|
||||||
|
mempty = NoDesc
|
||||||
|
mappend = (<>)
|
||||||
|
|
||||||
|
instance HasField "exists" Desc Bool where
|
||||||
|
getField d = d /= NoDesc
|
||||||
|
|
||||||
|
descFor :: Bool -> Info -> Desc
|
||||||
|
descFor nsfw (Info {desc, nsfwDesc}) = if nsfw then desc <> nsfwDesc else desc
|
||||||
|
|
||||||
tagsFor :: Bool -> Info -> [Text]
|
tagsFor :: Bool -> Info -> [Text]
|
||||||
tagsFor nsfw i = if nsfw then nub (#tags i <> #nsfwTags i) else #tags i
|
tagsFor nsfw i = if nsfw then nub (#tags i <> #nsfwTags i) else #tags i
|
||||||
|
@ -187,8 +213,8 @@ instance FromYAML Info where
|
||||||
<*> m .:? "nsfw-only" .!= False
|
<*> m .:? "nsfw-only" .!= False
|
||||||
<*> m .:? "tags" .!= []
|
<*> m .:? "tags" .!= []
|
||||||
<*> m .:? "nsfw-tags" .!= []
|
<*> m .:? "nsfw-tags" .!= []
|
||||||
<*> m .:? "desc"
|
<*> m .:? "desc" .!= NoDesc
|
||||||
<*> m .:? "nsfw-desc"
|
<*> m .:? "nsfw-desc" .!= NoDesc
|
||||||
<*> m .:? "bg"
|
<*> m .:? "bg"
|
||||||
<*> (m .: "images" >>= imageList)
|
<*> (m .: "images" >>= imageList)
|
||||||
<*> m .:? "thumb"
|
<*> m .:? "thumb"
|
||||||
|
@ -201,6 +227,13 @@ instance FromYAML Artist where
|
||||||
withUrl = YAML.withMap "full info" \m ->
|
withUrl = YAML.withMap "full info" \m ->
|
||||||
Artist <$> m .: "name" <*> m .:? "url"
|
Artist <$> m .: "name" <*> m .:? "url"
|
||||||
|
|
||||||
|
instance FromYAML Desc where
|
||||||
|
parseYAML y = textDesc y <|> mapDesc y where
|
||||||
|
textDesc = YAML.withStr "text" $ pure . TextDesc
|
||||||
|
mapDesc = fmap LongDesc . parseYAML
|
||||||
|
|
||||||
|
instance FromYAML DescField where parseYAML = withPair DescField
|
||||||
|
|
||||||
imageList :: YAML.Node YAML.Pos -> YAML.Parser [Image]
|
imageList :: YAML.Node YAML.Pos -> YAML.Parser [Image]
|
||||||
imageList y = pure <$> unlabelledImage y <|> parseYAML y
|
imageList y = pure <$> unlabelledImage y <|> parseYAML y
|
||||||
|
|
||||||
|
@ -366,6 +399,11 @@ instance (FromYAML a, FromYAML b) => FromYAML (Pair a b) where
|
||||||
[(a, b)] -> Pair <$> parseYAML a <*> parseYAML b
|
[(a, b)] -> Pair <$> parseYAML a <*> parseYAML b
|
||||||
_ -> fail "expected exactly one pair"
|
_ -> fail "expected exactly one pair"
|
||||||
|
|
||||||
|
withPair :: (FromYAML a, FromYAML b)
|
||||||
|
=> (a -> b -> c)
|
||||||
|
-> (YAML.Node YAML.Pos -> YAML.Parser c)
|
||||||
|
withPair f = withPairM \a b -> pure $ f a b
|
||||||
|
|
||||||
|
|
||||||
instance {-# OVERLAPPING #-} FromYAML String where
|
instance {-# OVERLAPPING #-} FromYAML String where
|
||||||
parseYAML y = Text.unpack <$> parseYAML y
|
parseYAML y = Text.unpack <$> parseYAML y
|
||||||
|
|
|
@ -62,8 +62,8 @@ makeItem root prefix nsfw path i@(Info {title, date, artist}) = [b|@4
|
||||||
Artist {name, url = Nothing} -> [b|<p>by $name|]
|
Artist {name, url = Nothing} -> [b|<p>by $name|]
|
||||||
Artist {name, url = Just url} -> [b|<p>by <a href=$url>$name</a>|]
|
Artist {name, url = Just url} -> [b|<p>by <a href=$url>$name</a>|]
|
||||||
desc = descFor nsfw i
|
desc = descFor nsfw i
|
||||||
desc' = ifJust desc \d -> [b|$10.d|]
|
desc' = makeDesc desc
|
||||||
descArtist' = if isJust desc || isJust artist then [b|@6
|
descArtist' = if #exists desc || isJust artist then [b|@6
|
||||||
<description>
|
<description>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
$10.desc'
|
$10.desc'
|
||||||
|
@ -73,3 +73,11 @@ makeItem root prefix nsfw path i@(Info {title, date, artist}) = [b|@4
|
||||||
|]
|
|]
|
||||||
else ""
|
else ""
|
||||||
date' = formatRSS date
|
date' = formatRSS date
|
||||||
|
|
||||||
|
makeDesc :: Desc -> Builder
|
||||||
|
makeDesc NoDesc = ""
|
||||||
|
makeDesc (TextDesc txt) = [b|$txt|]
|
||||||
|
makeDesc (LongDesc fs) = [b|$fields|]
|
||||||
|
where
|
||||||
|
fields = map makeField fs
|
||||||
|
makeField (DescField {name, text}) = [b|<b>$name</b>: $text|]
|
||||||
|
|
|
@ -166,8 +166,9 @@ makeArtist (Artist {name, url}) =
|
||||||
Just u -> [b|<a href="$u">$name</a>|]
|
Just u -> [b|<a href="$u">$name</a>|]
|
||||||
Nothing -> [b|$name|]
|
Nothing -> [b|$name|]
|
||||||
|
|
||||||
makeDesc :: Maybe Strict.Text -> Builder
|
makeDesc :: Desc -> Builder
|
||||||
makeDesc mdesc = ifJust mdesc \desc -> [b|@0
|
makeDesc NoDesc = ""
|
||||||
|
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>
|
||||||
|
@ -175,6 +176,22 @@ makeDesc mdesc = ifJust mdesc \desc -> [b|@0
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|]
|
|]
|
||||||
|
makeDesc (LongDesc fs) = [b|@0
|
||||||
|
<section id=desc class=info-section>
|
||||||
|
<h2>about</h2>
|
||||||
|
<div>
|
||||||
|
$4.fields
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|]
|
||||||
|
where
|
||||||
|
fields = map makeField fs
|
||||||
|
makeField (DescField {name, text}) = [b|@0
|
||||||
|
<h2>$name</h2>
|
||||||
|
<div>
|
||||||
|
$4.text
|
||||||
|
</div>
|
||||||
|
|]
|
||||||
|
|
||||||
makeButtonBar :: Strict.Text -> [(Image, Size)] -> Builder
|
makeButtonBar :: Strict.Text -> [(Image, Size)] -> Builder
|
||||||
makeButtonBar title images =
|
makeButtonBar title images =
|
||||||
|
|
Loading…
Reference in a new issue