support updates
This commit is contained in:
parent
e296e41b8b
commit
7f91331195
7 changed files with 120 additions and 39 deletions
|
@ -131,22 +131,27 @@ makeYearItems nsfw year infos = [b|@4
|
||||||
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 {title, bg, date}) = [b|@4
|
makeItem nsfw file info@(Info {title, bg}) = [b|@4
|
||||||
<li class="item post$nsfw'" data-tags="$tags'" data-date="$date'">
|
<li class="item post$nsfw'" data-date="$date'" data-updated="$updated'"
|
||||||
|
data-tags="$tags'">
|
||||||
<figure>
|
<figure>
|
||||||
<a href="$dir">
|
<a href="$dir">
|
||||||
<img src="$thumb"$bgStyle>
|
<img src="$thumb"$bgStyle>
|
||||||
</a>
|
</a>
|
||||||
<figcaption>$title</figcaption>
|
<figcaption>
|
||||||
|
<span class=date>$date'</span>
|
||||||
|
<span class=title>$title</span>
|
||||||
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|]
|
|]
|
||||||
where
|
where
|
||||||
dir = takeDirectory file
|
dir = takeDirectory file
|
||||||
thumb = getThumb dir info
|
thumb = getThumb dir info
|
||||||
nsfw' = if nsfw && #anyNsfw info then [b| nsfw|] else ""
|
nsfw' = if nsfw && #anyNsfw info then [b| nsfw|] else ""
|
||||||
tags' = fold $ intersperse ";" $ map fromText $ tagsFor nsfw info
|
tags' = fold $ intersperse ";" $ map fromText $ tagsFor nsfw info
|
||||||
date' = formatDateShort date
|
date' = formatDateShort $ #latestDate info
|
||||||
bgStyle = ifJust bg \col -> [b| style="background: $col"|]
|
updated' = if #updated info then [b|true|] else [b|false|]
|
||||||
|
bgStyle = ifJust bg \col -> [b| style="background: $col"|]
|
||||||
|
|
||||||
formatDateShort :: Time.Day -> Builder
|
formatDateShort :: Time.Day -> Builder
|
||||||
formatDateShort date = [b|$day $month|] where
|
formatDateShort date = [b|$day $month|] where
|
||||||
|
|
|
@ -19,6 +19,7 @@ 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 Data.Map.Strict (Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Maybe (isJust, isNothing)
|
import Data.Maybe (isJust, isNothing)
|
||||||
import Data.List (nub)
|
import Data.List (nub)
|
||||||
|
@ -40,6 +41,7 @@ data Info =
|
||||||
-- e.g. multiple things on the same day might have a,b,c in @sortEx@ to
|
-- e.g. multiple things on the same day might have a,b,c in @sortEx@ to
|
||||||
-- put them in the right order in the gallery
|
-- put them in the right order in the gallery
|
||||||
sortEx :: !Text,
|
sortEx :: !Text,
|
||||||
|
updates :: !(Map Day Text),
|
||||||
title :: !Text,
|
title :: !Text,
|
||||||
artist :: !(Maybe Artist), -- nothing = me, obv
|
artist :: !(Maybe Artist), -- nothing = me, obv
|
||||||
nsfwOnly :: !Bool,
|
nsfwOnly :: !Bool,
|
||||||
|
@ -109,6 +111,11 @@ instance HasField "year" Info Integer where getField = #first . #dmy
|
||||||
instance HasField "month" Info Int where getField = #second . #dmy
|
instance HasField "month" Info Int where getField = #second . #dmy
|
||||||
instance HasField "day" Info Int where getField = #third . #dmy
|
instance HasField "day" Info Int where getField = #third . #dmy
|
||||||
|
|
||||||
|
instance HasField "latestDate" Info Day where
|
||||||
|
getField (Info {date, updates}) = maximum (date : Map.keys updates)
|
||||||
|
|
||||||
|
instance HasField "updated" Info Bool where getField = not . Map.null . #updates
|
||||||
|
|
||||||
descFor :: Bool -> Info -> Maybe Text
|
descFor :: Bool -> Info -> Maybe Text
|
||||||
descFor nsfw (Info {desc, nsfwDesc}) = desc <> (guard nsfw *> nsfwDesc)
|
descFor nsfw (Info {desc, nsfwDesc}) = desc <> (guard nsfw *> nsfwDesc)
|
||||||
|
|
||||||
|
@ -122,7 +129,7 @@ linksFor :: Bool -> Info -> [Link]
|
||||||
linksFor nsfw = if nsfw then #links else #sfwLinks
|
linksFor nsfw = if nsfw then #links else #sfwLinks
|
||||||
|
|
||||||
instance Ord Info where
|
instance Ord Info where
|
||||||
compare = comparing \Info {date, sortEx, title} -> (date, sortEx, title)
|
compare = comparing \i -> (#latestDate i, #sortEx i, #title i)
|
||||||
|
|
||||||
|
|
||||||
newtype NoThumb = NoThumb FilePath
|
newtype NoThumb = NoThumb FilePath
|
||||||
|
@ -150,7 +157,8 @@ addSuffix suf path =
|
||||||
instance FromYAML Info where
|
instance FromYAML Info where
|
||||||
parseYAML = YAML.withMap "info" \m ->
|
parseYAML = YAML.withMap "info" \m ->
|
||||||
Info <$> m .: "date"
|
Info <$> m .: "date"
|
||||||
<*> m .:? "sort" .!= ""
|
<*> m .:? "sort" .!= ""
|
||||||
|
<*> m .:? "updates" .!= []
|
||||||
<*> m .: "title"
|
<*> m .: "title"
|
||||||
<*> m .:? "artist"
|
<*> m .:? "artist"
|
||||||
<*> m .:? "nsfw-only" .!= False
|
<*> m .:? "nsfw-only" .!= False
|
||||||
|
|
|
@ -5,10 +5,11 @@ import BuilderQQ
|
||||||
import Records ()
|
import Records ()
|
||||||
|
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
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 qualified Data.Time.Calendar as Time
|
import qualified Data.Time as Time
|
||||||
import System.FilePath (joinPath, splitPath, (</>))
|
import System.FilePath (joinPath, splitPath, (</>))
|
||||||
import qualified System.Process as Proc
|
import qualified System.Process as Proc
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
|
@ -34,7 +35,8 @@ make root prefix nsfw dataDir dir info =
|
||||||
toLazyText <$> make' root prefix nsfw dataDir dir info
|
toLazyText <$> make' root prefix nsfw dataDir dir info
|
||||||
|
|
||||||
make' :: Text -> FilePath -> Bool -> FilePath -> FilePath -> Info -> IO Builder
|
make' :: Text -> FilePath -> Bool -> FilePath -> FilePath -> Info -> IO Builder
|
||||||
make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do
|
make' root prefix nsfw dataDir dir
|
||||||
|
info@(Info {date, title, artist, bg, updates}) = do
|
||||||
images <- withSizes (dataDir </> dir) $ imagesFor nsfw info
|
images <- withSizes (dataDir </> dir) $ imagesFor nsfw info
|
||||||
|
|
||||||
let undir = joinPath (replicate (length (splitPath dir)) "..")
|
let undir = joinPath (replicate (length (splitPath dir)) "..")
|
||||||
|
@ -53,6 +55,7 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do
|
||||||
let descSection = makeDesc $ descFor nsfw info
|
let descSection = makeDesc $ descFor nsfw info
|
||||||
let tagsList = makeTags undir $ tagsFor nsfw info
|
let tagsList = makeTags undir $ tagsFor nsfw info
|
||||||
let linksList = extLinks $ linksFor nsfw info
|
let linksList = extLinks $ linksFor nsfw info
|
||||||
|
let updatesList = makeUpdates $ Map.toList updates
|
||||||
|
|
||||||
let makePrefetch (Image {path}) = [b|<link rel=prefetch href=$path>|]
|
let makePrefetch (Image {path}) = [b|<link rel=prefetch href=$path>|]
|
||||||
let prefetches = map (makePrefetch . #first) $ tail images
|
let prefetches = map (makePrefetch . #first) $ tail images
|
||||||
|
@ -76,6 +79,9 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do
|
||||||
Nothing -> "by niss"
|
Nothing -> "by niss"
|
||||||
let thumb = getThumb "" info
|
let thumb = getThumb "" info
|
||||||
|
|
||||||
|
let updateDate = ifJust (Map.lookupMax updates) \(formatDate -> u, _) ->
|
||||||
|
[b|<br> <span class=updated>updated $u</span>|]
|
||||||
|
|
||||||
pure [b|@0
|
pure [b|@0
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang=en>
|
<html lang=en>
|
||||||
|
@ -103,7 +109,9 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do
|
||||||
<header>
|
<header>
|
||||||
<h1>$title</h1>
|
<h1>$title</h1>
|
||||||
$artistTag
|
$artistTag
|
||||||
<h2 id=date class="right corner">$formattedDate</h2>
|
<h2 id=date class="right corner">
|
||||||
|
$formattedDate $updateDate
|
||||||
|
</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
$buttonBar
|
$buttonBar
|
||||||
|
@ -122,6 +130,8 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do
|
||||||
$tagsList
|
$tagsList
|
||||||
|
|
||||||
$linksList
|
$linksList
|
||||||
|
|
||||||
|
$updatesList
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -217,6 +227,25 @@ extLink (Link {title, url}) = [b|@8
|
||||||
</a>
|
</a>
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
makeUpdates :: [(Day, Text)] -> Builder
|
||||||
|
makeUpdates ups =
|
||||||
|
if null ups then "" else [b|@4
|
||||||
|
<section id=updates class=info-section>
|
||||||
|
<h2>updates</h2>
|
||||||
|
<dl>
|
||||||
|
$8.updateList
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
|]
|
||||||
|
where updateList = map (uncurry makeUpdate) ups
|
||||||
|
|
||||||
|
makeUpdate :: Day -> Text -> Builder
|
||||||
|
makeUpdate date txt = [b|@8
|
||||||
|
<dt>$date'
|
||||||
|
<dd>$txt
|
||||||
|
|]
|
||||||
|
where date' = Time.formatTime Time.defaultTimeLocale "%-d/%-m/%Y" date
|
||||||
|
|
||||||
formatDate :: Day -> Builder
|
formatDate :: Day -> Builder
|
||||||
formatDate date = [b|$week $day $month $year|] where
|
formatDate date = [b|$week $day $month $year|] where
|
||||||
(year, month', day') = Time.toGregorian date
|
(year, month', day') = Time.toGregorian date
|
||||||
|
|
1
style/cake.svg
Normal file
1
style/cake.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><metadata/><path d="m0 0h32v32h-32z" fill="none"/><path d="m15.086 6.532c.129-.53.401-1.019.793-1.411l1-1c.562-.562 1.325-.878 2.121-.878s1.559.316 2.121.878c.251.251.507.507.758.758.268.268.48.581.628.922 2.498.742 4.839 1.987 6.87 3.68.384.32.623.519.623.519v13l-28 7v-13z" fill="none" stroke="#000" stroke-width="4"/><path d="m2 19v-2l2-1 23-7 3 1v13l-2 .5z" fill="#ccc"/><path d="m28 18.5v5l-26 6.5v-5l1-1 24-6zm-26 4.5v-4l24.757-6.189c.299-.075.616-.008.858.182.243.189.385.48.385.788v2.719l-1 1.5-24 5.5-1-.5z" fill="#eaae53"/><path d="m28 18.5-26 6.5v-2l26-6.5z" fill="#da6363"/><path d="m2 17 15-12c4.523 0 8.903 1.586 12.377 4.481.384.32.623.519.623.519l-28 7z" fill="#fff"/><path d="m16 11c-.265 0-.52-.105-.707-.293-.188-.187-.293-.442-.293-.707v-2.757c0-.796.316-1.559.879-2.122l1-1c.562-.562 1.325-.878 2.121-.878s1.559.316 2.121.878c.251.251.507.507.758.758.562.562.878 1.325.878 2.121s-.316 1.559-.878 2.121c-.353.353-.702.702-1 1-.563.563-1.326.879-2.122.879-.85 0-1.964 0-2.757 0z" fill="#d72d35"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -116,17 +116,12 @@ body {
|
||||||
box-shadow: var(--focus-box);
|
box-shadow: var(--focus-box);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item[data-date]::before {
|
|
||||||
content: attr(data-date);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
figure {
|
figure {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
figcaption, .item::before {
|
figcaption .date, figcaption .title {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid var(--text-col);
|
border: 1px solid var(--text-col);
|
||||||
|
@ -134,10 +129,11 @@ figcaption, .item::before {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: hsl(0, 0%, 0%, 75%);
|
background: hsl(0, 0%, 0%, 75%);
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
figcaption { bottom: -1px; left: -1px; }
|
figcaption .date { top: -1px; left: -1px; }
|
||||||
.item::before { top: -1px; left: -1px; }
|
figcaption .title { bottom: -1px; left: -1px; }
|
||||||
|
|
||||||
.year-marker {
|
.year-marker {
|
||||||
grid-area: auto / 1;
|
grid-area: auto / 1;
|
||||||
|
@ -164,19 +160,31 @@ figcaption { bottom: -1px; left: -1px; }
|
||||||
transform: scaleX(110%);
|
transform: scaleX(110%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item.nsfw::after {
|
.item.nsfw::before, .item[data-updated="true"]::after {
|
||||||
--size: calc(1/4 * var(--image-size));
|
|
||||||
content: url(../18_plus_white.svg);
|
|
||||||
height: var(--size);
|
height: var(--size);
|
||||||
width: var(--size);
|
width: var(--size);
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.nsfw::before {
|
||||||
|
--size: calc(1/4 * var(--image-size));
|
||||||
|
--base-transform: rotate(var(--nsfw-sticker-rotate));
|
||||||
|
content: url(../18_plus_white.svg);
|
||||||
top: calc(1em + 3px);
|
top: calc(1em + 3px);
|
||||||
right: 3px;
|
right: 3px;
|
||||||
|
|
||||||
transform: rotate(var(--nsfw-sticker-rotate));
|
|
||||||
mix-blend-mode: multiply;
|
mix-blend-mode: multiply;
|
||||||
|
transform: var(--base-transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item[data-updated="true"]::after {
|
||||||
|
--size: calc(1/4 * var(--image-size));
|
||||||
|
content: url(../sparkles.svg);
|
||||||
|
bottom: calc(1em + 3px);
|
||||||
|
right: 3px;
|
||||||
|
mix-blend-mode: overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
|
@ -187,30 +195,33 @@ footer {
|
||||||
|
|
||||||
|
|
||||||
@media (hover) {
|
@media (hover) {
|
||||||
.item:hover figcaption, .item:hover::before {
|
.item:hover .date, .item:hover .title,
|
||||||
|
.item:hover::before, .item:hover::after {
|
||||||
filter: opacity(20%);
|
filter: opacity(20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion) {
|
|
||||||
.item:hover figcaption {
|
|
||||||
transform: translateY(80%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
figcaption, .item::before {
|
figcaption .date, figcaption .title, .item::before, .item::after {
|
||||||
transition-property: filter, transform;
|
transition-property: filter, transform;
|
||||||
transition-duration: 0.25s;
|
transition-duration: 0.15s;
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:hover figcaption {
|
.item:hover .title {
|
||||||
transform: translate(-20%, 80%) rotateZ(7deg);
|
transform: translate(-20%, 80%) rotateZ(7deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:hover::before {
|
.item:hover .date {
|
||||||
transform: translate(20%, -80%) rotateZ(7deg);
|
transform: translate(20%, -80%) rotateZ(7deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item:hover::before {
|
||||||
|
transform: translate(1.5em, -1.5em) var(--base-transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item:hover::after {
|
||||||
|
transform: translate(1.5em, 1.5em);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,10 +230,14 @@ footer {
|
||||||
height: min-content;
|
height: min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
figcaption {
|
figcaption .date, figcaption .title {
|
||||||
position: initial;
|
position: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
figcaption .date::after {
|
||||||
|
content: ':';
|
||||||
|
}
|
||||||
|
|
||||||
.item a {
|
.item a {
|
||||||
display: block;
|
display: block;
|
||||||
height: var(--image-size);
|
height: var(--image-size);
|
||||||
|
|
|
@ -132,6 +132,28 @@ body {
|
||||||
margin: 0.35em;
|
margin: 0.35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#updates dl {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content auto;
|
||||||
|
grid-gap: 0.5em;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#updates dt {
|
||||||
|
font-size: 80%;
|
||||||
|
font-weight: 700;
|
||||||
|
grid-area: auto / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#updates dd {
|
||||||
|
grid-area: auto / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.updated {
|
||||||
|
font-size: 90%;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
|
|
1
style/sparkles.svg
Normal file
1
style/sparkles.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><metadata/><g fill="none"><path d="m0 0h32v32h-32z"/><path d="m14 15 5.5-2.5 2.5-8.5 2.5 8.5 5.5 2.5-5.5 2.5-2.5 8.5-2.5-8.5z" stroke="#000" stroke-width="4"/><path d="m4 23 3.5-1.5 1.5-5.5 1.5 5.5 3.5 1.5-3.5 1.5-1.5 5.5-1.5-5.5z" stroke="#000" stroke-width="4"/><path d="m2 7 2-1 1-4 1 4 2 1-2 1-1 4-1-4z" stroke="#000" stroke-width="4"/></g><path d="m14 15 5.5-2.5 2.5-8.5 2.5 8.5 5.5 2.5-5.5 2.5-2.5 8.5-2.5-8.5z" fill="#fdef24"/><path d="m4 23 3.5-1.5 1.5-5.5 1.5 5.5 3.5 1.5-3.5 1.5-1.5 5.5-1.5-5.5z" fill="#fdef24"/><path d="m2 7 2-1 1-4 1 4 2 1-2 1-1 4-1-4z" fill="#fdef24"/></svg>
|
After Width: | Height: | Size: 760 B |
Loading…
Reference in a new issue