add nsfw warning dialog

This commit is contained in:
Rhiannon Morris 2020-10-06 22:07:39 +02:00
parent d671a4c01e
commit c807895244
12 changed files with 346 additions and 102 deletions

View File

@ -4,6 +4,7 @@ module GalleryPage (make) where
import BuilderQQ import BuilderQQ
import Date import Date
import Info import Info
import qualified NsfwWarning
import Data.Foldable import Data.Foldable
import Data.Function (on, (&)) import Data.Function (on, (&))
@ -38,45 +39,50 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
<meta name=twitter:card content=summary> <meta name=twitter:card content=summary>
<script src=/script/gallery.js></script> <script src=/script/gallery.js></script>
$0.nsfwScript
<title>$title</title> <title>$title</title>
<header> $0.nsfwDialog
<h1>$title</h1>
<h2 class="right corner">
<a href=rss.xml>rss</a>
</h2>
</header>
<nav id=filters> <div class=page>
<details id=filters-details> <header>
<summary><h2>filters</h2></summary> <h1>$title</h1>
<div> <h2 class="right corner">
<h3>show only</h3> <a href=rss.xml>rss</a>
<ul id=require class="buttonbar bb-choice"> </h2>
$8.requireFilters </header>
</ul>
<h3>exclude</h3> <nav id=filters>
<ul id=exclude class="buttonbar bb-choice"> <details id=filters-details>
$8.excludeFilters <summary><h2>filters</h2></summary>
</ul> <div>
<h3>show only</h3>
<ul id=require class="buttonbar bb-choice">
$10.requireFilters
</ul>
<a href=# id=clear>clear</a> <h3>exclude</h3>
<a href=# id=singles>toggle single-use tags</a> <ul id=exclude class="buttonbar bb-choice">
</div> $10.excludeFilters
</details> </ul>
</nav>
<main> <a href=# id=clear>clear</a>
<ul class=grid> <a href=# id=singles>toggle single-use tags</a>
$4.items </div>
</ul> </details>
</main> </nav>
<footer> <main>
<a href=$undir>all galleries</a> <ul class=grid>
</footer> $6.items
</ul>
</main>
<footer>
<a href=$undir>all galleries</a>
</footer>
</div>
|] |]
where where
items = map (uncurry $ makeYearItems nsfw) infosByYear items = map (uncurry $ makeYearItems nsfw) infosByYear
@ -106,8 +112,11 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
| (_, (p0, i0) : _) : _ <- infosByYear = getThumb (takeDirectory p0) i0 | (_, (p0, i0) : _) : _ <- infosByYear = getThumb (takeDirectory p0) i0
| otherwise = "/style/card.png" | otherwise = "/style/card.png"
nsfwScript = NsfwWarning.script nsfw
nsfwDialog = NsfwWarning.dialog nsfw
makeFilter :: Text -> HashSet Text -> Text -> Int -> Builder makeFilter :: Text -> HashSet Text -> Text -> Int -> Builder
makeFilter prefix initial tag count = [b|@8 makeFilter prefix initial tag count = [b|@0
<li> <li>
<input type=checkbox id="$id'" value="$tag"$checked> <input type=checkbox id="$id'" value="$tag"$checked>
<label for="$id'" data-count=$count>$tag</label> <label for="$id'" data-count=$count>$tag</label>
@ -121,17 +130,17 @@ makeYearItems :: Bool -- ^ nsfw
-> Int -- ^ year -> Int -- ^ year
-> [(FilePath, Info)] -> [(FilePath, Info)]
-> Builder -> Builder
makeYearItems nsfw year infos = [b|@4 makeYearItems nsfw year infos = [b|@0
<li class="item year-marker" id="marker-$year"> <li class="item year-marker" id="marker-$year">
<span class=year-text>$year'</span> <span class=year-text>$year'</span>
$4.items $0.items
|] |]
where where
items = map (uncurry $ makeItem nsfw) infos items = map (uncurry $ makeItem nsfw) infos
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}) = [b|@4 makeItem nsfw file info@(Info {title, bg}) = [b|@0
<li class="item post$nsfw'" data-date="$date'" data-year=$year' <li class="item post$nsfw'" data-date="$date'" data-year=$year'
data-updated="$updated'" data-updated="$updated'"
data-tags="$tags'"> data-tags="$tags'">

View File

@ -27,30 +27,32 @@ make' root (IndexInfo {title, desc, galleries, links, footer}) = [b|@0
<title>$title</title> <title>$title</title>
<header> <div class=page>
<h1 id=title>$title</h1> <header>
</header> <h1 id=title>$title</h1>
</header>
<main> <main>
$galleryList $4.galleryList
$linkList $4.linkList
</main> </main>
$footer' $2.footer'
</div>
|] |]
where where
galleryList = if null galleries then "" else [b|@2 galleryList = if null galleries then "" else [b|@0
<nav aria-label="gallery list"> <nav aria-label="gallery list">
<ul id=gallery-list class=list> <ul id=gallery-list class=list>
$6.items $4.items
</ul> </ul>
</nav> </nav>
|] |]
where items = map makeItem galleries where items = map makeItem galleries
linkList = if null links then "" else [b|@2 linkList = if null links then "" else [b|@0
<nav aria-label="other links"> <nav aria-label="other links">
<ul id=link-list class=list> <ul id=link-list class=list>
$6.items $4.items
</ul> </ul>
</nav> </nav>
|] |]
@ -65,13 +67,13 @@ make' root (IndexInfo {title, desc, galleries, links, footer}) = [b|@0
url = [b|$root|] url = [b|$root|]
makeItem :: GalleryInfo -> Builder makeItem :: GalleryInfo -> Builder
makeItem (GalleryInfo {title, desc, prefix, filters}) = [b|@6 makeItem (GalleryInfo {title, desc, prefix, filters}) = [b|@0
<li$nsfw><a href=$prefix title="$desc">$title</a></li> <li$nsfw><a href=$prefix title="$desc">$title</a></li>
|] |]
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 -> Builder
makeLink (Link {title, url, nsfw}) = [b|@6 makeLink (Link {title, url, nsfw}) = [b|@0
<li$nsfw'><a href=$url>$title</a> <li$nsfw'><a href=$url>$title</a>
|] |]
where nsfw' = if nsfw then [b| class=nsfw|] else "" where nsfw' = if nsfw then [b| class=nsfw|] else ""

30
make-pages/NsfwWarning.hs Normal file
View File

@ -0,0 +1,30 @@
{-# OPTIONS_GHC -fdefer-typed-holes #-}
module NsfwWarning (script, dialog) where
import BuilderQQ
script :: Bool -> Builder
script False = ""
script True = [b|<script src=/script/nsfw-warning.js></script>|]
dialog :: Bool -> Builder
dialog False = ""
dialog True = [b|@0
<div class=dialog id=nsfw-dialog>
<div class=dialog-inner>
<h1>cw: lewd</h1>
<img class=dialog-icon src=/style/stop_hand.svg>
<div class=dialog-message>
are you an adult? <br> if not please don't look!
</div>
<div class=dialog-buttons>
<button id=nsfw-yes class=yes>yes i am and i wanna see</button>
<button id=nsfw-no class=no>no im not</button>
</div>
</div>
</div>
|]

View File

@ -4,6 +4,7 @@ import Date
import Info import Info
import BuilderQQ import BuilderQQ
import Records () import Records ()
import qualified NsfwWarning
import Control.Exception import Control.Exception
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
@ -60,7 +61,7 @@ make' root prefix nsfw dataDir dir
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
let makeWarning w = [b|@4 let makeWarning w = [b|@0
<figcaption id=cw aria-role=button tabindex=0> <figcaption id=cw aria-role=button tabindex=0>
<span id=cw-text>$w</span> <span id=cw-text>$w</span>
</figcaption> </figcaption>
@ -82,6 +83,9 @@ make' root prefix nsfw dataDir dir
let updateDate = ifJust (Map.lookupMax updates) \(formatLong -> u, _) -> let updateDate = ifJust (Map.lookupMax updates) \(formatLong -> u, _) ->
[b|<br> <span class=updated>updated $u</span>|] [b|<br> <span class=updated>updated $u</span>|]
let nsfwScript = NsfwWarning.script nsfw
let nsfwDialog = NsfwWarning.dialog nsfw
pure [b|@0 pure [b|@0
<!DOCTYPE html> <!DOCTYPE html>
<html lang=en> <html lang=en>
@ -100,44 +104,49 @@ make' root prefix nsfw dataDir dir
<meta name=twitter:card content=summary> <meta name=twitter:card content=summary>
<script src=/script/single.js></script> <script src=/script/single.js></script>
$nsfwScript
$bgStyle $bgStyle
$0.prefetches $0.prefetches
<title>$title</title> <title>$title</title>
<header> $nsfwDialog
<h1>$title</h1>
$artistTag
<h2 id=date class="right corner">
$formattedDate $updateDate
</h2>
</header>
$buttonBar <div class=page>
<header>
<h1>$title</h1>
$artistTag
<h2 id=date class="right corner">
$formattedDate $updateDate
</h2>
</header>
<main> $2.buttonBar
<figure id=mainfig data-width=$width0 data-height=$height0>
$warning'
<a id=mainlink href="$download0" title="download full version">
<img id=mainimg src="$path0'" alt="">
</a>
</figure>
<div id=info> <main>
$descSection <figure id=mainfig data-width=$width0 data-height=$height0>
$warning'
<a id=mainlink href="$download0" title="download full version">
<img id=mainimg src="$path0'" alt="">
</a>
</figure>
$tagsList <div id=info>
$6.descSection
$linksList $6.tagsList
$updatesList $6.linksList
</div>
</main>
<footer> $6.updatesList
<a href=$undir>back to gallery</a> </div>
</footer> </main>
<footer>
<a href=$undir>back to gallery</a>
</footer>
</div>
<template id=cw-template> <template id=cw-template>
$warningT $warningT
@ -153,11 +162,11 @@ makeArtist (Artist {name, url}) =
Nothing -> [b|$name|] Nothing -> [b|$name|]
makeDesc :: Maybe Strict.Text -> Builder makeDesc :: Maybe Strict.Text -> Builder
makeDesc mdesc = ifJust mdesc \desc -> [b|@4 makeDesc mdesc = ifJust mdesc \desc -> [b|@0
<section id=desc class=info-section> <section id=desc class=info-section>
<h2>about</h2> <h2>about</h2>
<div> <div>
$8.desc $4.desc
</div> </div>
</section> </section>
|] |]
@ -177,7 +186,7 @@ makeButtonBar title images =
where alts = map (\(i, (im, sz)) -> altButton i im sz) $ zip [0..] images where alts = map (\(i, (im, sz)) -> altButton i im sz) $ zip [0..] images
altButton :: Int -> Image -> Size -> Builder altButton :: Int -> Image -> Size -> Builder
altButton i (Image {label, path, nsfw, warning}) (Size {width, height}) = [b|@4 altButton i (Image {label, path, nsfw, warning}) (Size {width, height}) = [b|@0
<li$nsfwClass> <li$nsfwClass>
<input type=radio$checked name=variant id="$idLabel" value="$path'" <input type=radio$checked name=variant id="$idLabel" value="$path'"
data-link="$path"$warning' data-link="$path"$warning'
@ -194,11 +203,11 @@ altButton i (Image {label, path, nsfw, warning}) (Size {width, height}) = [b|@4
makeTags :: FilePath -> [Strict.Text] -> Builder makeTags :: FilePath -> [Strict.Text] -> Builder
makeTags undir tags = makeTags undir tags =
if null tags then "" else [b|@4 if null tags then "" else [b|@0
<nav id=tags class=info-section> <nav id=tags class=info-section>
<h2>tags</h2> <h2>tags</h2>
<ul class="buttonbar bb-links"> <ul class="buttonbar bb-links">
$8.tagList $4.tagList
</ul> </ul>
</nav> </nav>
|] |]
@ -209,11 +218,11 @@ makeTags undir tags =
extLinks :: [Link] -> Builder extLinks :: [Link] -> Builder
extLinks links = extLinks links =
if null links then "" else [b|@4 if null links then "" else [b|@0
<nav id=links class=info-section> <nav id=links class=info-section>
<h2>links</h2> <h2>links</h2>
<ul class="buttonbar bb-links"> <ul class="buttonbar bb-links">
$8.linkList $4.linkList
</ul> </ul>
</nav> </nav>
|] |]

View File

@ -15,16 +15,17 @@ executable make-pages
main-is: Main.hs main-is: Main.hs
other-modules: other-modules:
BuilderQQ, BuilderQQ,
Date,
Depend,
GalleryPage,
Info,
IndexPage,
ListTags,
Options,
Records, Records,
Date,
Info,
Depend,
NsfwWarning,
GalleryPage,
IndexPage,
SinglePage, SinglePage,
RSS RSS,
ListTags,
Options
default-language: Haskell2010 default-language: Haskell2010
default-extensions: default-extensions:
BlockArguments, BlockArguments,

35
script/nsfw-warning.js Normal file
View File

@ -0,0 +1,35 @@
(function () {
'use strict';
let nsfwOk = 'nsfw-ok';
function alreadyYes() {
return sessionStorage.getItem(nsfwOk);
}
function dismiss() {
let dialog = document.getElementById('nsfw-dialog');
dialog.parentElement.removeChild(dialog);
}
function yes() {
sessionStorage.setItem(nsfwOk, 1);
dismiss();
}
function no() {
history.go(-1);
}
function setup() {
if (alreadyYes()) {
dismiss();
} else {
document.getElementById('nsfw-yes').onclick = yes;
document.getElementById('nsfw-no').onclick = no;
}
}
document.addEventListener('DOMContentLoaded', setup);
})();

View File

@ -17,6 +17,13 @@
--focus-box: 0 0 20px hsl(55deg, 60%, 90%, 80%); --focus-box: 0 0 20px hsl(55deg, 60%, 90%, 80%);
--focus-text: hsl(334deg, 87%, 90%); --focus-text: hsl(334deg, 87%, 90%);
--shadow-col: hsl(42deg, 82%, 90%, 75%);
--border-col: var(--text-col);
--border: 3px solid var(--border-col);
--border-radius: 1.5em;
--shadow: 0 0 3em var(--shadow-col);
--background: hsla(0, 0%, 0%, 60%);
font-family: Muller; font-family: Muller;
font-size: x-large; font-size: x-large;
font-weight: 600; font-weight: 600;
@ -35,18 +42,15 @@ h1 { font-size: 300%; }
h2 { font-size: 125%; } h2 { font-size: 125%; }
h3 { font-size: 110%; } h3 { font-size: 110%; }
body { .page {
--shadow: hsl(42deg, 82%, 90%, 75%); background: var(--background);
--border-col: var(--text-col); border: var(--border);
box-shadow: var(--shadow);
background: hsla(0, 0%, 0%, 60%);
border: 3px solid var(--border-col);
box-shadow: 0 0 3em var(--shadow);
position: relative; position: relative;
padding: 2em 4em; padding: 2em 4em;
margin: 3em auto 3.5em; margin: 3em auto 3.5em;
border-radius: 1.5em; border-radius: var(--border-radius);
color: var(--text-col); color: var(--text-col);
--text-shadow: 2px 2px 3px hsl(0, 0%, 0%, 75%); --text-shadow: 2px 2px 3px hsl(0, 0%, 0%, 75%);
@ -207,7 +211,7 @@ dd + dt {
} }
body { body {
--shadow: hsl(42deg, 82%, 90%, 20%); --shadow-col: hsl(42deg, 82%, 90%, 20%);
--border-col: black; --border-col: black;
} }

View File

@ -1,10 +1,11 @@
@import url(base.css); @import url(base.css);
@import url(nsfw-warning.css);
:root { :root {
--image-size: 200px; --image-size: 200px;
} }
body { .page {
--gap: 1em; --gap: 1em;
max-width: calc(4 * var(--image-size) + 3 * var(--gap)); max-width: calc(4 * var(--image-size) + 3 * var(--gap));
padding-left: 4em; padding-left: 4em;

View File

@ -7,7 +7,7 @@
justify-content: center; justify-content: center;
} }
body { .page {
width: 37.5em; width: 37.5em;
} }

View File

@ -0,0 +1,78 @@
.dialog {
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
margin: 0;
z-index: 1000;
background: hsl(340deg, 35%, 15%, 90%);
backdrop-filter: blur(15px);
color: var(--text-col);
display: grid;
}
.dialog-inner {
place-self: center;
display: grid;
grid-template:
"header header"
"icon text"
"buttons buttons"
/ 1fr 3fr;
grid-gap: 0.5em;
align-items: center;
min-height: 20vh;
max-width: 60vw;
padding: 1.5em 3em 2em;
background: var(--background);
border: var(--border);
border-radius: var(--border-radius);
}
.dialog h1 {
margin: 0;
grid-area: header;
justify-self: center;
}
.dialog-icon {
height: 3em;
width: 3em;
grid-area: icon;
justify-self: center;
}
.dialog-message {
grid-area: text;
justify-self: start;
}
.dialog-buttons {
grid-area: buttons;
justify-self: center;
}
.dialog button + button {
margin-left: 1em;
}
.dialog button {
border: none;
border-radius: 0.75em;
padding: 0.5em 1em;
font-family: Muller;
font-weight: 600;
color: black;
}
button.yes {
background: hsl(100deg, 70%, 80%);
}
button.no {
background: hsl(5deg, 70%, 80%);
}

View File

@ -1,10 +1,11 @@
@import url(base.css); @import url(base.css);
@import url(nsfw-warning.css);
:root { :root {
--image-width: 1000px; --image-width: 1000px;
} }
body { .page {
max-width: var(--image-width); max-width: var(--image-width);
} }

74
style/stop_hand.svg Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
clip-rule="evenodd"
fill-rule="evenodd"
stroke-linejoin="round"
stroke-miterlimit="2"
viewBox="0 0 32 32"
version="1.1"
id="svg17"
sodipodi:docname="hand_paw_c2.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<defs
id="defs21" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="711"
inkscape:window-height="480"
id="namedview19"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="16"
inkscape:cy="16"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="g15" />
<clipPath
id="a">
<path
clip-rule="evenodd"
d="m0 0h32v32h-32z"
id="path2" />
</clipPath>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<path
d="m0 0h32v32h-32z"
fill="none"
id="path7" />
<g
clip-path="url(#a)"
id="g15">
<path
d="m11.414 2.609c.714-1.542 2.276-2.613 4.086-2.613 1.914 0 3.551 1.198 4.201 2.885 1.043-.77 2.41-1.085 3.764-.747 2.41.603 3.877 3.048 3.275 5.457l-1.701 6.805c1.822-.775 4.012-.42 5.496 1.065 1.952 1.951 1.952 5.119 0 7.071 0 0-3.608 3.608-5.979 5.979-2.234 2.234-5.264 3.489-8.423 3.489h-.133v-.004h-1.035c-5.571 0-10.426-3.79-11.778-9.194-1.19-4.754-2.68-10.71-2.68-10.71-.603-2.409.863-4.854 3.272-5.457.293-.074.586-.116.877-.131-.004-2.126 1.507-4.021 3.671-4.427 1.103-.207 2.187.009 3.087.532z"
id="path9" />
<path
d="m13 4.493c.002-.313.059-.622.173-.913.189-.478.526-.891.955-1.173.211-.14.444-.247.688-.316.263-.075.539-.106.813-.092.279.015.556.076.816.182.288.118.554.291.779.506.233.221.422.488.555.781.146.323.219.673.221 1.028v8.689.315c.001.067.013.133.039.195.081.191.279.315.487.304.058-.003.115-.016.169-.038.055-.024.106-.058.15-.099.046-.044.084-.098.111-.156.029-.065.043-.135.044-.206v-3.812l.949-3.794c.334-1.339 1.693-2.154 3.031-1.819 1.339.334 2.154 1.693 1.819 3.031l-2.799 11.198v1.449l2.879-2.878c1.17-1.171 3.071-1.171 4.242 0s1.171 3.072 0 4.242c0 0-3.608 3.609-5.979 5.98-1.859 1.859-4.38 2.903-7.009 2.903h-.133v-.004h-1.039c-4.65 0-8.705-3.163-9.836-7.674-1.193-4.755-2.687-10.714-2.687-10.714-.336-1.338.478-2.697 1.817-3.033.664-.166 1.333-.05 1.879.273l1.123 6.734c.012.07.038.137.077.196.036.053.082.1.135.136.05.034.106.058.165.072.056.014.115.017.173.011.206-.024.381-.178.429-.381.016-.065.017-.132.007-.198l-1.554-9.324c.01-.062.023-.124.038-.185.076-.312.213-.609.401-.87.182-.253.411-.471.673-.64.236-.152.496-.264.769-.329.266-.064.543-.085.815-.06.253.023.501.085.735.183.473.199.881.543 1.154.978.167.266.28.56.339.868l.387 2.062v5.899c.001.067.013.133.039.195.081.191.279.315.487.304.058-.003.115-.016.169-.038.055-.024.106-.058.15-.099.046-.044.084-.098.111-.156.029-.065.043-.135.044-.206z"
fill="#00e2d7"
id="path11" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB