diff --git a/Makefile b/Makefile index b27b287..0572da0 100644 --- a/Makefile +++ b/Makefile @@ -16,18 +16,11 @@ MAKEPAGES := $(TMPDIR)/make-pages YAMLS != find -L $(DATADIR) -name $(INFONAME) -TSCRIPTS != find script -name '*.ts' -STYLES != find style -name '*.css' -STYLESVGS != find style -name '*.svg' -STYLEPNGS != find style -name '*.png' +TSCRIPTS != find script -name '*.ts' +STYLES != find style -type f +FONTS != find fonts -type f - -FONTS != find fonts \ - -iname '*.eot' -or -iname '*.svg' -or \ - -iname '*.ttf' -or -iname '*.woff' -or \ - -iname '*.woff2' -or -iname '*.css' - -STATIC = $(STYLES) $(STYLEPNGS) $(STYLESVGS) $(FONTS) +STATIC = $(STYLES) $(FONTS) BSTATIC = $(patsubst %,$(BUILDDIR)/%,$(STATIC)) BSCRIPTS = $(patsubst %.ts,$(BUILDDIR)/%.js,$(TSCRIPTS)) diff --git a/make-pages/BuilderQQ.hs b/make-pages/BuilderQQ.hs index c7cee73..de08612 100644 --- a/make-pages/BuilderQQ.hs +++ b/make-pages/BuilderQQ.hs @@ -18,9 +18,15 @@ import Data.List.NonEmpty (NonEmpty, toList) data Chunk = Lit String | Var String + +-- | +-- * use @$var@ to insert a variable (instance of 'CanBuild') +-- * use @$&@ to insert nothing like @\&@ in a string (e.g. to add whitespace +-- at the start or end, or to have a variable followed by a letter +-- * use @$$@ for a literal @$@ parseB :: String -> ExpQ parseB = toExpQ . reverse . go "" [] . trim where - trim = dropWhileEnd isSpace . dropWhile (== '\n') + trim = dropWhileEnd isSpace . dropWhile isSpace go acc cs [] = addLit acc cs go acc cs ('$':'&':rest) = go acc cs rest -- $&: expands to nothing go acc cs ('$':'$':rest) = go ('$' : acc) cs rest -- $$: expands to one $ @@ -58,7 +64,8 @@ escId = foldMap esc1 . Strict.unpack where escAttr :: Strict.Text -> Builder escAttr = foldMap esc1 . Strict.unpack where esc1 c = fromMaybe (singleton c) $ lookup c - [('<', "<"), ('>', ">"), ('"', """), ('\'', "'")] + [('<', "<"), ('>', ">"), ('"', """), ('\'', "'"), + ('&', "&")] class CanBuild a where build :: a -> Builder diff --git a/make-pages/GalleryPage.hs b/make-pages/GalleryPage.hs index ae2a1bd..99c69ca 100644 --- a/make-pages/GalleryPage.hs +++ b/make-pages/GalleryPage.hs @@ -80,9 +80,7 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|
- + $items
|] @@ -129,16 +127,17 @@ makeFilter prefix initial tag count = [b| where id' = [b|$prefix$&_$tag'|] tag' = escId tag - checked = if HashSet.member tag initial then [b| checked|] else "" - hidden = if count <= 1 then [b| hidden|] else "" + checked = if HashSet.member tag initial then [b|$& checked|] else "" + hidden = if count <= 1 then [b|$& hidden|] else "" makeYearItems :: Bool -- ^ nsfw -> Int -- ^ year -> [(FilePath, Info)] -> Builder makeYearItems nsfw year infos = [b| -
  • - $year' +

    + $year' +

    $items |] where @@ -147,24 +146,25 @@ makeYearItems nsfw year infos = [b| makeItem :: Bool -> FilePath -> Info -> Builder makeItem nsfw file info@(Info {bg}) = [b| -
  • + alt="$title" title="$tooltip"> + |] where - title = fromMaybe info.title $ info.galleryTitle + title = escAttr $ fromMaybe info.title info.galleryTitle dir = takeDirectory file thumbnail = 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 date = latestDateFor nsfw info date' = formatTooltip date year' = date.year updated' = if hasUpdatesFor nsfw info then [b|true|] else [b|false|] - bgStyle = case bg of Other col -> [b| style="background: $col"|]; _ -> "" + bgStyle = case bg of Other col -> [b|$& style="background: $col"|]; _ -> "" tooltip = [b|$title ($upd$date')|] where upd = if hasUpdatesFor nsfw info then "updated " else "" :: Builder diff --git a/make-pages/IndexPage.hs b/make-pages/IndexPage.hs index 3efce99..1b1600d 100644 --- a/make-pages/IndexPage.hs +++ b/make-pages/IndexPage.hs @@ -74,13 +74,13 @@ makeItem :: GalleryInfo -> Builder makeItem (GalleryInfo {title, desc, prefix, filters}) = [b| $title
  • |] - 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 {title, url, nsfw}) = [b| $title |] - where nsfw' = if nsfw then [b| class=nsfw|] else "" + where nsfw' = if nsfw then [b|$& class=nsfw|] else "" hasNsfw :: GalleryFilters -> Bool hasNsfw (GalleryFilters {nsfw}) = nsfw /= NoNsfw diff --git a/make-pages/Info.hs b/make-pages/Info.hs index e09e294..e14f0c5 100644 --- a/make-pages/Info.hs +++ b/make-pages/Info.hs @@ -105,6 +105,7 @@ data Image = label :: !Text, path :: !FilePath, download :: !(Maybe FilePath), + desc :: !Text, nsfw :: !Bool, warning :: !(Maybe Text), resize :: !Bool @@ -198,7 +199,7 @@ thumb (Info {thumb', images}) = latestDateFor :: Bool -> Info -> Date latestDateFor nsfw i = maximum $ i.date : mapMaybe relDate (updatesFor nsfw i) where - relDate (date, us) = date <$ guard (not $ null us || any (.ignoreSort) us) + relDate (date, us) = date <$ guard (not $ null us || all (.ignoreSort) us) latestYearFor :: Bool -> Info -> Int latestYearFor nsfw info = (latestDateFor nsfw info).year @@ -369,17 +370,18 @@ unlabelledImage' label' y = asStr y <|> asObj y where asStr = YAML.withStr "path" \(Text.unpack -> path) -> let label = fromMaybe (pathToLabel path) label' in - pure $ Image {label, path, download = Nothing, + pure $ Image {label, path, download = Nothing, desc = "", nsfw = False, warning = Nothing, resize = True} asObj = YAML.withMap "image info" \m -> do - checkKeys m ["path", "download", "nsfw", "warning", "resize"] + checkKeys m ["path", "download", "desc", "nsfw", "warning", "resize"] path <- m .: "path" download <- m .:? "download" + desc <- m .:? "desc" .!= "" nsfw <- m .:? "nsfw" .!= False warning <- m .:? "warning" resize <- m .:? "resize" .!= True let label = fromMaybe (pathToLabel path) label' - pure $ Image {label, path, download, nsfw, warning, resize} + pure $ Image {label, path, download, nsfw, warning, desc, resize} pathToLabel = Text.pack . gapToSpace . takeBaseName gapToSpace = map \case '-' -> ' '; '_' -> ' '; c -> c @@ -407,14 +409,13 @@ instance FromYAML Link where updateList :: Maybe (YAML.Node YAML.Pos) -> YAML.Parser [(Date, NonEmpty Update)] updateList = - maybe (pure []) $ YAML.withMap "updates" $ - nonEmptys <=< traverse bodies . Map.toList + maybe (pure []) $ YAML.withMap "updates" $ traverse bodies . Map.toList where bodies (date', rest) = (,) <$> parseYAML date' <*> body rest - body b = - return <$> body1 b - <|> YAML.withSeq "update list" (traverse body1) b + body b = return <$> body1 b <|> YAML.withSeq "update list" (bodyN b) b body1 b = asDesc b <|> asObj b + bodyN y = + maybe (YAML.typeMismatch "non-empty list" y) (traverse body1) . nonEmpty asDesc = YAML.withStr "desc" \desc -> pure $ Update {desc, nsfw = False, ignoreSort = False} asObj = YAML.withMap "update info" \m -> do @@ -423,8 +424,6 @@ updateList = nsfw <- m .:? "nsfw" .!= False ignoreSort <- m .:? "ignore-sort" .!= False pure $ Update {desc, nsfw, ignoreSort} - nonEmptys = traverse $ traverse $ - maybe (fail "expected non-empty list") pure . nonEmpty data GalleryInfo = diff --git a/make-pages/RSS.hs b/make-pages/RSS.hs index 3739cda..ee40bdc 100644 --- a/make-pages/RSS.hs +++ b/make-pages/RSS.hs @@ -26,11 +26,12 @@ make' :: Strict.Text -> Strict.Text -> GalleryInfo -> Maybe FilePath -> [(FilePath, Info)] -> Builder make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b| - + - $name—$title + <![CDATA[$name—$title]]> $link - $desc + $selflink $items @@ -50,11 +51,12 @@ make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b| makeItem :: Strict.Text -> FilePath -> Bool -> FilePath -> Info -> Builder makeItem root prefix nsfw path info@(Info {title}) = [b| - $title$suffix + <![CDATA[$title$suffix]]> $link $link - $body + $date + $body |] where @@ -77,20 +79,37 @@ makeItem root prefix nsfw path info@(Info {title}) = [b| dir = takeDirectory path link = [b|$root/$prefix/$dir|] + creator = maybe "niss" (.name) info.artist + date = formatRSS $ latestDateFor nsfw info artist = ifJust info.artist \case Artist name Nothing -> [b|

    by $name|] Artist name (Just url) -> [b|

    by $name|] desc = makeDesc $ descFor nsfw info - image = case previewImage info of - Just (PFull img) -> figure $ pageFile img - Just (PThumb th) -> figure $ thumbFile th + preview = previewImage info + image = case preview of + Just (PFull img) -> figure (escAttr img.desc) $ pageFile img + Just (PThumb th) -> figure "full image hidden" $ thumbFile th Nothing -> "" - figure p = [b|

    |] + msg = case preview of + Just (PThumb _) -> "

    (full image hidden; open to see)

    " + _ -> "" :: Text + figure alt p = [b| +
    + + $alt + +
    + $msg + |] makeDesc :: Desc -> Builder makeDesc NoDesc = "" makeDesc (TextDesc txt) = [b|$txt|] -makeDesc (LongDesc fs) = [b|
    $fields
    |] - where fields = map (\(DescField {name, text}) -> [b|
    $name
    $text|]) fs +makeDesc (LongDesc fs) = [b|
      $fields
    |] where + fields = map mkField fs + mkField (DescField {name, text}) = [b| +
  • $name: + $text + |] diff --git a/make-pages/SinglePage.hs b/make-pages/SinglePage.hs index 8124b50..1173cef 100644 --- a/make-pages/SinglePage.hs +++ b/make-pages/SinglePage.hs @@ -17,6 +17,7 @@ import qualified Data.HashSet as Set import Data.Traversable import Data.Semigroup import Data.List.NonEmpty (toList) +import Data.Char (isSpace) -- | e.g. only nsfw images are present for a non-nsfw page @@ -95,6 +96,8 @@ make' root siteName prefix nsfw _dataDir dir Just (Artist {name}) -> [b|by $name|] Nothing -> "by niss" + let alt = escAttr image0.desc + let updateDate = ifJust (last' updates) \(d, _) -> let updated = formatLong d in [b|
    updated $updated|] @@ -104,23 +107,25 @@ make' root siteName prefix nsfw _dataDir dir let nsfwDialog = NsfwWarning.dialog nsfw' let imageMeta = case previewImage info of - Just (PFull (Image {path})) -> [b| + Just (PFull (pageFile -> path)) -> [b| |] - Just (PThumb path) -> [b| + Just (PThumb (thumbFile -> path)) -> [b| |] Nothing -> throw $ NoThumb dir + let escTitle = escAttr title + pure [b| - + @@ -138,13 +143,13 @@ make' root siteName prefix nsfw _dataDir dir $prefetches - $title + $escTitle $nsfwDialog
    -

    $title

    +

    $escTitle

    $formattedDate $updateDate

    @@ -156,10 +161,10 @@ make' root siteName prefix nsfw _dataDir dir $buttonBar
    -
    +
    $warning' - + $alt
    @@ -297,16 +302,17 @@ altButton :: Image -> Text -> Builder altButton img i = [b| + data-link="$link"$warning' data-alt="$alt"> |] where Image {label, nsfw, warning, download} = img - nsfwClass = if nsfw then [b| class=nsfw|] else "" - nsfwLabelClass = if nsfw then [b| class=nsfw-label|] else "" + nsfwClass = if nsfw then [b|$& class=nsfw|] else "" + nsfwLabelClass = if nsfw then [b|$& class=nsfw-label|] else "" path' = pageFile img link = fromMaybe (bigFile img) download - warning' = ifJust warning \(escAttr -> w) -> [b| data-warning="$w"|] + warning' = ifJust warning \(escAttr -> w) -> [b|$& data-warning="$w"|] + alt = img.desc makeTags :: FilePath -> [Strict.Text] -> Builder makeTags undir tags = @@ -361,4 +367,8 @@ makeUpdate date ups = [b|
    $desc |] where date' = formatSlash date - desc = mconcat $ map fromText $ intersperse "; " $ toList $ fmap (.desc) ups + desc = mconcat $ + intersperse "; " $ + map (fromText . Strict.dropWhileEnd isSpace) $ + toList $ + fmap (.desc) ups diff --git a/script/gallery.ts b/script/gallery.ts index 6c562cd..738f23b 100644 --- a/script/gallery.ts +++ b/script/gallery.ts @@ -106,14 +106,18 @@ function makeFragment() { } } + type Shortcuts = { [short: string]: Set }; const shortcuts: Shortcuts = { - 'summary': new Set('require_artsummary'), - 'colourexamples': new Set('require_colourexample'), - 'flatexamples': new Set('require_flatexample'), - 'sketchexamples': new Set('require_sketchexample'), - 'iconexamples': new Set('require_iconexample'), - 'curated': new Set('require_curated') + summary: new Set(['require_artsummary']), + colourexamples: new Set(['require_colourexample']), + flatexamples: new Set(['require_flatexample']), + sketchexamples: new Set(['require_sketchexample']), + iconexamples: new Set(['require_iconexample']), + curated: new Set(['require_curated']), + gecs: new Set(['require_niss', 'require_nisse']), + qt: new Set(['require_q_t_']), + kesi: new Set(['require_kesi']), }; function useFragment() { @@ -195,12 +199,11 @@ function setup() { itemsByYear = new Map; for (const item of items) { const year = item.dataset.year; - if (year !== undefined) { - if (!itemsByYear.has(year)) { - itemsByYear.set(year, new Set([item])); - } else { - itemsByYear.get(year)?.add(item); - } + if (!year) continue; + if (!itemsByYear.has(year)) { + itemsByYear.set(year, new Set([item])); + } else { + itemsByYear.get(year)!.add(item); } } diff --git a/script/single.ts b/script/single.ts index 21e6f8c..0cd291a 100644 --- a/script/single.ts +++ b/script/single.ts @@ -21,7 +21,8 @@ function addCWListeners(id: string | null, caption: HTMLElement): void { e => { if (e.key == 'Enter') openCW(id, caption, true) }); } -function setImage(id: string, src: string, href: string, cw: string): void { +function setImage(id: string, src: string, href: string, + alt: string, cw: string): void { const curCw = document.getElementById('cw'); const coverNew = cw != '' && !opened.has(id) && !skipAll.checked; @@ -45,12 +46,14 @@ function setImage(id: string, src: string, href: string, cw: string): void { // else no cover before or after mainimg.src = src; + mainimg.alt = mainimg.title = alt; mainlink.href = href; } function activateButton(button: HTMLInputElement, doPush = true): void { setImage(button.id, button.value, button.dataset.link!, + button.dataset.alt ?? '', button.dataset.warning ?? ''); if (doPush) history.pushState(null, '', '#' + button.id); diff --git a/style/shiny/gallery.css b/style/shiny/gallery.css index 131e123..b21904e 100644 --- a/style/shiny/gallery.css +++ b/style/shiny/gallery.css @@ -154,7 +154,7 @@ } -.grid { +main { padding: 0; display: grid; grid: auto-flow / repeat(auto-fit, var(--image-size)); @@ -169,6 +169,7 @@ width: var(--image-size); height: var(--image-size); overflow: hidden; + margin: 0; position: relative; } @@ -185,17 +186,13 @@ box-shadow: var(--focus-box); } -.year-marker { +.year-marker:not([hidden]) { /* uncomment to reenable line breaks before year markers */ /* grid-area: auto / 1; */ padding: var(--border-thickness); -} - -.year-text { - --gap: 0.2em; display: grid; grid-template-columns: repeat(2, calc(50% - 3 * var(--gap))); - grid-gap: var(--gap); + grid-gap: 0; align-items: center; justify-content: center; height: 100%;