style & layout updates

This commit is contained in:
rhiannon morris 2023-06-21 19:58:01 +02:00
parent ebd08fb2e5
commit 485b90fb46
9 changed files with 65 additions and 159 deletions

View file

@ -1,7 +1,7 @@
module Date module Date
(Date (..), (Date (..),
Day (..), dayNum, exact, Day (..), dayNum, exact,
formatLong, formatShort, formatRSS, formatSlash, formatLong, formatShort, formatRSS, formatSlash, formatTooltip,
parseP, parseS, parseA) parseP, parseS, parseA)
where where
@ -9,7 +9,7 @@ import Control.Applicative
import qualified Text.ParserCombinators.ReadP as ReadP import qualified Text.ParserCombinators.ReadP as ReadP
import Text.ParserCombinators.ReadP (ReadP, readS_to_P, readP_to_S, (<++)) import Text.ParserCombinators.ReadP (ReadP, readS_to_P, readP_to_S, (<++))
import Data.Time hiding (Day) import Data.Time hiding (Day)
import Data.Char (isSpace) import Data.Char (isSpace, toLower)
import BuilderQQ import BuilderQQ
import Data.Function (on) import Data.Function (on)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
@ -60,6 +60,15 @@ formatShort (Date {month, day}) = [b|$day'$month'|] where
Unknown -> "" Unknown -> ""
month' = formatTime defaultTimeLocale "%b" $ fromGregorian 1 month 1 month' = formatTime defaultTimeLocale "%b" $ fromGregorian 1 month 1
formatTooltip :: Date -> Builder
formatTooltip (Date {year, month, day}) = [b|$day'$month' $year|] where
day' = case day of
Exact d -> [b|$d $&|]
Approx d -> [b|$d? $&|]
Unknown -> ""
month' = map toLower $
formatTime defaultTimeLocale "%b" $ fromGregorian 1 month 1
formatRSS :: Date -> Builder formatRSS :: Date -> Builder
formatRSS = fromString . format . toTime where formatRSS = fromString . format . toTime where
format = formatTime defaultTimeLocale "%a, %d %b %_Y %T GMT" format = formatTime defaultTimeLocale "%a, %d %b %_Y %T GMT"

View file

