Compare commits
3 commits
5e64e9ea1b
...
fa0b826c26
Author | SHA1 | Date | |
---|---|---|---|
fa0b826c26 | |||
969cdc938d | |||
43af72aa4d |
11 changed files with 185 additions and 178 deletions
2
Makefile
2
Makefile
|
@ -50,7 +50,7 @@ $(BUILDDIR)/%: $(TMPDIR)/%
|
||||||
|
|
||||||
$(TMPDIR)/%.js: %.ts
|
$(TMPDIR)/%.js: %.ts
|
||||||
echo "[tsc] "$@
|
echo "[tsc] "$@
|
||||||
tsc --strict --noEmitOnError \
|
tsc --strict --noUncheckedIndexedAccess --noEmitOnError \
|
||||||
--lib dom,es2021 --target es2015 \
|
--lib dom,es2021 --target es2015 \
|
||||||
--outDir $(dir $@) $^
|
--outDir $(dir $@) $^
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
|
||||||
<meta property=og:title content="$title">
|
<meta property=og:title content="$title">
|
||||||
<meta property=og:site_name content="$title">
|
<meta property=og:site_name content="$title">
|
||||||
<meta property=og:description content="$desc">
|
<meta property=og:description content="$desc">
|
||||||
<meta property=og:image content="$url/$imagepath0">
|
<meta property=og:image content="$url/style/card.png">
|
||||||
<meta property=og:url content="$url">
|
<meta property=og:url content="$url">
|
||||||
<meta name=twitter:site content=@2_gecs>
|
<meta name=twitter:site content=@2_gecs>
|
||||||
<meta name=twitter:card content=summary>
|
<meta name=twitter:card content=summary>
|
||||||
|
@ -108,9 +108,6 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
|
||||||
nsfw = filters.nsfw /= NoNsfw
|
nsfw = filters.nsfw /= NoNsfw
|
||||||
|
|
||||||
url = [b|$root/$prefix|]
|
url = [b|$root/$prefix|]
|
||||||
imagepath0
|
|
||||||
| (_, (p₀, i₀) : _) : _ <- infosByYear = getThumb (takeDirectory p₀) i₀
|
|
||||||
| otherwise = "/style/card.png"
|
|
||||||
|
|
||||||
nsfw' = NsfwWarning.Gallery <$ guard nsfw
|
nsfw' = NsfwWarning.Gallery <$ guard nsfw
|
||||||
nsfwScript = NsfwWarning.script nsfw'
|
nsfwScript = NsfwWarning.script nsfw'
|
||||||
|
|
|
@ -13,6 +13,7 @@ module Info
|
||||||
CompareKey (..), compareKeyFor, compareFor, sortFor,
|
CompareKey (..), compareKeyFor, compareFor, sortFor,
|
||||||
|
|
||||||
Artist (..), Images' (..), Images, Image (..), Desc (..), DescField (..),
|
Artist (..), Images' (..), Images, Image (..), Desc (..), DescField (..),
|
||||||
|
PreviewImage (..), previewImage,
|
||||||
|
|
||||||
Link (..), Update (..), Bg (..),
|
Link (..), Update (..), Bg (..),
|
||||||
|
|
||||||
|
@ -117,6 +118,13 @@ data Images' a =
|
||||||
|
|
||||||
type Images = Images' Image
|
type Images = Images' Image
|
||||||
|
|
||||||
|
data PreviewImage = PFull Image | PThumb FilePath
|
||||||
|
|
||||||
|
previewImage :: Info -> Maybe PreviewImage
|
||||||
|
previewImage info
|
||||||
|
| Just img <- find (.sfw) $ allImages info.images = Just $ PFull img
|
||||||
|
| otherwise = PThumb <$> info.thumb'
|
||||||
|
|
||||||
|
|
||||||
data Link =
|
data Link =
|
||||||
Link {
|
Link {
|
||||||
|
@ -261,8 +269,7 @@ newtype NoThumb = NoThumb FilePath
|
||||||
instance Show NoThumb where show (NoThumb dir) = "no thumbnail for " ++ dir
|
instance Show NoThumb where show (NoThumb dir) = "no thumbnail for " ++ dir
|
||||||
|
|
||||||
getThumb :: FilePath -> Info -> FilePath
|
getThumb :: FilePath -> Info -> FilePath
|
||||||
getThumb dir =
|
getThumb dir = maybe (throw $ NoThumb dir) (\t -> dir </> thumbFile t) . thumb
|
||||||
maybe (throw $ NoThumb dir) (\t -> dir </> thumbFile t) . thumb
|
|
||||||
|
|
||||||
thumbFile :: FilePath -> FilePath
|
thumbFile :: FilePath -> FilePath
|
||||||
thumbFile = addSuffix "_small"
|
thumbFile = addSuffix "_small"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Data.List (intersperse)
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
import Data.Text.Lazy (Text)
|
import Data.Text.Lazy (Text)
|
||||||
import Data.Text.Lazy.Builder (toLazyText)
|
import Data.Text.Lazy.Builder (toLazyText)
|
||||||
|
import qualified Data.Text as Strict
|
||||||
import qualified Data.Text.Lazy.IO as Text
|
import qualified Data.Text.Lazy.IO as Text
|
||||||
import qualified Data.YAML as YAML
|
import qualified Data.YAML as YAML
|
||||||
import System.FilePath (makeRelative, takeDirectory, takeFileName)
|
import System.FilePath (makeRelative, takeDirectory, takeFileName)
|
||||||
|
@ -56,7 +57,7 @@ main2 (SinglePage {root, file, prefix, index, dataDir, nsfw, output}) = do
|
||||||
writeOutput output page
|
writeOutput output page
|
||||||
|
|
||||||
main2 (GalleryPage {root, files, prefix, index, output, dataDir}) = do
|
main2 (GalleryPage {root, files, prefix, index, output, dataDir}) = do
|
||||||
ginfo <- galleryFromIndex index prefix
|
(_, ginfo) <- galleryFromIndex index prefix
|
||||||
printV $ "gallery_info" := ginfo
|
printV $ "gallery_info" := ginfo
|
||||||
infos <- mapM (infoYAML dataDir) files
|
infos <- mapM (infoYAML dataDir) files
|
||||||
printV $ "infos" := infos
|
printV $ "infos" := infos
|
||||||
|
@ -70,12 +71,12 @@ main2 (IndexPage {root, file, output}) = do
|
||||||
writeOutput output page
|
writeOutput output page
|
||||||
|
|
||||||
main2 (RSS {files, root, index, prefix, output, dataDir}) = do
|
main2 (RSS {files, root, index, prefix, output, dataDir}) = do
|
||||||
ginfo <- galleryFromIndex index prefix
|
(name, ginfo) <- galleryFromIndex index prefix
|
||||||
printV $ "gallery_info" := ginfo
|
printV $ "gallery_info" := ginfo
|
||||||
infos <- mapM (infoYAML dataDir) files
|
infos <- mapM (infoYAML dataDir) files
|
||||||
printV $ "infos" := infos
|
printV $ "infos" := infos
|
||||||
let output' = takeFileName <$> output
|
let output' = takeFileName <$> output
|
||||||
let rss = RSS.make root ginfo output' infos
|
let rss = RSS.make root name ginfo output' infos
|
||||||
writeOutput output rss
|
writeOutput output rss
|
||||||
|
|
||||||
main2 (DependSingle {index, file, nsfw, output, prefix, buildDir, dataDir}) = do
|
main2 (DependSingle {index, file, nsfw, output, prefix, buildDir, dataDir}) = do
|
||||||
|
@ -117,10 +118,10 @@ findInfos dataDir infoName =
|
||||||
readYAML :: YAML.FromYAML a => FilePath -> IO a
|
readYAML :: YAML.FromYAML a => FilePath -> IO a
|
||||||
readYAML file = ByteString.readFile file >>= decode1Must file
|
readYAML file = ByteString.readFile file >>= decode1Must file
|
||||||
|
|
||||||
galleryFromIndex :: FilePath -> FilePath -> IO GalleryInfo
|
galleryFromIndex :: FilePath -> FilePath -> IO (Strict.Text, GalleryInfo)
|
||||||
galleryFromIndex file prefix = do
|
galleryFromIndex file prefix = do
|
||||||
IndexInfo {galleries} <- readYAML file
|
IndexInfo {title, galleries} <- readYAML file
|
||||||
maybe (fail $ "no gallery with prefix " ++ prefix) pure $
|
maybe (fail $ "no gallery with prefix " ++ prefix) (pure . (title,)) $
|
||||||
List.find (\g -> g.prefix == prefix) galleries
|
List.find (\g -> g.prefix == prefix) galleries
|
||||||
|
|
||||||
decode1Must :: YAML.FromYAML a => FilePath -> ByteString -> IO a
|
decode1Must :: YAML.FromYAML a => FilePath -> ByteString -> IO a
|
||||||
|
|
|
@ -17,27 +17,15 @@ script (Just _) = [b|<script src=/script/nsfw-warning.js type=module></script>|]
|
||||||
dialog :: Maybe What -> Builder
|
dialog :: Maybe What -> Builder
|
||||||
dialog Nothing = ""
|
dialog Nothing = ""
|
||||||
dialog (Just what) = [b|@0
|
dialog (Just what) = [b|@0
|
||||||
<div class=dialog id=nsfw-dialog>
|
<dialog id=nsfw-dialog>
|
||||||
<div class=dialog-inner>
|
|
||||||
<h1>cw: lewd art</h1>
|
<h1>cw: lewd art</h1>
|
||||||
|
<img src=/style/stop_hand.svg>
|
||||||
<img class=dialog-icon src=/style/stop_hand.svg>
|
<div> you must be an adult to view $what. no minors! </div>
|
||||||
|
<form>
|
||||||
<div class=dialog-message>
|
|
||||||
<p>
|
|
||||||
$what contains pornographic content that is
|
|
||||||
<strong>not suitable for minors</strong>.
|
|
||||||
<p>
|
|
||||||
by continuing, you are confirming that you are at least
|
|
||||||
<strong>eighteen years old</strong>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=dialog-buttons>
|
|
||||||
<button id=nsfw-yes class=yes>i am an adult</button>
|
<button id=nsfw-yes class=yes>i am an adult</button>
|
||||||
<a href=//crouton.net referrerpolicy=no-referrer>
|
<a href=//crouton.net referrerpolicy=no-referrer>
|
||||||
<button id=nsfw-no class=no>i am not</button>
|
<button id=nsfw-no class=no>i am not</button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
|
||||||
|]
|
|]
|
||||||
|
|
|
@ -4,8 +4,8 @@ import Date
|
||||||
import Info
|
import Info
|
||||||
import BuilderQQ
|
import BuilderQQ
|
||||||
|
|
||||||
import Data.List (sortBy)
|
import Data.List (sortBy, intersperse)
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (catMaybes)
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
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
|
||||||
|
@ -13,20 +13,21 @@ import System.FilePath (takeDirectory)
|
||||||
|
|
||||||
|
|
||||||
make :: Strict.Text -- ^ website root e.g. @https://gallery.niss.website@
|
make :: Strict.Text -- ^ website root e.g. @https://gallery.niss.website@
|
||||||
|
-> Strict.Text -- ^ website name e.g. @nissart@
|
||||||
-> GalleryInfo
|
-> GalleryInfo
|
||||||
-> Maybe FilePath -- ^ output filename for self link
|
-> Maybe FilePath -- ^ output filename for self link
|
||||||
-> [(FilePath, Info)]
|
-> [(FilePath, Info)]
|
||||||
-> Lazy.Text
|
-> Lazy.Text
|
||||||
make root ginfo output infos =
|
make root name ginfo output infos =
|
||||||
toLazyText $ make' root ginfo output infos
|
toLazyText $ make' root name ginfo output infos
|
||||||
|
|
||||||
make' :: Strict.Text -> GalleryInfo
|
make' :: Strict.Text -> Strict.Text -> GalleryInfo
|
||||||
-> Maybe FilePath -> [(FilePath, Info)] -> Builder
|
-> Maybe FilePath -> [(FilePath, Info)] -> Builder
|
||||||
make' root ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|@0
|
make' root name ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|@0
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
<rss version="2.0">
|
||||||
<channel>
|
<channel>
|
||||||
<title>$title</title>
|
<title>$name—$title</title>
|
||||||
<link>$link</link>
|
<link>$link</link>
|
||||||
<description>$desc</description>
|
<description>$desc</description>
|
||||||
$selflink
|
$selflink
|
||||||
|
@ -43,37 +44,54 @@ make' root ginfo@(GalleryInfo {title, desc, prefix}) output infos = [b|@0
|
||||||
filter (not . (.unlisted) . snd) infos
|
filter (not . (.unlisted) . snd) infos
|
||||||
selflink = case output of
|
selflink = case output of
|
||||||
Nothing -> ""
|
Nothing -> ""
|
||||||
Just o -> [b|<atom:link href="$link/$o" rel="self" />|]
|
Just o -> [b|<link href="$link/$o" rel="self" />|]
|
||||||
|
|
||||||
makeItem :: Strict.Text -> FilePath -> Bool -> FilePath -> Info -> Builder
|
makeItem :: Strict.Text -> FilePath -> Bool -> FilePath -> Info -> Builder
|
||||||
makeItem root prefix nsfw path i@(Info {title, artist}) = [b|@4
|
makeItem root prefix nsfw path i@(Info {title, artist}) = [b|@4
|
||||||
<item>
|
<item>
|
||||||
<title>$title$up</title>
|
<title>$title$suf</title>
|
||||||
<link>$link</link>
|
<link>$link</link>
|
||||||
<guid>$link</guid>
|
<guid>$link</guid>
|
||||||
$descArtist'
|
$body
|
||||||
<pubDate>$date</pubDate>
|
<pubDate>$date</pubDate>
|
||||||
</item>
|
</item>
|
||||||
|]
|
|]
|
||||||
where
|
where
|
||||||
up = if hasUpdatesFor nsfw i then [b| (updated)|] else ""
|
suf = let parts = catMaybes [o18, cnt, up] in
|
||||||
|
if null parts then ""
|
||||||
|
else " (" <> mconcat (intersperse ", " parts) <> ")"
|
||||||
|
up = if hasUpdatesFor nsfw i then Just "updated" else Nothing
|
||||||
|
o18 = if nsfw && anyNsfw i then Just "🔞" else Nothing
|
||||||
|
cnt = let len = maybe 0 length $ allImages <$> imagesFor nsfw i in
|
||||||
|
if len == 1 then Nothing else Just [b|$len images|]
|
||||||
|
|
||||||
dir = takeDirectory path
|
dir = takeDirectory path
|
||||||
link = [b|$root/$prefix/$dir|]
|
link = [b|$root/$prefix/$dir|]
|
||||||
|
|
||||||
|
date = formatRSS $ latestDateFor nsfw i
|
||||||
artist' = ifJust artist \case
|
artist' = ifJust artist \case
|
||||||
Artist {name, url = Nothing} -> [b|<p>by $name|]
|
Artist {name, url = Nothing} -> [b|<p>by $name|]
|
||||||
Artist {name, url = Just url} -> [b|<p>by <a href=$url>$name</a>|]
|
Artist {name, url = Just url} -> [b|<p>by <a href="$url">$name</a>|]
|
||||||
desc = descFor nsfw i
|
desc = descFor nsfw i
|
||||||
desc' = makeDesc desc
|
desc' = makeDesc desc
|
||||||
descArtist' = if desc.exists || isJust artist then [b|@6
|
|
||||||
<description>
|
body = [b|@6
|
||||||
<![CDATA[
|
<description> <![CDATA[
|
||||||
$10.artist'
|
$8.image
|
||||||
$10.desc'
|
$8.artist'
|
||||||
]]>
|
$8.desc'
|
||||||
</description>
|
]]> </description>
|
||||||
|
|]
|
||||||
|
|
||||||
|
image = case previewImage i of
|
||||||
|
Just (PFull img) -> go $ pageFile img
|
||||||
|
Just (PThumb th) -> go $ thumbFile th
|
||||||
|
Nothing -> ""
|
||||||
|
where go p = [b|@0
|
||||||
|
<figure>
|
||||||
|
<a href="$link"><img src="$link/$p"></a>
|
||||||
|
</figure>
|
||||||
|]
|
|]
|
||||||
else ""
|
|
||||||
date = formatRSS $ latestDateFor nsfw i
|
|
||||||
|
|
||||||
makeDesc :: Desc -> Builder
|
makeDesc :: Desc -> Builder
|
||||||
makeDesc NoDesc = ""
|
makeDesc NoDesc = ""
|
||||||
|
|
|
@ -9,7 +9,7 @@ import qualified NsfwWarning
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Data.List (sort, intersperse)
|
import Data.List (sort, intersperse)
|
||||||
import Data.Maybe (fromMaybe, isNothing, isJust)
|
import Data.Maybe (fromMaybe, isJust)
|
||||||
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 System.FilePath (joinPath, splitPath)
|
import System.FilePath (joinPath, splitPath)
|
||||||
|
@ -94,7 +94,6 @@ make' root siteName prefix nsfw _dataDir dir
|
||||||
let desc = case artist of
|
let desc = case artist of
|
||||||
Just (Artist {name}) -> [b|by $name|]
|
Just (Artist {name}) -> [b|by $name|]
|
||||||
Nothing -> "by niss"
|
Nothing -> "by niss"
|
||||||
let thumbnail = getThumb "" info
|
|
||||||
|
|
||||||
let updateDate = ifJust (last' updates) \(d, _) ->
|
let updateDate = ifJust (last' updates) \(d, _) ->
|
||||||
let updated = formatLong d in
|
let updated = formatLong d in
|
||||||
|
@ -104,15 +103,17 @@ make' root siteName prefix nsfw _dataDir dir
|
||||||
let nsfwScript = NsfwWarning.script nsfw'
|
let nsfwScript = NsfwWarning.script nsfw'
|
||||||
let nsfwDialog = NsfwWarning.dialog nsfw'
|
let nsfwDialog = NsfwWarning.dialog nsfw'
|
||||||
|
|
||||||
let imageMeta =
|
let imageMeta = case previewImage info of
|
||||||
if image0.sfw && isNothing image0.warning then [b|@0
|
Just (PFull (Image {path})) -> [b|@0
|
||||||
<meta property=og:image content="$url/$path0'">
|
<meta property=og:image content="$url/$path">
|
||||||
<meta name=twitter:card content=summary_large_image>
|
<meta name=twitter:card content=summary_large_image>
|
||||||
<meta name=twitter:image content="$url/$path0'">
|
<meta name=twitter:image content="$url/$path">
|
||||||
|] else [b|@0
|
|]
|
||||||
<meta property=og:image content="$url/$thumbnail">
|
Just (PThumb path) -> [b|@0
|
||||||
|
<meta property=og:image content="$url/$path">
|
||||||
<meta name=twitter:card content=summary>
|
<meta name=twitter:card content=summary>
|
||||||
|]
|
|]
|
||||||
|
Nothing -> throw $ NoThumb dir
|
||||||
|
|
||||||
pure [b|@0
|
pure [b|@0
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
|
@ -106,23 +106,30 @@ function makeFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Shortcuts = { [short: string]: Set<string> };
|
||||||
|
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')
|
||||||
|
};
|
||||||
|
|
||||||
function useFragment() {
|
function useFragment() {
|
||||||
const frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
const frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
||||||
const details = document.getElementById('filters-details') as HTMLDetailsElement;
|
const details = document.getElementById('filters-details') as HTMLDetailsElement;
|
||||||
|
const fromShortcut = shortcuts[frag];
|
||||||
|
|
||||||
if (!frag) {
|
if (!frag) {
|
||||||
clearForm();
|
clearForm();
|
||||||
} else if (frag == 'all') {
|
} else if (frag == 'all') {
|
||||||
allBoxes.forEach(b => b.checked = false);
|
allBoxes.forEach(b => b.checked = false);
|
||||||
details.open = false;
|
details.open = false;
|
||||||
|
} else if (fromShortcut) {
|
||||||
|
allBoxes.forEach(b => b.checked = fromShortcut.has(b.id));
|
||||||
} else {
|
} else {
|
||||||
const pieces =
|
const pieces = frag.split(';');
|
||||||
frag == 'summary' ? ['require_artsummary'] :
|
|
||||||
frag == 'colourexamples' ? ['require_colourexample'] :
|
|
||||||
frag == 'flatexamples' ? ['require_flatexample'] :
|
|
||||||
frag == 'sketchexamples' ? ['require_sketchexample'] :
|
|
||||||
frag == 'iconexamples' ? ['require_iconexample'] :
|
|
||||||
frag == 'curated' ? ['require_curated'] : frag.split(';');
|
|
||||||
const set = new Set(pieces);
|
const set = new Set(pieces);
|
||||||
const re = /^(require|exclude)_|hide_filters/;
|
const re = /^(require|exclude)_|hide_filters/;
|
||||||
if (pieces.every(x => re.test(x))) {
|
if (pieces.every(x => re.test(x))) {
|
||||||
|
@ -154,7 +161,7 @@ function sortFilters(cmp: (a: Node, b: Node) => number) {
|
||||||
function sortFiltersAlpha(e: Event) {
|
function sortFiltersAlpha(e: Event) {
|
||||||
function getName(node: Node): string {
|
function getName(node: Node): string {
|
||||||
if (node instanceof Element) {
|
if (node instanceof Element) {
|
||||||
return node.getElementsByTagName('input')[0].value;
|
return node.getElementsByTagName('input')[0]?.value ?? '';
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -164,9 +171,9 @@ function sortFiltersAlpha(e: Event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortFiltersUses(e: Event) {
|
function sortFiltersUses(e: Event) {
|
||||||
function getUses(node: Node) {
|
function getUses(node: Node): number {
|
||||||
if (node instanceof Element) {
|
if (node instanceof Element) {
|
||||||
const countStr = node.getElementsByTagName('label')[0].dataset.count;
|
const countStr = node.getElementsByTagName('label')[0]?.dataset.count;
|
||||||
return countStr ? +countStr : 0;
|
return countStr ? +countStr : 0;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
const nsfwOk = 'nsfw-ok';
|
const nsfwOk = 'nsfw-ok';
|
||||||
|
const dialog = document.getElementById('nsfw-dialog')! as HTMLDialogElement;
|
||||||
function dismiss() {
|
|
||||||
const dialog = document.getElementById('nsfw-dialog')!;
|
|
||||||
dialog.parentElement!.removeChild(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
function yes() {
|
function yes() {
|
||||||
localStorage.setItem(nsfwOk, '1');
|
localStorage.setItem(nsfwOk, '1');
|
||||||
dismiss();
|
dialog.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
if (localStorage.getItem(nsfwOk)) {
|
if (!localStorage.getItem(nsfwOk)) {
|
||||||
dismiss();
|
(dialog.querySelector('#nsfw-yes') as HTMLElement).onclick = yes;
|
||||||
} else {
|
|
||||||
document.getElementById('nsfw-yes')!.onclick = yes;
|
|
||||||
// nsfw-no is a normal link
|
// nsfw-no is a normal link
|
||||||
|
|
||||||
|
dialog.showModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,22 @@
|
||||||
.dialog {
|
dialog {
|
||||||
position: fixed;
|
&[open] {
|
||||||
top: 0; left: 0;
|
&::backdrop {
|
||||||
width: 100vw; height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
|
|
||||||
background: hsl(340deg, 35%, 15%, 90%);
|
background: hsl(340deg, 35%, 15%, 90%);
|
||||||
color: var(--text-col);
|
mix-blend-mode: multiply;
|
||||||
display: grid;
|
}
|
||||||
}
|
~ .page { filter: blur(15px); }
|
||||||
|
|
||||||
.dialog ~ .page {
|
|
||||||
filter: blur(15px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-inner {
|
|
||||||
place-self: center;
|
place-self: center;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template:
|
grid-template:
|
||||||
"header header"
|
"icon header"
|
||||||
"icon text"
|
"icon text"
|
||||||
"buttons buttons"
|
"icon buttons"
|
||||||
/ 1fr 3fr;
|
/ 1fr 3fr;
|
||||||
grid-gap: 0.5em;
|
gap: 0.5em 1.5em;
|
||||||
align-items: center;
|
place-items: center;
|
||||||
|
place-content: center;
|
||||||
|
|
||||||
min-height: 20vh;
|
min-height: 20vh;
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
|
@ -33,42 +25,40 @@
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
border: var(--border);
|
border: var(--border);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
}
|
box-shadow: 0 0 50px #fff6;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog h1 {
|
color: var(--text-col);
|
||||||
|
|
||||||
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
justify-self: center;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-icon {
|
img {
|
||||||
height: 3em;
|
|
||||||
width: 3em;
|
|
||||||
grid-area: icon;
|
grid-area: icon;
|
||||||
justify-self: center;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-message {
|
div {
|
||||||
grid-area: text;
|
grid-area: text;
|
||||||
justify-self: start;
|
text-align: center;
|
||||||
font-size: 125%;
|
font-size: 125%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-buttons {
|
form {
|
||||||
grid-area: buttons;
|
grid-area: buttons;
|
||||||
justify-self: center;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-buttons > * {
|
> * {
|
||||||
margin: 0 1em;
|
margin: 0 1em;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dialog button {
|
button {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.75em;
|
border-radius: 0.75em;
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
@ -81,30 +71,31 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
.dialog button a {
|
a {
|
||||||
inset: 0;
|
inset: 0;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dialog .yes {
|
.yes {
|
||||||
background: hsl(100deg, 70%, 80%);
|
background: hsl(100deg, 70%, 80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog .no {
|
.no {
|
||||||
background: hsl(5deg, 70%, 80%);
|
background: hsl(5deg, 70%, 80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog p {
|
p {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
-ms-hyphens: none;
|
-ms-hyphens: none;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog strong {
|
strong {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (pointer: coarse) {
|
@media (pointer: coarse) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
"noEmitOnError": true,
|
"noEmitOnError": true,
|
||||||
"lib": ["ES2021", "dom"],
|
"lib": ["ES2021", "dom"],
|
||||||
"target": "ES2015"
|
"target": "ES2015"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue