diff --git a/make-pages/GalleryPage.hs b/make-pages/GalleryPage.hs index 1839c6a..9a8b6af 100644 --- a/make-pages/GalleryPage.hs +++ b/make-pages/GalleryPage.hs @@ -131,22 +131,27 @@ makeYearItems nsfw year infos = [b|@4 year' = show year & foldMap \c -> [b|$c|] makeItem :: Bool -> FilePath -> Info -> Builder -makeItem nsfw file info@(Info {title, bg, date}) = [b|@4 -
  • +makeItem nsfw file info@(Info {title, bg}) = [b|@4 +
  • -
    $title
    +
    + $date' + $title +
    |] where - dir = takeDirectory file - thumb = getThumb dir info - nsfw' = if nsfw && #anyNsfw info then [b| nsfw|] else "" - tags' = fold $ intersperse ";" $ map fromText $ tagsFor nsfw info - date' = formatDateShort date - bgStyle = ifJust bg \col -> [b| style="background: $col"|] + dir = takeDirectory file + thumb = getThumb dir info + nsfw' = if nsfw && #anyNsfw info then [b| nsfw|] else "" + tags' = fold $ intersperse ";" $ map fromText $ tagsFor nsfw info + date' = formatDateShort $ #latestDate info + updated' = if #updated info then [b|true|] else [b|false|] + bgStyle = ifJust bg \col -> [b| style="background: $col"|] formatDateShort :: Time.Day -> Builder formatDateShort date = [b|$day $month|] where diff --git a/make-pages/Info.hs b/make-pages/Info.hs index 66ac8da..59349ae 100644 --- a/make-pages/Info.hs +++ b/make-pages/Info.hs @@ -19,6 +19,7 @@ import Data.Foldable (find) import Data.Hashable (Hashable) import Data.HashSet (HashSet) import qualified Data.HashSet as HashSet +import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe (isJust, isNothing) 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 -- put them in the right order in the gallery sortEx :: !Text, + updates :: !(Map Day Text), title :: !Text, artist :: !(Maybe Artist), -- nothing = me, obv 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 "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 nsfw (Info {desc, nsfwDesc}) = desc <> (guard nsfw *> nsfwDesc) @@ -122,7 +129,7 @@ linksFor :: Bool -> Info -> [Link] linksFor nsfw = if nsfw then #links else #sfwLinks 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 @@ -150,7 +157,8 @@ addSuffix suf path = instance FromYAML Info where parseYAML = YAML.withMap "info" \m -> Info <$> m .: "date" - <*> m .:? "sort" .!= "" + <*> m .:? "sort" .!= "" + <*> m .:? "updates" .!= [] <*> m .: "title" <*> m .:? "artist" <*> m .:? "nsfw-only" .!= False diff --git a/make-pages/SinglePage.hs b/make-pages/SinglePage.hs index 8b4302e..48cda1c 100644 --- a/make-pages/SinglePage.hs +++ b/make-pages/SinglePage.hs @@ -5,10 +5,11 @@ import BuilderQQ import Records () import Control.Exception +import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe) import qualified Data.Text as Strict 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 qualified System.Process as Proc import Text.Read (readMaybe) @@ -34,7 +35,8 @@ 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' 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 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 tagsList = makeTags undir $ tagsFor nsfw info let linksList = extLinks $ linksFor nsfw info + let updatesList = makeUpdates $ Map.toList updates let makePrefetch (Image {path}) = [b||] 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" let thumb = getThumb "" info + let updateDate = ifJust (Map.lookupMax updates) \(formatDate -> u, _) -> + [b|
    updated $u|] + pure [b|@0 @@ -103,7 +109,9 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do

    $title

    $artistTag -

    $formattedDate

    +

    + $formattedDate $updateDate +

    $buttonBar @@ -122,6 +130,8 @@ make' root prefix nsfw dataDir dir info@(Info {date, title, artist, bg}) = do $tagsList $linksList + + $updatesList @@ -217,6 +227,25 @@ extLink (Link {title, url}) = [b|@8 |] +makeUpdates :: [(Day, Text)] -> Builder +makeUpdates ups = + if null ups then "" else [b|@4 +
    +

    updates

    +
    + $8.updateList +
    +
    + |] + where updateList = map (uncurry makeUpdate) ups + +makeUpdate :: Day -> Text -> Builder +makeUpdate date txt = [b|@8 +
    $date' +
    $txt + |] + where date' = Time.formatTime Time.defaultTimeLocale "%-d/%-m/%Y" date + formatDate :: Day -> Builder formatDate date = [b|$week $day $month $year|] where (year, month', day') = Time.toGregorian date diff --git a/style/cake.svg b/style/cake.svg new file mode 100644 index 0000000..6900dc1 --- /dev/null +++ b/style/cake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/style/shiny/gallery.css b/style/shiny/gallery.css index 659d3fd..aa27625 100644 --- a/style/shiny/gallery.css +++ b/style/shiny/gallery.css @@ -116,17 +116,12 @@ body { box-shadow: var(--focus-box); } -.item[data-date]::before { - content: attr(data-date); -} - - figure { margin: 0; padding: 0; } -figcaption, .item::before { +figcaption .date, figcaption .title { position: absolute; width: 100%; border: 1px solid var(--text-col); @@ -134,10 +129,11 @@ figcaption, .item::before { text-align: center; background: hsl(0, 0%, 0%, 75%); font-size: 80%; + text-shadow: none; } -figcaption { bottom: -1px; left: -1px; } -.item::before { top: -1px; left: -1px; } +figcaption .date { top: -1px; left: -1px; } +figcaption .title { bottom: -1px; left: -1px; } .year-marker { grid-area: auto / 1; @@ -164,19 +160,31 @@ figcaption { bottom: -1px; left: -1px; } transform: scaleX(110%); } -.item.nsfw::after { - --size: calc(1/4 * var(--image-size)); - content: url(../18_plus_white.svg); +.item.nsfw::before, .item[data-updated="true"]::after { height: var(--size); width: var(--size); display: inline-block; 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); right: 3px; - - transform: rotate(var(--nsfw-sticker-rotate)); 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 { @@ -187,30 +195,33 @@ footer { @media (hover) { - .item:hover figcaption, .item:hover::before { + .item:hover .date, .item:hover .title, + .item:hover::before, .item:hover::after { filter: opacity(20%); } - @media (prefers-reduced-motion) { - .item:hover figcaption { - transform: translateY(80%); - } - } - @media (prefers-reduced-motion: no-preference) { - figcaption, .item::before { + figcaption .date, figcaption .title, .item::before, .item::after { transition-property: filter, transform; - transition-duration: 0.25s; + transition-duration: 0.15s; transition-timing-function: ease-in-out; } - .item:hover figcaption { + .item:hover .title { transform: translate(-20%, 80%) rotateZ(7deg); } - .item:hover::before { + .item:hover .date { 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; } - figcaption { + figcaption .date, figcaption .title { position: initial; } + figcaption .date::after { + content: ':'; + } + .item a { display: block; height: var(--image-size); diff --git a/style/shiny/single.css b/style/shiny/single.css index 55a4530..59b3f95 100644 --- a/style/shiny/single.css +++ b/style/shiny/single.css @@ -132,6 +132,28 @@ body { 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 { text-align: center; margin-top: 1em; diff --git a/style/sparkles.svg b/style/sparkles.svg new file mode 100644 index 0000000..030419b --- /dev/null +++ b/style/sparkles.svg @@ -0,0 +1 @@ + \ No newline at end of file