@ -12,7 +12,7 @@ import Data.Function (on, (&))
import qualified Data.HashMap.Strict as HashMap import qualified Data.HashMap.Strict as HashMap
import Data.HashSet (HashSet) import Data.HashSet (HashSet)
import qualified Data.HashSet as HashSet import qualified Data.HashSet as HashSet
import Data.List (intersperse, groupBy, sortBy, sortOn) import Data.List (intersperse, groupBy, sortBy, sort)
import Data.Maybe import Data.Maybe
import qualified Data.Text.Lazy as Lazy import qualified Data.Text.Lazy as Lazy
import System.FilePath (takeDirectory, joinPath, splitPath) import System.FilePath (takeDirectory, joinPath, splitPath)
@ -52,9 +52,8 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
<div class=page> <div class=page>
<header> <header>
<h1>$title</h1> <h1>$title</h1>
<h2 class="right corner"> <a class="right corner" href=rss.xml>rss</a>
<a href=rss.xml>rss</a> <a class="left corner" href=$undir>back</a>
</h2>
</header> </header>
<nav id=filters> <nav id=filters>
@ -86,10 +85,6 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
$6.items $6.items
</ul> </ul>
</main> </main>
<footer>
<a href=$undir>all galleries</a>
</footer>
</div> </div>
|] |]
where where
@ -110,7 +105,7 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
allTags = infos allTags = infos
& concatMap (map (,1) . tagsFor nsfw . #second) & concatMap (map (,1) . tagsFor nsfw . #second)
& HashMap.fromListWith (+) & HashMap.toList & HashMap.fromListWith (+) & HashMap.toList
& sortOn (\(tag, count) -> (Down count, tag)) & sort
requireFilters = map (uncurry $ makeFilter "require" mempty) allTags requireFilters = map (uncurry $ makeFilter "require" mempty) allTags
excludeFilters = map (uncurry $ makeFilter "exclude" hidden) allTags excludeFilters = map (uncurry $ makeFilter "exclude" hidden) allTags
@ -153,18 +148,12 @@ makeYearItems nsfw year infos = [b|@0
makeItem :: Bool -> FilePath -> Info -> Builder makeItem :: Bool -> FilePath -> Info -> Builder
makeItem nsfw file info@(Info {bg}) = [b|@0 makeItem nsfw file info@(Info {bg}) = [b|@0
<li class="item post$nsfw'" data-date="$date'" data-year=$year' <li class="item post$nsfw'" data-year=$year' data-updated="$updated'"
data-updated="$updated'"
data-tags="$tags'"> data-tags="$tags'">
<figure>
<a href="$dir"> <a href="$dir">
<img src="$thumb" loading=lazy$bgStyle> <img src="$thumb" loading=lazy$bgStyle
title="$tooltip">
</a> </a>
<figcaption>
<span class=date>$date'</span>
<span class=title>$title</span>
</figcaption>
</figure>
|] |]
where where
title = fromMaybe (#title info) $ #galleryTitle info title = fromMaybe (#title info) $ #galleryTitle info
@ -173,7 +162,10 @@ makeItem nsfw file info@(Info {bg}) = [b|@0
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 = #latestDate info nsfw date = #latestDate info nsfw
date' = formatShort date date' = formatTooltip date
year' = #year date year' = #year date
updated' = if #updated info nsfw then [b|true|] else [b|false|] updated' = if #updated info nsfw 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 =
let upd = if #updated info nsfw then "updated " else "" :: Builder in
[b|$title ($upd$date')|]

View file

@ -3,7 +3,8 @@
{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-orphans #-}
module Info module Info
(Info (..), (Info (..),
tagsFor, descFor, imagesFor, linksFor, updatesFor, compareFor, sortFor, tagsFor, descFor, imagesFor, linksFor, updatesFor, lastUpdate,
compareFor, sortFor,
Artist (..), Images' (..), Images, Image (..), Desc (..), DescField (..), Artist (..), Images' (..), Images, Image (..), Desc (..), DescField (..),
Link (..), Update (..), Bg (..), Link (..), Update (..), Bg (..),
GalleryInfo (..), GalleryFilters (..), ArtistFilter (..), NsfwFilter (..), GalleryInfo (..), GalleryFilters (..), ArtistFilter (..), NsfwFilter (..),
@ -219,6 +220,10 @@ linksFor nsfw = if nsfw then #links else #sfwLinks
updatesFor :: Bool -> Info -> [(Date, [Update])] updatesFor :: Bool -> Info -> [(Date, [Update])]
updatesFor nsfw = if nsfw then #updates else #sfwUpdates updatesFor nsfw = if nsfw then #updates else #sfwUpdates
lastUpdate :: Bool -> Info -> Maybe Date
lastUpdate nsfw info =
case updatesFor nsfw info of [] -> Nothing; us -> Just $ fst $ last us
compareFor :: Bool -> Info -> Info -> Ordering compareFor :: Bool -> Info -> Info -> Ordering
compareFor nsfw = comparing \i -> (#latestDate i nsfw, #sortEx i, #title i) compareFor nsfw = comparing \i -> (#latestDate i nsfw, #sortEx i, #title i)

View file

@ -158,6 +158,7 @@ make' root siteName prefix nsfw _dataDir dir
<h2 id=date class="right corner"> <h2 id=date class="right corner">
$formattedDate $updateDate $formattedDate $updateDate
</h2> </h2>
<a class="left corner" href=$undir>back to gallery</a>
</header> </header>
$2.buttonBar $2.buttonBar
@ -180,10 +181,6 @@ make' root siteName prefix nsfw _dataDir dir
$6.tagsList $6.tagsList
</div> </div>
</main> </main>
<footer>
<a href=$undir>back to gallery</a>
</footer>
</div> </div>
<template id=cw-template> <template id=cw-template>

View file

@ -130,7 +130,7 @@ function sortFilters(cmp) {
sort1('exclude'); sort1('exclude');
} }
function sortFiltersAlpha() { function sortFiltersAlpha(e) {
function getName(x) { function getName(x) {
if (x.nodeType == Node.ELEMENT_NODE) { if (x.nodeType == Node.ELEMENT_NODE) {
return x.getElementsByTagName('input')[0].value; return x.getElementsByTagName('input')[0].value;
@ -139,9 +139,10 @@ function sortFiltersAlpha() {
} }
} }
sortFilters((a, b) => getName(a).localeCompare(getName(b))); sortFilters((a, b) => getName(a).localeCompare(getName(b)));
e.preventDefault();
} }
function sortFiltersUses() { function sortFiltersUses(e) {
function getUses(x) { function getUses(x) {
if (x.nodeType == Node.ELEMENT_NODE) { if (x.nodeType == Node.ELEMENT_NODE) {
return parseInt(x.getElementsByTagName('label')[0].dataset.count); return parseInt(x.getElementsByTagName('label')[0].dataset.count);
@ -150,6 +151,7 @@ function sortFiltersUses() {
} }
} }
sortFilters((a, b) => getUses(b) - getUses(a)); sortFilters((a, b) => getUses(b) - getUses(a));
e.preventDefault();
} }
@ -160,8 +162,8 @@ function setup() {
} }
let items = Array.from(document.getElementsByClassName('post')); let items = Array.from(document.getElementsByClassName('post'));
itemsByYear = new Map;
itemsByYear = new Map;
for (let item of items) { for (let item of items) {
let year = item.dataset.year; let year = item.dataset.year;
if (!itemsByYear.has(year)) itemsByYear.set(year, new Set); if (!itemsByYear.has(year)) itemsByYear.set(year, new Set);

View file

@ -28,7 +28,6 @@
--text-col: white; --text-col: white;
--text-shadow-col: hsl(0, 0%, 0%, 75%); --text-shadow-col: hsl(0, 0%, 0%, 75%);
--text-shadow: 2px 2px 3px var(--text-shadow-col); --text-shadow: 2px 2px 3px var(--text-shadow-col);
--nsfw-sticker-rotate: 15deg;
--focus-box: 0 0 5px hsl(55deg, 60%, 90%, 80%); --focus-box: 0 0 5px hsl(55deg, 60%, 90%, 80%);
--focus-text: hsl(334deg, 87%, 90%); --focus-text: hsl(334deg, 87%, 90%);
@ -53,6 +52,8 @@
margin: 0; margin: 0;
} }
body { margin: 0; }
header { header {
text-align: center; text-align: center;
} }
@ -65,12 +66,10 @@ h3 { font-size: 110%; }
.page { .page {
background: var(--background); background: var(--background);
border: var(--border);
position: relative; position: relative;
padding: 2em 4em; padding: 2em 4em;
margin: 3em auto 3.5em; margin: 0 auto;
border-radius: var(--border-radius);
color: var(--text-col); color: var(--text-col);
text-shadow: var(--text-shadow); text-shadow: var(--text-shadow);
@ -112,7 +111,7 @@ figure > img {
margin: 0; margin: 0;
padding: 0; padding: 0;
position: absolute; position: absolute;
top: 0.5em; top: 1em;
font-size: 100%; font-size: 100%;
font-weight: 500; font-weight: 500;

View file

@ -3,13 +3,18 @@
:root { :root {
--image-size: 200px; --image-size: 200px;
--gap: 1em; --badge-size: calc(1/4 * var(--image-size));
--gap: 0em;
} }
@media (min-width: 1000px) { @media (min-width: 1000px) {
.page { max-width: 80%; } .page { max-width: 80%; }
} }
.page {
padding: 2em calc(1/4 * var(--image-size));
}
#filters { #filters {
margin: 1em 0 2em 0; margin: 1em 0 2em 0;
} }
@ -33,7 +38,6 @@
.filterlist { .filterlist {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
/* justify-content: space-between; */
padding: 0; padding: 0;
font-weight: 500; font-weight: 500;
@ -54,10 +58,7 @@
} }
.filterlist label { .filterlist label {
padding: 0.15em 0.4em; cursor: pointer;
border-radius: var(--button-radius);
background: var(--button-bg);
border: var(--button-border);
} }
.filterlist label::before { .filterlist label::before {
@ -154,35 +155,18 @@
.item:not(.year-marker) { .item:not(.year-marker) {
box-shadow: var(--text-shadow); box-shadow: var(--text-shadow);
border: var(--border-thickness) solid var(--border-col); outline: var(--border-thickness) solid var(--border-col);
border-radius: 0.5em; background: hsl(0, 0%, 0%, 50%);
background: hsl(340, 45%, 65%); clip-path: polygon(5% 0, 95% 10%, 95% 100%, 5% 90%);
}
.item img {
clip-path: polygon(7% 2%, 93% 12%, 93% 98%, 7% 88%);
} }
.item:focus-within { .item:focus-within {
box-shadow: var(--focus-box); box-shadow: var(--focus-box);
} }
figure {
margin: 0;
padding: 0;
}
figcaption .date, figcaption .title {
position: absolute;
width: 100%;
border: 1px solid var(--border-col);
display: block;
text-align: center;
background: hsl(0, 0%, 0%, 75%);
text-shadow: none;
}
figcaption .date { top: -1px; left: -1px; }
figcaption .title { bottom: -1px; left: -1px; }
.date { text-transform: lowercase; }
.year-marker { .year-marker {
/* uncomment to reenable line breaks before year markers */ /* uncomment to reenable line breaks before year markers */
/* grid-area: auto / 1; */ /* grid-area: auto / 1; */
@ -210,9 +194,8 @@ figcaption .title { bottom: -1px; left: -1px; }
} }
.item.nsfw::before, .item[data-updated="true"]::after { .item.nsfw::before, .item[data-updated="true"]::after {
height: var(--size); height: var(--badge-size);
width: var(--size); width: var(--badge-size);
transform: var(--base-transform);
display: inline-block; display: inline-block;
position: absolute; position: absolute;
@ -221,19 +204,18 @@ figcaption .title { bottom: -1px; left: -1px; }
} }
.item.nsfw::before { .item.nsfw::before {
--size: calc(1/4 * var(--image-size)); transform: rotate(15deg);
--base-transform: rotate(var(--nsfw-sticker-rotate));
content: url(../18_plus_white.svg); content: url(../18_plus_white.svg);
top: calc(1em + 3px); top: 11%;
right: 3px; right: 7%;
z-index: 100;
} }
.item[data-updated="true"]::after { .item[data-updated="true"]::after {
--size: calc(1/4 * var(--image-size)); transform: rotate(-8deg);
--base-transform: rotate(-8deg);
content: url(../sparkles.svg); content: url(../sparkles.svg);
bottom: calc(1em + 3px); bottom: 4%;
right: 3px; right: 7%;
} }
footer { footer {
@ -242,68 +224,6 @@ footer {
margin-top: 1em; margin-top: 1em;
} }
@media (hover) and (pointer: fine) {
.item:hover .date, .item:hover .title,
.item:hover::before, .item:hover::after {
filter: opacity(20%);
}
@media (prefers-reduced-motion: no-preference) {
figcaption .date, figcaption .title, .item::before, .item::after {
transition-property: filter, transform;
transition-duration: 0.15s;
transition-timing-function: ease-in-out;
}
.item:hover .title {
transform: translate(-20%, 80%) rotateZ(7deg);
}
.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) var(--base-transform);
}
}
}
@media (not hover), (pointer: coarse) {
.item:not(.year-marker) {
height: min-content;
}
figcaption .date, figcaption .title {
position: initial;
}
figcaption .date {
border-bottom: none;
}
figcaption .title {
border-top: none;
}
figcaption .date::after {
content: ':';
}
.item a {
display: block;
height: var(--image-size);
}
.item img {
margin-bottom: 0;
}
}
@media (pointer: coarse) { @media (pointer: coarse) {
#filters label { #filters label {
font-size: 150%; font-size: 150%;

View file

@ -9,6 +9,7 @@
.page { .page {
width: 37.5em; width: 37.5em;
border-radius: var(--border-radius);
} }
#title::before, #title::after { #title::before, #title::after {
@ -30,12 +31,11 @@
} }
@media screen { @media not speech {
.nsfw::after { .nsfw::after {
content: url(../18_plus_white.svg); content: url(../18_plus_white.svg);
height: 1em; height: 1em;
width: 1em; width: 1em;
transform: rotate(var(--nsfw-sticker-rotate));
mix-blend-mode: hard-light; mix-blend-mode: hard-light;
margin-left: 0.3em; margin-left: 0.3em;
} }
@ -43,7 +43,7 @@
@media speech { @media speech {
.nsfw::after { .nsfw::after {
content: ' (some nsfw)'; content: ' (contains adult content)';
} }
} }

View file

@ -18,7 +18,6 @@
position: relative; position: relative;
overflow: hidden; overflow: hidden;
border: var(--border-thickness) solid var(--border-col); border: var(--border-thickness) solid var(--border-col);
border-radius: 1em;
box-shadow: var(--text-shadow); box-shadow: var(--text-shadow);
background: hsl(340, 45%, 65%); background: hsl(340, 45%, 65%);
} }
@ -76,20 +75,6 @@
} }
} }
/*
.nsfw-label::after {
content: url(../18_plus_white.svg);
display: inline-block;
height: 0.9em; width: 0.9em;
vertical-align: -0.07em;
padding-left: 0.25em;
}
:checked ~ .nsfw-label::after {
content: url(../18_plus.svg);
}
*/
#date { text-transform: lowercase; } #date { text-transform: lowercase; }
#info { #info {
@ -104,9 +89,6 @@
align-items: baseline; align-items: baseline;
} }
/* 'display: contents' removes things from the accessibility tree
* which is probably only a problem for screen readers?
*/
@media not speech { @media not speech {
.info-section { .info-section {
display: contents; display: contents;