30 Commits

Author SHA1 Message Date
559ff6a7b3 version bump 2025-09-28 15:45:59 +02:00
3e3bb67884 fixed wrong preload on filtering 2025-09-28 15:34:37 +02:00
d0935a474f forgot the debug timeout 2025-09-25 14:32:11 +02:00
a57bc8e3b5 added loader to imagelist 2025-09-25 14:27:12 +02:00
08622bd092 added non breaking space 2025-09-15 13:19:45 +02:00
a8b2df43bd moved item name replace 2025-08-20 08:42:35 +02:00
b249ae9d46 patched fotoswipe to use searchParams instead of the wrong and stupid hash 2025-08-18 23:04:58 +02:00
b4badfbd15 replaced with URL 2025-08-18 14:21:21 +02:00
cb0fe96654 added pathname 2025-08-18 14:18:18 +02:00
6b04b75314 test window.location object use 2025-08-18 13:28:14 +02:00
6076b5f6f2 updated requirements.txt 2025-07-09 11:45:22 +02:00
5036ff79f7 hotfix 2025-07-06 17:34:26 +02:00
50ca8ab5bf fixed reset not unchecking recursive 2025-07-05 22:50:11 +02:00
3f427dfa32 moved javascript to global file, added js minifier and html formatter 2025-07-05 00:54:17 +02:00
9b7c3dc697 added --reread-sidecar option 2025-07-02 13:35:42 +02:00
c732b49339 ui improvements 2025-06-30 00:18:51 +02:00
9829a74f95 hotfix symbols in URL issue 2025-06-29 19:34:34 +02:00
372b960261 fixed selection of partial matching tags 2025-06-29 12:54:40 +02:00
c671c2a4bc fixed double showing of recursive filtered items 2025-06-27 23:48:21 +02:00
8088b2e69c sort reintroduced 2025-06-27 13:29:56 +02:00
e4d63de680 recursive sharable link 2025-06-27 11:32:03 +02:00
0e8287e4a8 more percentencode 2025-06-27 09:09:05 +02:00
48950d1d82 fixed url flicker 2025-06-27 00:18:46 +02:00
e1d74c3091 hm... 2025-06-27 00:03:35 +02:00
f57d81f508 hotfix 2025-06-26 23:21:01 +02:00
67a9058b7d well then... recursive filtering works :) 2025-06-26 22:00:03 +02:00
79e34d7e43 hierarchical tagging selection 2025-06-26 13:36:02 +02:00
0cda1706fa added selected tags after hash in url 2025-06-25 22:37:42 +02:00
85467f4f1e remove st tag 2025-06-24 19:45:41 +02:00
00ccb96581 moved functions around 2025-06-24 16:22:33 +02:00
54 changed files with 5782 additions and 568 deletions

10
.hintrc
View File

@@ -3,6 +3,14 @@
"development"
],
"hints": {
"apple-touch-icons": "off"
"apple-touch-icons": "off",
"compat-api/css": [
"default",
{
"ignore": [
"-webkit-app-region"
]
}
]
}
}

View File

@@ -1 +1 @@
2.7.3
2.8.5

View File

@@ -55,6 +55,7 @@ The script supports several command-line options to customize its behavior. Belo
- `--ignore-other-files`: Ignore files that do not match the specified extensions.
- `--regenerate-thumbnails`: Regenerate thumbnails even if they already exist.
- `--reread-metadata`: Reread image metadata if it already exists.
- `--reread-sidecar`: Reread sidecar file data.
- `--reverse-sort`: Sort images by reverse name order.
- `--theme-path PATH`: Specify the path to the CSS theme file. Default is the provided default theme.
- `--use-fancy-folders`: Enable fancy folder view instead of the default Apache directory listing.

View File

@@ -90,8 +90,9 @@
"Scans",
"--exclude-folder",
"*/Galleries/*",
"--folderthumbnails",
"--reread-metadata"
"--exclude-folder",
"*/Wallpaper/*",
"--folderthumbnails"
],
"console": "integratedTerminal",
"name": "production",
@@ -161,10 +162,12 @@
}
],
"prettier.htmlWhitespaceSensitivity": "css",
"pylint.args": [
"--disable=C0111",
"--disable=C0301",
"--good-names-rgxs=^[_a-z][_a-z0-9]?$"
"python-envs.pythonProjects": [
{
"path": "",
"envManager": "ms-python.python:pyenv",
"packageManager": "ms-python.python:pip"
}
],
"python.analysis.inlayHints.callArgumentNames": "off",
"python.analysis.inlayHints.functionReturnTypes": false,
@@ -257,6 +260,21 @@
"showReuseMessage": false,
"clear": true
}
},
{
"command": "COLUMNS=120 ./builder.py --generate-help-preview help.svg",
"isBackground": false,
"label": "Create help svg",
"problemMatcher": [],
"type": "shell",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "dedicated",
"showReuseMessage": false,
"clear": true
}
}
]
}

View File

@@ -11,6 +11,7 @@ from pathlib import Path
from tqdm.auto import tqdm
from PIL import Image, ImageOps
from jsmin import jsmin
from modules.argumentparser import parse_arguments, Args
@@ -123,6 +124,10 @@ def copy_static_files(_args: Args) -> None:
with open(os.path.join(static_dir, "theme.css"), "x", encoding="utf-8") as f:
logger.info("writing theme file")
f.write(themehead + '\n.foldericon {\n content: url("data:image/svg+xml,' + svg + '");\n}\n' + themetail)
logger.info("minifying javascript")
with open(os.path.join(SCRIPTDIR, "templates", "functionality.js"), "r", encoding="utf-8") as js_file:
with open(os.path.join(static_dir, "functionality.min.js"), "w+", encoding="utf-8") as min_file:
min_file.write(jsmin(js_file.read()))
def generate_thumbnail(arguments: tuple[str, str, str]) -> None:
@@ -169,7 +174,7 @@ def main(args) -> None:
try:
Path(lock_file).touch()
logger.info("starting builder", extra={"version": VERSION})
logger.info("starting builder", extra={"version": VERSION, "arguments": args})
logger.info("getting logo from sorogon.eu")
req = urllib.request.Request("https://files.sorogon.eu/logo.svg")

View File

@@ -66,6 +66,13 @@ body {
padding: 0 2px;
}
.centerload {
margin-top: 100px;
display: flex;
justify-content: center;
align-items: center;
}
figure {
margin: 0;
}
@@ -157,10 +164,31 @@ figure {
cursor: pointer;
}
.tooltip .tooltiptext {
display: none;
.tooltip a {
cursor: pointer;
}
.tagtoggle {
cursor: pointer;
float: right;
padding: 12px;
}
.tagflex {
display: flex;
}
.tag {
flex: 1;
}
input {
pointer-events: none;
}
.tooltiptext {
cursor: default;
width: max-content;
position: absolute;
z-index: 100;
opacity: 0;
@@ -172,33 +200,66 @@ figure {
.tooltip .infotext {
padding: 12px;
width: max-content;
}
.tooltip .tagdropdown {
.tooltiptext.tagdropdown {
width: max-content;
right: 0;
padding: 0;
margin: 0;
overflow: hidden;
transition: max-height 0.3s ease, opacity 0.3s ease;
max-height: 0;
opacity: 0;
}
.tooltip:hover .tooltiptext {
.tooltiptext.tagdropdown.show {
max-height: 80vh;
overflow-y: scroll;
opacity: 1;
}
.tooltip:hover .infotext {
display: block;
opacity: 1;
}
.tooltip:active .tooltiptext {
.tooltip:active .infotext {
display: block;
opacity: 1;
}
.tooltip .tooltiptext .tagentry {
.tagentryparent {
width: 100%;
overflow: hidden;
transition: max-height 0.3s ease, opacity 0.3s ease;
max-height: 0;
opacity: 0;
}
.tagentryparent.show {
max-height: 80vh;
opacity: 1;
overflow-y: scroll;
}
.tagentry {
list-style: none;
width: 100%;
cursor: pointer;
margin: 0;
padding: 0;
display: block;
}
.tooltip .tooltiptext ol {
margin-left: 0;
padding-left: 0.5em;
}
.tooltip .tooltiptext .tagentry label {
cursor: pointer;
width: 100%;
height: 100%;
padding: 12px;
display: block;

View File

@@ -35,8 +35,7 @@
transition: opacity 0.2s;
-webkit-box-shadow: none;
box-shadow: none; }
.pswp__button:focus,
.pswp__button:hover {
.pswp__button:focus, .pswp__button:hover {
opacity: 1; }
.pswp__button:active {
outline: none;
@@ -272,14 +271,13 @@ a.pswp__share--download:hover {
color: #BBB; }
.pswp__caption__center {
text-align: center;
text-align: left;
max-width: 420px;
margin: 0 auto;
font-size: 13px;
padding: 10px;
line-height: 20px;
color: #CCC;
font-weight: bold; }
color: #CCC; }
.pswp__caption--empty {
display: none; }

View File

@@ -1,131 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="264"
height="88"
viewBox="0 0 264 88"
version="1.1"
id="svg12"
sodipodi:docname="default-skin.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview12"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="true"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
showborder="true"
borderlayer="true"
inkscape:zoom="3.0855569"
inkscape:cx="95.606729"
inkscape:cy="65.142212"
inkscape:window-width="1896"
inkscape:window-height="1016"
inkscape:window-x="1932"
inkscape:window-y="52"
inkscape:window-maximized="1"
inkscape:current-layer="g11" />
<title
id="title1">default-skin 2</title>
<g
fill="none"
fill-rule="evenodd"
id="g12">
<g
id="g11">
<g
fill="#fff"
id="g1">
<path
d="M13 29v-5h2v3h3v2h-5zM13 15h5v2h-3v3h-2v-5zM31 15v5h-2v-3h-3v-2h5zM31 29h-5v-2h3v-3h2v5z"
id="path1" />
</g>
<g
fill="#fff"
id="g2">
<path
d="M62 24v5h-2v-3h-3v-2h5zM62 20h-5v-2h3v-3h2v5zM70 20v-5h2v3h3v2h-5zM70 24h5v2h-3v3h-2v-5z"
id="path2" />
</g>
<path
d="M20.586 66l-5.656-5.656 1.414-1.414L22 64.586l5.656-5.656 1.414 1.414L23.414 66l5.656 5.656-1.414 1.414L22 67.414l-5.656 5.656-1.414-1.414L20.586 66z"
fill="#fff"
id="path3" />
<path
d="M111.785 65.03L110 63.5l3-3.5h-10v-2h10l-3-3.5 1.785-1.468L117 59l-5.215 6.03z"
fill="#fff"
id="path4" />
<path
d="M152.215 65.03L154 63.5l-3-3.5h10v-2h-10l3-3.5-1.785-1.468L147 59l5.215 6.03z"
fill="#fff"
id="path5" />
<g
id="g6">
<path
id="Rectangle-11"
fill="#fff"
d="M160.957 28.543l-3.25-3.25-1.413 1.414 3.25 3.25z" />
<path
d="M152.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z"
id="Oval-1"
stroke="#fff"
stroke-width="1.5" />
<path
fill="#fff"
d="M150 21h5v1h-5z"
id="path6" />
</g>
<g
id="g10">
<path
d="M116.957 28.543l-1.414 1.414-3.25-3.25 1.414-1.414 3.25 3.25z"
fill="#fff"
id="path7" />
<path
d="M108.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z"
stroke="#fff"
stroke-width="1.5"
id="path8" />
<path
fill="#fff"
d="M106 21h5v1h-5z"
id="path9" />
<path
fill="#fff"
d="M109.043 19.008l-.085 5-1-.017.085-5z"
id="path10" />
</g>
<g
id="g14">
<path
id="Shape"
style="fill:#ffffff"
d="M 63.708984 57.572266 L 63.708984 66.917969 L 62.773438 66.917969 L 59.173828 66.917969 L 65.089844 72.916016 L 71.173828 66.917969 L 67.40625 66.917969 L 66.640625 66.917969 L 66.640625 57.572266 L 63.708984 57.572266 z " />
<path
id="rect13"
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.649;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 56.24391,72.078606 v 3.51729 h 17.859837 v -3.51729 h -1.210961 v 2.324677 H 57.456705 v -2.324677 z" />
</g>
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>default-skin 2</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>
<svg width="264" height="88" viewBox="0 0 264 88" xmlns="http://www.w3.org/2000/svg"><title>default-skin 2</title><g fill="none" fill-rule="evenodd"><g><path d="M67.002 59.5v3.768c-6.307.84-9.184 5.75-10.002 9.732 2.22-2.83 5.564-5.098 10.002-5.098V71.5L73 65.585 67.002 59.5z" id="Shape" fill="#fff"/><g fill="#fff"><path d="M13 29v-5h2v3h3v2h-5zM13 15h5v2h-3v3h-2v-5zM31 15v5h-2v-3h-3v-2h5zM31 29h-5v-2h3v-3h2v5z" id="Shape"/></g><g fill="#fff"><path d="M62 24v5h-2v-3h-3v-2h5zM62 20h-5v-2h3v-3h2v5zM70 20v-5h2v3h3v2h-5zM70 24h5v2h-3v3h-2v-5z"/></g><path d="M20.586 66l-5.656-5.656 1.414-1.414L22 64.586l5.656-5.656 1.414 1.414L23.414 66l5.656 5.656-1.414 1.414L22 67.414l-5.656 5.656-1.414-1.414L20.586 66z" fill="#fff"/><path d="M111.785 65.03L110 63.5l3-3.5h-10v-2h10l-3-3.5 1.785-1.468L117 59l-5.215 6.03z" fill="#fff"/><path d="M152.215 65.03L154 63.5l-3-3.5h10v-2h-10l3-3.5-1.785-1.468L147 59l5.215 6.03z" fill="#fff"/><g><path id="Rectangle-11" fill="#fff" d="M160.957 28.543l-3.25-3.25-1.413 1.414 3.25 3.25z"/><path d="M152.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" id="Oval-1" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M150 21h5v1h-5z"/></g><g><path d="M116.957 28.543l-1.414 1.414-3.25-3.25 1.414-1.414 3.25 3.25z" fill="#fff"/><path d="M108.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M106 21h5v1h-5z"/><path fill="#fff" d="M109.043 19.008l-.085 5-1-.017.085-5z"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

View File

@@ -15,21 +15,14 @@
touch-action: none;
z-index: 1500;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
/* create separate layer, to avoid paint on window.onscroll in webkit/blink */
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
outline: none;
}
.pswp * {
outline: none; }
.pswp * {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.pswp img {
max-width: none;
}
box-sizing: border-box; }
.pswp img {
max-width: none; }
/* style is added when JS option showHideOpacity is set to true */
.pswp--animate_opacity {
@@ -38,33 +31,28 @@
will-change: opacity;
/* for open/close transition */
-webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
}
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); }
.pswp--open {
display: block;
}
display: block; }
.pswp--zoom-allowed .pswp__img {
/* autoprefixer: off */
cursor: -webkit-zoom-in;
cursor: -moz-zoom-in;
cursor: zoom-in;
}
cursor: zoom-in; }
.pswp--zoomed-in .pswp__img {
/* autoprefixer: off */
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
cursor: grab; }
.pswp--dragging .pswp__img {
/* autoprefixer: off */
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
cursor: grabbing; }
/*
Background is added as a separate element.
@@ -78,10 +66,10 @@
height: 100%;
background: #000;
opacity: 0;
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
will-change: opacity;
}
will-change: opacity; }
.pswp__scroll-wrap {
position: absolute;
@@ -89,8 +77,7 @@
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
overflow: hidden; }
.pswp__container,
.pswp__zoom-wrap {
@@ -100,8 +87,7 @@
left: 0;
right: 0;
top: 0;
bottom: 0;
}
bottom: 0; }
/* Prevent selection and tap highlights */
.pswp__container,
@@ -111,8 +97,7 @@
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
-webkit-touch-callout: none; }
.pswp__zoom-wrap {
position: absolute;
@@ -122,27 +107,22 @@
transform-origin: left top;
/* for open/close transition */
-webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
}
transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1); }
.pswp__bg {
will-change: opacity;
/* for open/close transition */
-webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
}
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); }
.pswp--animated-in .pswp__bg,
.pswp--animated-in .pswp__zoom-wrap {
-webkit-transition: none;
transition: none;
}
transition: none; }
.pswp__container,
.pswp__zoom-wrap {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
-webkit-backface-visibility: hidden; }
.pswp__item {
position: absolute;
@@ -150,40 +130,34 @@
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
overflow: hidden; }
.pswp__img {
position: absolute;
width: auto;
height: auto;
top: 0;
left: 0;
}
left: 0; }
/*
stretched thumbnail or div placeholder element (see below)
style is added to avoid flickering in webkit/blink when layers overlap
*/
.pswp__img--placeholder {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
-webkit-backface-visibility: hidden; }
/*
div element that matches size of large image
large image loads on top of it
*/
.pswp__img--placeholder--blank {
background: #222;
}
background: #222; }
.pswp--ie .pswp__img {
width: 100% !important;
height: auto !important;
left: 0;
top: 0;
}
top: 0; }
/*
Error message appears when image is not loaded
@@ -198,10 +172,8 @@
font-size: 14px;
line-height: 16px;
margin-top: -8px;
color: #CCC;
}
color: #CCC; }
.pswp__error-msg a {
color: #CCC;
text-decoration: underline;
}
text-decoration: underline; }

3788
files/pswp/photoswipe.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

168
help.svg
View File

@@ -1,4 +1,4 @@
<svg class="rich-terminal" viewBox="0 0 1482 855.1999999999999" xmlns="http://www.w3.org/2000/svg">
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -19,171 +19,183 @@
font-weight: 700;
}
.terminal-1308707172-matrix {
.terminal-3378394567-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
.terminal-1308707172-title {
.terminal-3378394567-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
.terminal-1308707172-r1 { fill: #ff8700 }
.terminal-1308707172-r2 { fill: #c5c8c6 }
.terminal-1308707172-r3 { fill: #808080 }
.terminal-1308707172-r4 { fill: #68a0b3 }
.terminal-1308707172-r5 { fill: #00af87 }
.terminal-3378394567-r1 { fill: #ff8700 }
.terminal-3378394567-r2 { fill: #c5c8c6 }
.terminal-3378394567-r3 { fill: #808080 }
.terminal-3378394567-r4 { fill: #68a0b3 }
.terminal-3378394567-r5 { fill: #00af87 }
</style>
<defs>
<clipPath id="terminal-1308707172-clip-terminal">
<rect x="0" y="0" width="1463.0" height="804.1999999999999" />
<clipPath id="terminal-3378394567-clip-terminal">
<rect x="0" y="0" width="1463.0" height="877.4" />
</clipPath>
<clipPath id="terminal-1308707172-line-0">
<clipPath id="terminal-3378394567-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-1">
<clipPath id="terminal-3378394567-line-1">
<rect x="0" y="25.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-2">
<clipPath id="terminal-3378394567-line-2">
<rect x="0" y="50.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-3">
<clipPath id="terminal-3378394567-line-3">
<rect x="0" y="74.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-4">
<clipPath id="terminal-3378394567-line-4">
<rect x="0" y="99.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-5">
<clipPath id="terminal-3378394567-line-5">
<rect x="0" y="123.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-6">
<clipPath id="terminal-3378394567-line-6">
<rect x="0" y="147.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-7">
<clipPath id="terminal-3378394567-line-7">
<rect x="0" y="172.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-8">
<clipPath id="terminal-3378394567-line-8">
<rect x="0" y="196.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-9">
<clipPath id="terminal-3378394567-line-9">
<rect x="0" y="221.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-10">
<clipPath id="terminal-3378394567-line-10">
<rect x="0" y="245.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-11">
<clipPath id="terminal-3378394567-line-11">
<rect x="0" y="269.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-12">
<clipPath id="terminal-3378394567-line-12">
<rect x="0" y="294.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-13">
<clipPath id="terminal-3378394567-line-13">
<rect x="0" y="318.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-14">
<clipPath id="terminal-3378394567-line-14">
<rect x="0" y="343.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-15">
<clipPath id="terminal-3378394567-line-15">
<rect x="0" y="367.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-16">
<clipPath id="terminal-3378394567-line-16">
<rect x="0" y="391.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-17">
<clipPath id="terminal-3378394567-line-17">
<rect x="0" y="416.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-18">
<clipPath id="terminal-3378394567-line-18">
<rect x="0" y="440.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-19">
<clipPath id="terminal-3378394567-line-19">
<rect x="0" y="465.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-20">
<clipPath id="terminal-3378394567-line-20">
<rect x="0" y="489.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-21">
<clipPath id="terminal-3378394567-line-21">
<rect x="0" y="513.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-22">
<clipPath id="terminal-3378394567-line-22">
<rect x="0" y="538.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-23">
<clipPath id="terminal-3378394567-line-23">
<rect x="0" y="562.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-24">
<clipPath id="terminal-3378394567-line-24">
<rect x="0" y="587.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-25">
<clipPath id="terminal-3378394567-line-25">
<rect x="0" y="611.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-26">
<clipPath id="terminal-3378394567-line-26">
<rect x="0" y="635.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-27">
<clipPath id="terminal-3378394567-line-27">
<rect x="0" y="660.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-28">
<clipPath id="terminal-3378394567-line-28">
<rect x="0" y="684.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-29">
<clipPath id="terminal-3378394567-line-29">
<rect x="0" y="709.1" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-30">
<clipPath id="terminal-3378394567-line-30">
<rect x="0" y="733.5" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-1308707172-line-31">
<clipPath id="terminal-3378394567-line-31">
<rect x="0" y="757.9" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-3378394567-line-32">
<rect x="0" y="782.3" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-3378394567-line-33">
<rect x="0" y="806.7" width="1464" height="24.65"/>
</clipPath>
<clipPath id="terminal-3378394567-line-34">
<rect x="0" y="831.1" width="1464" height="24.65"/>
</clipPath>
</defs>
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="853.2" rx="8"/>
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
<circle cx="44" cy="0" r="7" fill="#28c840"/>
</g>
<g transform="translate(9, 41)" clip-path="url(#terminal-1308707172-clip-terminal)">
<g transform="translate(9, 41)" clip-path="url(#terminal-3378394567-clip-terminal)">
<g class="terminal-1308707172-matrix">
<text class="terminal-1308707172-r1" x="0" y="20" textLength="73.2" clip-path="url(#terminal-1308707172-line-0)">Usage:</text><text class="terminal-1308707172-r3" x="85.4" y="20" textLength="122" clip-path="url(#terminal-1308707172-line-0)">builder.py</text><text class="terminal-1308707172-r2" x="207.4" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">&#160;[</text><text class="terminal-1308707172-r4" x="231.8" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-h</text><text class="terminal-1308707172-r2" x="256.2" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">]&#160;[</text><text class="terminal-1308707172-r4" x="292.8" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-a</text><text class="terminal-1308707172-r5" x="329.4" y="20" textLength="73.2" clip-path="url(#terminal-1308707172-line-0)">AUTHOR</text><text class="terminal-1308707172-r2" x="402.6" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">]&#160;[</text><text class="terminal-1308707172-r4" x="439.2" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-e</text><text class="terminal-1308707172-r5" x="475.8" y="20" textLength="109.8" clip-path="url(#terminal-1308707172-line-0)">EXTENSION</text><text class="terminal-1308707172-r2" x="585.6" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">]&#160;[</text><text class="terminal-1308707172-r4" x="622.2" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-l</text><text class="terminal-1308707172-r5" x="658.8" y="20" textLength="85.4" clip-path="url(#terminal-1308707172-line-0)">LICENSE</text><text class="terminal-1308707172-r2" x="744.2" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">]&#160;[</text><text class="terminal-1308707172-r4" x="780.8" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-m</text><text class="terminal-1308707172-r2" x="805.2" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">]&#160;[</text><text class="terminal-1308707172-r4" x="841.8" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-n</text><text class="terminal-1308707172-r2" x="866.2" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">]&#160;</text><text class="terminal-1308707172-r4" x="890.6" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-p</text><text class="terminal-1308707172-r5" x="927.2" y="20" textLength="48.8" clip-path="url(#terminal-1308707172-line-0)">ROOT</text><text class="terminal-1308707172-r4" x="988.2" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-t</text><text class="terminal-1308707172-r5" x="1024.8" y="20" textLength="61" clip-path="url(#terminal-1308707172-line-0)">TITLE</text><text class="terminal-1308707172-r4" x="1098" y="20" textLength="24.4" clip-path="url(#terminal-1308707172-line-0)">-w</text><text class="terminal-1308707172-r5" x="1134.6" y="20" textLength="36.6" clip-path="url(#terminal-1308707172-line-0)">URL</text><text class="terminal-1308707172-r2" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-1308707172-line-0)">
</text><text class="terminal-1308707172-r2" x="0" y="44.4" textLength="231.8" clip-path="url(#terminal-1308707172-line-1)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[</text><text class="terminal-1308707172-r4" x="231.8" y="44.4" textLength="195.2" clip-path="url(#terminal-1308707172-line-1)">--exclude-folder</text><text class="terminal-1308707172-r5" x="439.2" y="44.4" textLength="73.2" clip-path="url(#terminal-1308707172-line-1)">FOLDER</text><text class="terminal-1308707172-r2" x="512.4" y="44.4" textLength="36.6" clip-path="url(#terminal-1308707172-line-1)">]&#160;[</text><text class="terminal-1308707172-r4" x="549" y="44.4" textLength="244" clip-path="url(#terminal-1308707172-line-1)">--ignore-other-files</text><text class="terminal-1308707172-r2" x="793" y="44.4" textLength="36.6" clip-path="url(#terminal-1308707172-line-1)">]&#160;[</text><text class="terminal-1308707172-r4" x="829.6" y="44.4" textLength="280.6" clip-path="url(#terminal-1308707172-line-1)">--regenerate-thumbnails</text><text class="terminal-1308707172-r2" x="1110.2" y="44.4" textLength="36.6" clip-path="url(#terminal-1308707172-line-1)">]&#160;[</text><text class="terminal-1308707172-r4" x="1146.8" y="44.4" textLength="207.4" clip-path="url(#terminal-1308707172-line-1)">--reread-metadata</text><text class="terminal-1308707172-r2" x="1354.2" y="44.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-1)">]</text><text class="terminal-1308707172-r2" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-1)">
</text><text class="terminal-1308707172-r2" x="0" y="68.8" textLength="231.8" clip-path="url(#terminal-1308707172-line-2)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[</text><text class="terminal-1308707172-r4" x="231.8" y="68.8" textLength="170.8" clip-path="url(#terminal-1308707172-line-2)">--reverse-sort</text><text class="terminal-1308707172-r2" x="402.6" y="68.8" textLength="36.6" clip-path="url(#terminal-1308707172-line-2)">]&#160;[</text><text class="terminal-1308707172-r4" x="439.2" y="68.8" textLength="146.4" clip-path="url(#terminal-1308707172-line-2)">--theme-path</text><text class="terminal-1308707172-r5" x="597.8" y="68.8" textLength="48.8" clip-path="url(#terminal-1308707172-line-2)">PATH</text><text class="terminal-1308707172-r2" x="646.6" y="68.8" textLength="36.6" clip-path="url(#terminal-1308707172-line-2)">]&#160;[</text><text class="terminal-1308707172-r4" x="683.2" y="68.8" textLength="231.8" clip-path="url(#terminal-1308707172-line-2)">--use-fancy-folders</text><text class="terminal-1308707172-r2" x="915" y="68.8" textLength="36.6" clip-path="url(#terminal-1308707172-line-2)">]&#160;[</text><text class="terminal-1308707172-r4" x="951.6" y="68.8" textLength="109.8" clip-path="url(#terminal-1308707172-line-2)">--version</text><text class="terminal-1308707172-r2" x="1061.4" y="68.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-2)">]</text><text class="terminal-1308707172-r2" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-2)">
</text><text class="terminal-1308707172-r2" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-3)">
</text><text class="terminal-1308707172-r2" x="0" y="117.6" textLength="671" clip-path="url(#terminal-1308707172-line-4)">Generate&#160;HTML&#160;files&#160;for&#160;a&#160;static&#160;image&#160;hosting&#160;website.</text><text class="terminal-1308707172-r2" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-4)">
</text><text class="terminal-1308707172-r2" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-1308707172-line-5)">
</text><text class="terminal-1308707172-r1" x="0" y="166.4" textLength="97.6" clip-path="url(#terminal-1308707172-line-6)">Options:</text><text class="terminal-1308707172-r2" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-6)">
</text><text class="terminal-1308707172-r4" x="24.4" y="190.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-7)">-h</text><text class="terminal-1308707172-r2" x="48.8" y="190.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-7)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="190.8" textLength="73.2" clip-path="url(#terminal-1308707172-line-7)">--help</text><text class="terminal-1308707172-r2" x="292.8" y="190.8" textLength="378.2" clip-path="url(#terminal-1308707172-line-7)">show&#160;this&#160;help&#160;message&#160;and&#160;exit</text><text class="terminal-1308707172-r2" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-7)">
</text><text class="terminal-1308707172-r4" x="24.4" y="215.2" textLength="24.4" clip-path="url(#terminal-1308707172-line-8)">-a</text><text class="terminal-1308707172-r2" x="48.8" y="215.2" textLength="24.4" clip-path="url(#terminal-1308707172-line-8)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="215.2" textLength="158.6" clip-path="url(#terminal-1308707172-line-8)">--author-name</text><text class="terminal-1308707172-r5" x="244" y="215.2" textLength="73.2" clip-path="url(#terminal-1308707172-line-8)">AUTHOR</text><text class="terminal-1308707172-r2" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-8)">
</text><text class="terminal-1308707172-r2" x="292.8" y="239.6" textLength="402.6" clip-path="url(#terminal-1308707172-line-9)">Name&#160;of&#160;the&#160;author&#160;of&#160;the&#160;images.</text><text class="terminal-1308707172-r2" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-9)">
</text><text class="terminal-1308707172-r4" x="24.4" y="264" textLength="24.4" clip-path="url(#terminal-1308707172-line-10)">-e</text><text class="terminal-1308707172-r2" x="48.8" y="264" textLength="24.4" clip-path="url(#terminal-1308707172-line-10)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="264" textLength="207.4" clip-path="url(#terminal-1308707172-line-10)">--file-extensions</text><text class="terminal-1308707172-r5" x="292.8" y="264" textLength="109.8" clip-path="url(#terminal-1308707172-line-10)">EXTENSION</text><text class="terminal-1308707172-r2" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-1308707172-line-10)">
</text><text class="terminal-1308707172-r2" x="292.8" y="288.4" textLength="744.2" clip-path="url(#terminal-1308707172-line-11)">File&#160;extensions&#160;to&#160;include&#160;(can&#160;be&#160;specified&#160;multiple&#160;times).</text><text class="terminal-1308707172-r2" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-11)">
</text><text class="terminal-1308707172-r4" x="24.4" y="312.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-12)">-l</text><text class="terminal-1308707172-r2" x="48.8" y="312.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-12)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="312.8" textLength="170.8" clip-path="url(#terminal-1308707172-line-12)">--license-type</text><text class="terminal-1308707172-r5" x="256.2" y="312.8" textLength="85.4" clip-path="url(#terminal-1308707172-line-12)">LICENSE</text><text class="terminal-1308707172-r2" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-12)">
</text><text class="terminal-1308707172-r2" x="292.8" y="337.2" textLength="488" clip-path="url(#terminal-1308707172-line-13)">Specify&#160;the&#160;license&#160;type&#160;for&#160;the&#160;images.</text><text class="terminal-1308707172-r2" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-13)">
</text><text class="terminal-1308707172-r4" x="24.4" y="361.6" textLength="24.4" clip-path="url(#terminal-1308707172-line-14)">-m</text><text class="terminal-1308707172-r2" x="48.8" y="361.6" textLength="24.4" clip-path="url(#terminal-1308707172-line-14)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="361.6" textLength="170.8" clip-path="url(#terminal-1308707172-line-14)">--web-manifest</text><text class="terminal-1308707172-r2" x="292.8" y="361.6" textLength="353.8" clip-path="url(#terminal-1308707172-line-14)">Generate&#160;a&#160;web&#160;manifest&#160;file.</text><text class="terminal-1308707172-r2" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-14)">
</text><text class="terminal-1308707172-r4" x="24.4" y="386" textLength="24.4" clip-path="url(#terminal-1308707172-line-15)">-n</text><text class="terminal-1308707172-r2" x="48.8" y="386" textLength="24.4" clip-path="url(#terminal-1308707172-line-15)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="386" textLength="268.4" clip-path="url(#terminal-1308707172-line-15)">--non-interactive-mode</text><text class="terminal-1308707172-r2" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-1308707172-line-15)">
</text><text class="terminal-1308707172-r2" x="292.8" y="410.4" textLength="646.6" clip-path="url(#terminal-1308707172-line-16)">Run&#160;in&#160;non-interactive&#160;mode,&#160;disabling&#160;progress&#160;bars.</text><text class="terminal-1308707172-r2" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-16)">
</text><text class="terminal-1308707172-r4" x="24.4" y="434.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-17)">-p</text><text class="terminal-1308707172-r2" x="48.8" y="434.8" textLength="24.4" clip-path="url(#terminal-1308707172-line-17)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="434.8" textLength="195.2" clip-path="url(#terminal-1308707172-line-17)">--root-directory</text><text class="terminal-1308707172-r5" x="280.6" y="434.8" textLength="48.8" clip-path="url(#terminal-1308707172-line-17)">ROOT</text><text class="terminal-1308707172-r2" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-17)">
</text><text class="terminal-1308707172-r2" x="292.8" y="459.2" textLength="451.4" clip-path="url(#terminal-1308707172-line-18)">Root&#160;directory&#160;containing&#160;the&#160;images.</text><text class="terminal-1308707172-r2" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-18)">
</text><text class="terminal-1308707172-r4" x="24.4" y="483.6" textLength="24.4" clip-path="url(#terminal-1308707172-line-19)">-t</text><text class="terminal-1308707172-r2" x="48.8" y="483.6" textLength="24.4" clip-path="url(#terminal-1308707172-line-19)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="483.6" textLength="146.4" clip-path="url(#terminal-1308707172-line-19)">--site-title</text><text class="terminal-1308707172-r5" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-1308707172-line-19)">TITLE</text><text class="terminal-1308707172-r2" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-19)">
</text><text class="terminal-1308707172-r2" x="292.8" y="508" textLength="390.4" clip-path="url(#terminal-1308707172-line-20)">Title&#160;of&#160;the&#160;image&#160;hosting&#160;site.</text><text class="terminal-1308707172-r2" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-1308707172-line-20)">
</text><text class="terminal-1308707172-r4" x="24.4" y="532.4" textLength="24.4" clip-path="url(#terminal-1308707172-line-21)">-w</text><text class="terminal-1308707172-r2" x="48.8" y="532.4" textLength="24.4" clip-path="url(#terminal-1308707172-line-21)">,&#160;</text><text class="terminal-1308707172-r4" x="73.2" y="532.4" textLength="170.8" clip-path="url(#terminal-1308707172-line-21)">--web-root-url</text><text class="terminal-1308707172-r5" x="256.2" y="532.4" textLength="36.6" clip-path="url(#terminal-1308707172-line-21)">URL</text><text class="terminal-1308707172-r2" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-21)">
</text><text class="terminal-1308707172-r2" x="292.8" y="556.8" textLength="634.4" clip-path="url(#terminal-1308707172-line-22)">Base&#160;URL&#160;of&#160;the&#160;web&#160;root&#160;for&#160;the&#160;image&#160;hosting&#160;site.</text><text class="terminal-1308707172-r2" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-22)">
</text><text class="terminal-1308707172-r4" x="24.4" y="581.2" textLength="195.2" clip-path="url(#terminal-1308707172-line-23)">--exclude-folder</text><text class="terminal-1308707172-r5" x="231.8" y="581.2" textLength="73.2" clip-path="url(#terminal-1308707172-line-23)">FOLDER</text><text class="terminal-1308707172-r2" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-23)">
</text><text class="terminal-1308707172-r2" x="292.8" y="605.6" textLength="1049.2" clip-path="url(#terminal-1308707172-line-24)">Folders&#160;to&#160;exclude&#160;from&#160;processing,&#160;globs&#160;supported&#160;(can&#160;be&#160;specified&#160;multiple&#160;times).</text><text class="terminal-1308707172-r2" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-24)">
</text><text class="terminal-1308707172-r4" x="24.4" y="630" textLength="244" clip-path="url(#terminal-1308707172-line-25)">--ignore-other-files</text><text class="terminal-1308707172-r2" x="292.8" y="630" textLength="683.2" clip-path="url(#terminal-1308707172-line-25)">Ignore&#160;files&#160;that&#160;do&#160;not&#160;match&#160;the&#160;specified&#160;extensions.</text><text class="terminal-1308707172-r2" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-1308707172-line-25)">
</text><text class="terminal-1308707172-r4" x="24.4" y="654.4" textLength="280.6" clip-path="url(#terminal-1308707172-line-26)">--regenerate-thumbnails</text><text class="terminal-1308707172-r2" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-26)">
</text><text class="terminal-1308707172-r2" x="292.8" y="678.8" textLength="597.8" clip-path="url(#terminal-1308707172-line-27)">Regenerate&#160;thumbnails&#160;even&#160;if&#160;they&#160;already&#160;exist.</text><text class="terminal-1308707172-r2" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-27)">
</text><text class="terminal-1308707172-r4" x="24.4" y="703.2" textLength="207.4" clip-path="url(#terminal-1308707172-line-28)">--reread-metadata</text><text class="terminal-1308707172-r2" x="292.8" y="703.2" textLength="256.2" clip-path="url(#terminal-1308707172-line-28)">Reread&#160;image&#160;metadata</text><text class="terminal-1308707172-r2" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-1308707172-line-28)">
</text><text class="terminal-1308707172-r4" x="24.4" y="727.6" textLength="170.8" clip-path="url(#terminal-1308707172-line-29)">--reverse-sort</text><text class="terminal-1308707172-r2" x="292.8" y="727.6" textLength="353.8" clip-path="url(#terminal-1308707172-line-29)">Sort&#160;images&#160;in&#160;reverse&#160;order.</text><text class="terminal-1308707172-r2" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-1308707172-line-29)">
</text><text class="terminal-1308707172-r4" x="24.4" y="752" textLength="146.4" clip-path="url(#terminal-1308707172-line-30)">--theme-path</text><text class="terminal-1308707172-r5" x="183" y="752" textLength="48.8" clip-path="url(#terminal-1308707172-line-30)">PATH</text><text class="terminal-1308707172-r2" x="292.8" y="752" textLength="329.4" clip-path="url(#terminal-1308707172-line-30)">Path&#160;to&#160;the&#160;CSS&#160;theme&#160;file.</text><text class="terminal-1308707172-r2" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-1308707172-line-30)">
</text><text class="terminal-1308707172-r4" x="24.4" y="776.4" textLength="231.8" clip-path="url(#terminal-1308707172-line-31)">--use-fancy-folders</text><text class="terminal-1308707172-r2" x="292.8" y="776.4" textLength="890.6" clip-path="url(#terminal-1308707172-line-31)">Enable&#160;fancy&#160;folder&#160;view&#160;instead&#160;of&#160;the&#160;default&#160;Apache&#160;directory&#160;listing.</text><text class="terminal-1308707172-r2" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-1308707172-line-31)">
</text><text class="terminal-1308707172-r4" x="24.4" y="800.8" textLength="109.8" clip-path="url(#terminal-1308707172-line-32)">--version</text><text class="terminal-1308707172-r2" x="292.8" y="800.8" textLength="463.6" clip-path="url(#terminal-1308707172-line-32)">show&#160;program&#x27;s&#160;version&#160;number&#160;and&#160;exit</text><text class="terminal-1308707172-r2" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-1308707172-line-32)">
<g class="terminal-3378394567-matrix">
<text class="terminal-3378394567-r1" x="0" y="20" textLength="73.2" clip-path="url(#terminal-3378394567-line-0)">Usage:</text><text class="terminal-3378394567-r3" x="85.4" y="20" textLength="122" clip-path="url(#terminal-3378394567-line-0)">builder.py</text><text class="terminal-3378394567-r2" x="207.4" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">&#160;[</text><text class="terminal-3378394567-r4" x="231.8" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-h</text><text class="terminal-3378394567-r2" x="256.2" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">]&#160;[</text><text class="terminal-3378394567-r4" x="292.8" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-a</text><text class="terminal-3378394567-r5" x="329.4" y="20" textLength="73.2" clip-path="url(#terminal-3378394567-line-0)">AUTHOR</text><text class="terminal-3378394567-r2" x="402.6" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">]&#160;[</text><text class="terminal-3378394567-r4" x="439.2" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-e</text><text class="terminal-3378394567-r5" x="475.8" y="20" textLength="109.8" clip-path="url(#terminal-3378394567-line-0)">EXTENSION</text><text class="terminal-3378394567-r2" x="585.6" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">]&#160;[</text><text class="terminal-3378394567-r4" x="622.2" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-l</text><text class="terminal-3378394567-r5" x="658.8" y="20" textLength="85.4" clip-path="url(#terminal-3378394567-line-0)">LICENSE</text><text class="terminal-3378394567-r2" x="744.2" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">]&#160;[</text><text class="terminal-3378394567-r4" x="780.8" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-m</text><text class="terminal-3378394567-r2" x="805.2" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">]&#160;[</text><text class="terminal-3378394567-r4" x="841.8" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-n</text><text class="terminal-3378394567-r2" x="866.2" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">]&#160;</text><text class="terminal-3378394567-r4" x="890.6" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-p</text><text class="terminal-3378394567-r5" x="927.2" y="20" textLength="48.8" clip-path="url(#terminal-3378394567-line-0)">ROOT</text><text class="terminal-3378394567-r4" x="988.2" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-t</text><text class="terminal-3378394567-r5" x="1024.8" y="20" textLength="61" clip-path="url(#terminal-3378394567-line-0)">TITLE</text><text class="terminal-3378394567-r4" x="1098" y="20" textLength="24.4" clip-path="url(#terminal-3378394567-line-0)">-w</text><text class="terminal-3378394567-r5" x="1134.6" y="20" textLength="36.6" clip-path="url(#terminal-3378394567-line-0)">URL</text><text class="terminal-3378394567-r2" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-3378394567-line-0)">
</text><text class="terminal-3378394567-r2" x="0" y="44.4" textLength="231.8" clip-path="url(#terminal-3378394567-line-1)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[</text><text class="terminal-3378394567-r4" x="231.8" y="44.4" textLength="195.2" clip-path="url(#terminal-3378394567-line-1)">--exclude-folder</text><text class="terminal-3378394567-r5" x="439.2" y="44.4" textLength="73.2" clip-path="url(#terminal-3378394567-line-1)">FOLDER</text><text class="terminal-3378394567-r2" x="512.4" y="44.4" textLength="36.6" clip-path="url(#terminal-3378394567-line-1)">]&#160;[</text><text class="terminal-3378394567-r4" x="549" y="44.4" textLength="219.6" clip-path="url(#terminal-3378394567-line-1)">--folderthumbnails</text><text class="terminal-3378394567-r2" x="768.6" y="44.4" textLength="36.6" clip-path="url(#terminal-3378394567-line-1)">]&#160;[</text><text class="terminal-3378394567-r4" x="805.2" y="44.4" textLength="244" clip-path="url(#terminal-3378394567-line-1)">--ignore-other-files</text><text class="terminal-3378394567-r2" x="1049.2" y="44.4" textLength="36.6" clip-path="url(#terminal-3378394567-line-1)">]&#160;[</text><text class="terminal-3378394567-r4" x="1085.8" y="44.4" textLength="280.6" clip-path="url(#terminal-3378394567-line-1)">--regenerate-thumbnails</text><text class="terminal-3378394567-r2" x="1366.4" y="44.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-1)">]</text><text class="terminal-3378394567-r2" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-1)">
</text><text class="terminal-3378394567-r2" x="0" y="68.8" textLength="231.8" clip-path="url(#terminal-3378394567-line-2)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[</text><text class="terminal-3378394567-r4" x="231.8" y="68.8" textLength="207.4" clip-path="url(#terminal-3378394567-line-2)">--reread-metadata</text><text class="terminal-3378394567-r2" x="439.2" y="68.8" textLength="36.6" clip-path="url(#terminal-3378394567-line-2)">]&#160;[</text><text class="terminal-3378394567-r4" x="475.8" y="68.8" textLength="195.2" clip-path="url(#terminal-3378394567-line-2)">--reread-sidecar</text><text class="terminal-3378394567-r2" x="671" y="68.8" textLength="36.6" clip-path="url(#terminal-3378394567-line-2)">]&#160;[</text><text class="terminal-3378394567-r4" x="707.6" y="68.8" textLength="170.8" clip-path="url(#terminal-3378394567-line-2)">--reverse-sort</text><text class="terminal-3378394567-r2" x="878.4" y="68.8" textLength="36.6" clip-path="url(#terminal-3378394567-line-2)">]&#160;[</text><text class="terminal-3378394567-r4" x="915" y="68.8" textLength="146.4" clip-path="url(#terminal-3378394567-line-2)">--theme-path</text><text class="terminal-3378394567-r5" x="1073.6" y="68.8" textLength="48.8" clip-path="url(#terminal-3378394567-line-2)">PATH</text><text class="terminal-3378394567-r2" x="1122.4" y="68.8" textLength="36.6" clip-path="url(#terminal-3378394567-line-2)">]&#160;[</text><text class="terminal-3378394567-r4" x="1159" y="68.8" textLength="231.8" clip-path="url(#terminal-3378394567-line-2)">--use-fancy-folders</text><text class="terminal-3378394567-r2" x="1390.8" y="68.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-2)">]</text><text class="terminal-3378394567-r2" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-2)">
</text><text class="terminal-3378394567-r2" x="0" y="93.2" textLength="231.8" clip-path="url(#terminal-3378394567-line-3)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[</text><text class="terminal-3378394567-r4" x="231.8" y="93.2" textLength="109.8" clip-path="url(#terminal-3378394567-line-3)">--version</text><text class="terminal-3378394567-r2" x="341.6" y="93.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-3)">]</text><text class="terminal-3378394567-r2" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-3)">
</text><text class="terminal-3378394567-r2" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-4)">
</text><text class="terminal-3378394567-r2" x="0" y="142" textLength="658.8" clip-path="url(#terminal-3378394567-line-5)">generate&#160;HTML&#160;files&#160;for&#160;a&#160;static&#160;image&#160;hosting&#160;website</text><text class="terminal-3378394567-r2" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-3378394567-line-5)">
</text><text class="terminal-3378394567-r2" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-6)">
</text><text class="terminal-3378394567-r1" x="0" y="190.8" textLength="97.6" clip-path="url(#terminal-3378394567-line-7)">Options:</text><text class="terminal-3378394567-r2" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-7)">
</text><text class="terminal-3378394567-r4" x="24.4" y="215.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-8)">-h</text><text class="terminal-3378394567-r2" x="48.8" y="215.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-8)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="215.2" textLength="73.2" clip-path="url(#terminal-3378394567-line-8)">--help</text><text class="terminal-3378394567-r2" x="292.8" y="215.2" textLength="378.2" clip-path="url(#terminal-3378394567-line-8)">show&#160;this&#160;help&#160;message&#160;and&#160;exit</text><text class="terminal-3378394567-r2" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-8)">
</text><text class="terminal-3378394567-r4" x="24.4" y="239.6" textLength="24.4" clip-path="url(#terminal-3378394567-line-9)">-a</text><text class="terminal-3378394567-r2" x="48.8" y="239.6" textLength="24.4" clip-path="url(#terminal-3378394567-line-9)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="239.6" textLength="158.6" clip-path="url(#terminal-3378394567-line-9)">--author-name</text><text class="terminal-3378394567-r5" x="244" y="239.6" textLength="73.2" clip-path="url(#terminal-3378394567-line-9)">AUTHOR</text><text class="terminal-3378394567-r2" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-9)">
</text><text class="terminal-3378394567-r2" x="292.8" y="264" textLength="390.4" clip-path="url(#terminal-3378394567-line-10)">name&#160;of&#160;the&#160;author&#160;of&#160;the&#160;images</text><text class="terminal-3378394567-r2" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-3378394567-line-10)">
</text><text class="terminal-3378394567-r4" x="24.4" y="288.4" textLength="24.4" clip-path="url(#terminal-3378394567-line-11)">-e</text><text class="terminal-3378394567-r2" x="48.8" y="288.4" textLength="24.4" clip-path="url(#terminal-3378394567-line-11)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="288.4" textLength="207.4" clip-path="url(#terminal-3378394567-line-11)">--file-extensions</text><text class="terminal-3378394567-r5" x="292.8" y="288.4" textLength="109.8" clip-path="url(#terminal-3378394567-line-11)">EXTENSION</text><text class="terminal-3378394567-r2" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-11)">
</text><text class="terminal-3378394567-r2" x="292.8" y="312.8" textLength="732" clip-path="url(#terminal-3378394567-line-12)">file&#160;extensions&#160;to&#160;include&#160;(can&#160;be&#160;specified&#160;multiple&#160;times)</text><text class="terminal-3378394567-r2" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-12)">
</text><text class="terminal-3378394567-r4" x="24.4" y="337.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-13)">-l</text><text class="terminal-3378394567-r2" x="48.8" y="337.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-13)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="337.2" textLength="170.8" clip-path="url(#terminal-3378394567-line-13)">--license-type</text><text class="terminal-3378394567-r5" x="256.2" y="337.2" textLength="85.4" clip-path="url(#terminal-3378394567-line-13)">LICENSE</text><text class="terminal-3378394567-r2" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-13)">
</text><text class="terminal-3378394567-r2" x="292.8" y="361.6" textLength="475.8" clip-path="url(#terminal-3378394567-line-14)">specify&#160;the&#160;license&#160;type&#160;for&#160;the&#160;images</text><text class="terminal-3378394567-r2" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-14)">
</text><text class="terminal-3378394567-r4" x="24.4" y="386" textLength="24.4" clip-path="url(#terminal-3378394567-line-15)">-m</text><text class="terminal-3378394567-r2" x="48.8" y="386" textLength="24.4" clip-path="url(#terminal-3378394567-line-15)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="386" textLength="170.8" clip-path="url(#terminal-3378394567-line-15)">--web-manifest</text><text class="terminal-3378394567-r2" x="292.8" y="386" textLength="341.6" clip-path="url(#terminal-3378394567-line-15)">generate&#160;a&#160;web&#160;manifest&#160;file</text><text class="terminal-3378394567-r2" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-3378394567-line-15)">
</text><text class="terminal-3378394567-r4" x="24.4" y="410.4" textLength="24.4" clip-path="url(#terminal-3378394567-line-16)">-n</text><text class="terminal-3378394567-r2" x="48.8" y="410.4" textLength="24.4" clip-path="url(#terminal-3378394567-line-16)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="410.4" textLength="268.4" clip-path="url(#terminal-3378394567-line-16)">--non-interactive-mode</text><text class="terminal-3378394567-r2" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-16)">
</text><text class="terminal-3378394567-r2" x="292.8" y="434.8" textLength="634.4" clip-path="url(#terminal-3378394567-line-17)">run&#160;in&#160;non-interactive&#160;mode,&#160;disabling&#160;progress&#160;bars</text><text class="terminal-3378394567-r2" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-17)">
</text><text class="terminal-3378394567-r4" x="24.4" y="459.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-18)">-p</text><text class="terminal-3378394567-r2" x="48.8" y="459.2" textLength="24.4" clip-path="url(#terminal-3378394567-line-18)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="459.2" textLength="195.2" clip-path="url(#terminal-3378394567-line-18)">--root-directory</text><text class="terminal-3378394567-r5" x="280.6" y="459.2" textLength="48.8" clip-path="url(#terminal-3378394567-line-18)">ROOT</text><text class="terminal-3378394567-r2" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-18)">
</text><text class="terminal-3378394567-r2" x="292.8" y="483.6" textLength="439.2" clip-path="url(#terminal-3378394567-line-19)">root&#160;directory&#160;containing&#160;the&#160;images</text><text class="terminal-3378394567-r2" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-19)">
</text><text class="terminal-3378394567-r4" x="24.4" y="508" textLength="24.4" clip-path="url(#terminal-3378394567-line-20)">-t</text><text class="terminal-3378394567-r2" x="48.8" y="508" textLength="24.4" clip-path="url(#terminal-3378394567-line-20)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="508" textLength="146.4" clip-path="url(#terminal-3378394567-line-20)">--site-title</text><text class="terminal-3378394567-r5" x="231.8" y="508" textLength="61" clip-path="url(#terminal-3378394567-line-20)">TITLE</text><text class="terminal-3378394567-r2" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-3378394567-line-20)">
</text><text class="terminal-3378394567-r2" x="292.8" y="532.4" textLength="378.2" clip-path="url(#terminal-3378394567-line-21)">title&#160;of&#160;the&#160;image&#160;hosting&#160;site</text><text class="terminal-3378394567-r2" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-21)">
</text><text class="terminal-3378394567-r4" x="24.4" y="556.8" textLength="24.4" clip-path="url(#terminal-3378394567-line-22)">-w</text><text class="terminal-3378394567-r2" x="48.8" y="556.8" textLength="24.4" clip-path="url(#terminal-3378394567-line-22)">,&#160;</text><text class="terminal-3378394567-r4" x="73.2" y="556.8" textLength="170.8" clip-path="url(#terminal-3378394567-line-22)">--web-root-url</text><text class="terminal-3378394567-r5" x="256.2" y="556.8" textLength="36.6" clip-path="url(#terminal-3378394567-line-22)">URL</text><text class="terminal-3378394567-r2" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-22)">
</text><text class="terminal-3378394567-r2" x="292.8" y="581.2" textLength="622.2" clip-path="url(#terminal-3378394567-line-23)">base&#160;URL&#160;of&#160;the&#160;web&#160;root&#160;for&#160;the&#160;image&#160;hosting&#160;site</text><text class="terminal-3378394567-r2" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-23)">
</text><text class="terminal-3378394567-r4" x="24.4" y="605.6" textLength="195.2" clip-path="url(#terminal-3378394567-line-24)">--exclude-folder</text><text class="terminal-3378394567-r5" x="231.8" y="605.6" textLength="73.2" clip-path="url(#terminal-3378394567-line-24)">FOLDER</text><text class="terminal-3378394567-r2" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-24)">
</text><text class="terminal-3378394567-r2" x="292.8" y="630" textLength="1037" clip-path="url(#terminal-3378394567-line-25)">folders&#160;to&#160;exclude&#160;from&#160;processing,&#160;globs&#160;supported&#160;(can&#160;be&#160;specified&#160;multiple&#160;times)</text><text class="terminal-3378394567-r2" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-3378394567-line-25)">
</text><text class="terminal-3378394567-r4" x="24.4" y="654.4" textLength="219.6" clip-path="url(#terminal-3378394567-line-26)">--folderthumbnails</text><text class="terminal-3378394567-r2" x="292.8" y="654.4" textLength="817.4" clip-path="url(#terminal-3378394567-line-26)">generate&#160;subfolder&#160;thumbnails&#160;(first&#160;image&#160;in&#160;folder&#160;will&#160;be&#160;shown)</text><text class="terminal-3378394567-r2" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-26)">
</text><text class="terminal-3378394567-r4" x="24.4" y="678.8" textLength="244" clip-path="url(#terminal-3378394567-line-27)">--ignore-other-files</text><text class="terminal-3378394567-r2" x="292.8" y="678.8" textLength="671" clip-path="url(#terminal-3378394567-line-27)">ignore&#160;files&#160;that&#160;do&#160;not&#160;match&#160;the&#160;specified&#160;extensions</text><text class="terminal-3378394567-r2" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-27)">
</text><text class="terminal-3378394567-r4" x="24.4" y="703.2" textLength="280.6" clip-path="url(#terminal-3378394567-line-28)">--regenerate-thumbnails</text><text class="terminal-3378394567-r2" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-28)">
</text><text class="terminal-3378394567-r2" x="292.8" y="727.6" textLength="585.6" clip-path="url(#terminal-3378394567-line-29)">regenerate&#160;thumbnails&#160;even&#160;if&#160;they&#160;already&#160;exist</text><text class="terminal-3378394567-r2" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-29)">
</text><text class="terminal-3378394567-r4" x="24.4" y="752" textLength="207.4" clip-path="url(#terminal-3378394567-line-30)">--reread-metadata</text><text class="terminal-3378394567-r2" x="292.8" y="752" textLength="256.2" clip-path="url(#terminal-3378394567-line-30)">reread&#160;image&#160;metadata</text><text class="terminal-3378394567-r2" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-3378394567-line-30)">
</text><text class="terminal-3378394567-r4" x="24.4" y="776.4" textLength="195.2" clip-path="url(#terminal-3378394567-line-31)">--reread-sidecar</text><text class="terminal-3378394567-r2" x="292.8" y="776.4" textLength="244" clip-path="url(#terminal-3378394567-line-31)">reread&#160;sidecar&#160;files</text><text class="terminal-3378394567-r2" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-3378394567-line-31)">
</text><text class="terminal-3378394567-r4" x="24.4" y="800.8" textLength="170.8" clip-path="url(#terminal-3378394567-line-32)">--reverse-sort</text><text class="terminal-3378394567-r2" x="292.8" y="800.8" textLength="341.6" clip-path="url(#terminal-3378394567-line-32)">sort&#160;images&#160;in&#160;reverse&#160;order</text><text class="terminal-3378394567-r2" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-3378394567-line-32)">
</text><text class="terminal-3378394567-r4" x="24.4" y="825.2" textLength="146.4" clip-path="url(#terminal-3378394567-line-33)">--theme-path</text><text class="terminal-3378394567-r5" x="183" y="825.2" textLength="48.8" clip-path="url(#terminal-3378394567-line-33)">PATH</text><text class="terminal-3378394567-r2" x="292.8" y="825.2" textLength="317.2" clip-path="url(#terminal-3378394567-line-33)">path&#160;to&#160;the&#160;CSS&#160;theme&#160;file</text><text class="terminal-3378394567-r2" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-3378394567-line-33)">
</text><text class="terminal-3378394567-r4" x="24.4" y="849.6" textLength="231.8" clip-path="url(#terminal-3378394567-line-34)">--use-fancy-folders</text><text class="terminal-3378394567-r2" x="292.8" y="849.6" textLength="878.4" clip-path="url(#terminal-3378394567-line-34)">enable&#160;fancy&#160;folder&#160;view&#160;instead&#160;of&#160;the&#160;default&#160;Apache&#160;directory&#160;listing</text><text class="terminal-3378394567-r2" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-3378394567-line-34)">
</text><text class="terminal-3378394567-r4" x="24.4" y="874" textLength="109.8" clip-path="url(#terminal-3378394567-line-35)">--version</text><text class="terminal-3378394567-r2" x="292.8" y="874" textLength="463.6" clip-path="url(#terminal-3378394567-line-35)">show&#160;program&#x27;s&#160;version&#160;number&#160;and&#160;exit</text><text class="terminal-3378394567-r2" x="1464" y="874" textLength="12.2" clip-path="url(#terminal-3378394567-line-35)">
</text>
</g>
</g>

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -67,6 +67,7 @@ class Args:
non_interactive_mode: bool
regenerate_thumbnails: bool
reread_metadata: bool
reread_sidecar: bool
reverse_sort: bool
root_directory: str
site_title: str
@@ -87,6 +88,7 @@ class Args:
result["non_interactive_mode"] = self.non_interactive_mode
result["regenerate_thumbnails"] = self.regenerate_thumbnails
result["reread_metadata"] = self.reread_metadata
result["reread_sidecar"] = self.reread_sidecar
result["reverse_sort"] = self.reverse_sort
result["root_directory"] = self.root_directory
result["site_title"] = self.site_title
@@ -112,27 +114,28 @@ def parse_arguments(version: str) -> Args:
"""
# fmt: off
if RICH:
parser = argparse.ArgumentParser(description="Generate HTML files for a static image hosting website.", formatter_class=RichHelpFormatter)
parser = argparse.ArgumentParser(description="generate HTML files for a static image hosting website", formatter_class=RichHelpFormatter)
else:
parser = argparse.ArgumentParser(description="Generate HTML files for a static image hosting website.")
parser.add_argument("-a", "--author-name", help="Name of the author of the images.", default=DEFAULT_AUTHOR, type=str, dest="author_name", metavar="AUTHOR")
parser.add_argument("-e", "--file-extensions", help="File extensions to include (can be specified multiple times).", action="append", dest="file_extensions", metavar="EXTENSION")
parser.add_argument("-l", "--license-type", help="Specify the license type for the images.", choices=["cc-zero", "cc-by", "cc-by-sa", "cc-by-nd", "cc-by-nc", "cc-by-nc-sa", "cc-by-nc-nd"], default=None, dest="license_type", metavar="LICENSE")
parser.add_argument("-m", "--web-manifest", help="Generate a web manifest file.", action="store_true", default=False, dest="generate_webmanifest")
parser.add_argument("-n", "--non-interactive-mode", help="Run in non-interactive mode, disabling progress bars.", action="store_true", default=False, dest="non_interactive_mode")
parser.add_argument("-p", "--root-directory", help="Root directory containing the images.", required=True, type=str, dest="root_directory", metavar="ROOT")
parser.add_argument("-t", "--site-title", help="Title of the image hosting site.", required=True, type=str, dest="site_title", metavar="TITLE")
parser.add_argument("-w", "--web-root-url", help="Base URL of the web root for the image hosting site.", required=True, type=str, dest="web_root_url", metavar="URL")
parser.add_argument("--exclude-folder", help="Folders to exclude from processing, globs supported (can be specified multiple times).", action="append", dest="exclude_folders", metavar="FOLDER")
parser.add_argument("--folderthumbnails", help="Generate subfolder thumbnails (first image in folder will be shown)", action="store_true", default=False, dest="folder_thumbs")
parser = argparse.ArgumentParser(description="generate HTML files for a static image hosting website")
parser.add_argument("-a", "--author-name", help="name of the author of the images", default=DEFAULT_AUTHOR, type=str, dest="author_name", metavar="AUTHOR")
parser.add_argument("-e", "--file-extensions", help="file extensions to include (can be specified multiple times)", action="append", dest="file_extensions", metavar="EXTENSION")
parser.add_argument("-l", "--license-type", help="specify the license type for the images", choices=["cc-zero", "cc-by", "cc-by-sa", "cc-by-nd", "cc-by-nc", "cc-by-nc-sa", "cc-by-nc-nd"], default=None, dest="license_type", metavar="LICENSE")
parser.add_argument("-m", "--web-manifest", help="generate a web manifest file", action="store_true", default=False, dest="generate_webmanifest")
parser.add_argument("-n", "--non-interactive-mode", help="run in non-interactive mode, disabling progress bars", action="store_true", default=False, dest="non_interactive_mode")
parser.add_argument("-p", "--root-directory", help="root directory containing the images", required=True, type=str, dest="root_directory", metavar="ROOT")
parser.add_argument("-t", "--site-title", help="title of the image hosting site", required=True, type=str, dest="site_title", metavar="TITLE")
parser.add_argument("-w", "--web-root-url", help="base URL of the web root for the image hosting site", required=True, type=str, dest="web_root_url", metavar="URL")
parser.add_argument("--exclude-folder", help="folders to exclude from processing, globs supported (can be specified multiple times)", action="append", dest="exclude_folders", metavar="FOLDER")
parser.add_argument("--folderthumbnails", help="generate subfolder thumbnails (first image in folder will be shown)", action="store_true", default=False, dest="folder_thumbs")
if RICH:
parser.add_argument("--generate-help-preview", action=HelpPreviewAction, path="help.svg", )
parser.add_argument("--ignore-other-files", help="Ignore files that do not match the specified extensions.", action="store_true", default=False, dest="ignore_other_files")
parser.add_argument("--regenerate-thumbnails", help="Regenerate thumbnails even if they already exist.", action="store_true", default=False, dest="regenerate_thumbnails")
parser.add_argument("--reread-metadata", help="Reread image metadata", action="store_true", default=False, dest="reread_metadata")
parser.add_argument("--reverse-sort", help="Sort images in reverse order.", action="store_true", default=False, dest="reverse_sort")
parser.add_argument("--theme-path", help="Path to the CSS theme file.", default=DEFAULT_THEME_PATH, type=str, dest="theme_path", metavar="PATH")
parser.add_argument("--use-fancy-folders", help="Enable fancy folder view instead of the default Apache directory listing.", action="store_true", default=False, dest="use_fancy_folders")
parser.add_argument("--ignore-other-files", help="ignore files that do not match the specified extensions", action="store_true", default=False, dest="ignore_other_files")
parser.add_argument("--regenerate-thumbnails", help="regenerate thumbnails even if they already exist", action="store_true", default=False, dest="regenerate_thumbnails")
parser.add_argument("--reread-metadata", help="reread image metadata", action="store_true", default=False, dest="reread_metadata")
parser.add_argument("--reread-sidecar", help="reread sidecar files", action="store_true", default=False, dest="reread_sidecar")
parser.add_argument("--reverse-sort", help="sort images in reverse order", action="store_true", default=False, dest="reverse_sort")
parser.add_argument("--theme-path", help="path to the CSS theme file", default=DEFAULT_THEME_PATH, type=str, dest="theme_path", metavar="PATH")
parser.add_argument("--use-fancy-folders", help="enable fancy folder view instead of the default Apache directory listing", action="store_true", default=False, dest="use_fancy_folders")
parser.add_argument("--version", action="version", version=f"%(prog)s {version}")
parsed_args = parser.parse_args()
# fmt: on
@@ -147,6 +150,7 @@ def parse_arguments(version: str) -> Args:
non_interactive_mode=parsed_args.non_interactive_mode,
regenerate_thumbnails=parsed_args.regenerate_thumbnails,
reread_metadata=parsed_args.reread_metadata,
reread_sidecar=parsed_args.reread_sidecar,
reverse_sort=parsed_args.reverse_sort,
root_directory=parsed_args.root_directory,
site_title=parsed_args.site_title,

View File

@@ -3,13 +3,16 @@ import re
import urllib.parse
import fnmatch
import json
import html
from typing import Any
from datetime import datetime
from collections import defaultdict
from tqdm.auto import tqdm
from PIL import Image, ExifTags, TiffImagePlugin, UnidentifiedImageError
from jinja2 import Environment, FileSystemLoader
from defusedxml import ElementTree
from bs4 import BeautifulSoup
from modules.logger import logger
from modules import cclicense
@@ -97,8 +100,32 @@ def initialize_metadata(folder: str) -> dict[str, dict[str, int]]:
# remove old sizelist if it exists
sizelist_path = os.path.join(folder, ".sizelist.json")
if os.path.exists(sizelist_path):
with open(sizelist_path, "r") as sizelist:
metadata = json.loads(sizelist.read())
logger.warning("found old .sizelist.json, removing it...", extra={"path": sizelist_path})
os.remove(sizelist_path)
# convert from old metadata format
if "images" not in metadata and "subfolders" not in metadata:
images = metadata.copy()
metadata = {}
metadata["images"] = images
elif "images" not in metadata:
metadata["images"] = {}
for k, v in metadata["images"].items():
if "width" in v:
metadata["images"][k]["w"] = v["width"]
del metadata["images"][k]["width"]
if "height" in v:
metadata["images"][k]["h"] = v["height"]
del metadata["images"][k]["height"]
if "tags" not in v:
metadata["images"][k]["tags"] = []
if "exifdata" not in v:
metadata["images"][k]["exifdata"] = None
if "xmp" not in v:
metadata["images"][k]["xmp"] = None
return metadata
@@ -143,7 +170,7 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
except UnidentifiedImageError:
logger.error("cannot identify image file", extra={"file": file})
print(f"cannot identify image file: {file}")
return {"width": None, "height": None, "tags": None, "exifdata": None, "xmp": None}
return {"w": None, "h": None, "tags": None, "exifdata": None, "xmp": None}
if exif:
logger.info("extracting EXIF data", extra={"file": file})
ifd = exif.get_ifd(ExifTags.IFD.Exif)
@@ -189,23 +216,70 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
xmp = xmpdata
except TypeError:
...
pass
except KeyError:
...
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
xmp = xmpdata
except TypeError:
...
pass
except KeyError:
...
pass
try:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
sidecarfile = os.path.join(folder, item + ".xmp")
if os.path.exists(sidecarfile):
logger.info("xmp sidecar file found", extra={"file": sidecarfile})
try:
tags = get_tags(sidecarfile)
except Exception as e:
logger.error(e)
if None in tags:
tags.remove(None)
return {"width": width, "height": height, "tags": tags, "exifdata": exifdata, "xmp": xmp}
return {"w": width, "h": height, "tags": tags, "exifdata": exifdata, "xmp": xmp}
def nested_dict():
return defaultdict(nested_dict)
def insert_path(d, path):
for part in path[:-1]:
d = d[part]
last = path[-1]
if not isinstance(d[last], dict):
d[last] = {}
def finalize(d):
if isinstance(d, defaultdict):
return {k: finalize(d[k]) for k in sorted(d)}
return d or []
def parse_hierarchical_tags(tags, delimiter="|"):
tree = nested_dict()
for tag in tags:
parts = tag.split(delimiter)
insert_path(tree, parts)
return finalize(tree)
def get_tags(sidecarfile: str) -> list[str]:
@@ -228,17 +302,33 @@ def get_tags(sidecarfile: str) -> list[str]:
if isinstance(tags, str):
tags = [tags]
except TypeError:
...
pass
except KeyError:
...
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
...
pass
except KeyError:
...
pass
try:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
if None in tags:
tags.remove(None)
return tags
@@ -260,25 +350,23 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
dict[str, Any]: dictionary containing image details for HTML rendering.
"""
extsplit = os.path.splitext(item)
if item not in metadata or _args.reread_metadata:
metadata[item] = get_image_info(item, folder)
sidecarfile = os.path.join(folder, item + ".xmp")
if os.path.exists(sidecarfile):
if item not in metadata["images"] or _args.reread_metadata:
metadata["images"][item] = get_image_info(item, folder)
if _args.reread_sidecar and os.path.exists(sidecarfile):
logger.info("xmp sidecar file found", extra={"file": sidecarfile})
try:
metadata[item]["tags"] = get_tags(sidecarfile)
metadata["images"][item]["tags"] = get_tags(sidecarfile)
except Exception as e:
logger.error(e)
image = {
"url": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}",
"thumbnail": f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg",
"src": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}",
"msrc": f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg",
"name": item,
"width": metadata[item]["width"],
"height": metadata[item]["height"],
"tags": metadata[item]["tags"],
"exifdata": metadata[item].get("exifdata", ""),
"xmp": metadata[item].get("xmp", ""),
"w": metadata["images"][item]["w"],
"h": metadata["images"][item]["h"],
"tags": metadata["images"][item]["tags"],
}
path = os.path.join(_args.root_directory, ".thumbnails", baseurl, item + ".jpg")
if not os.path.exists(path) or _args.regenerate_thumbnails:
@@ -296,10 +384,13 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
else:
logger.info("raw file found", extra={"file": file, "extension": _raw})
image["raw"] = url
return image
metadata["images"][item].update(image)
return image, metadata
def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo) -> None:
def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[str]:
"""
Generates HTML content for a folder of images.
@@ -320,10 +411,15 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
contains_files = False
images = []
subfolders = []
subfoldertags = set()
foldername = folder.removeprefix(_args.root_directory)
foldername = f"{foldername}/" if foldername else ""
baseurl = urllib.parse.quote(foldername)
gone = [item for item in metadata["images"] if item not in items]
for gon in gone:
del metadata["images"][gon]
create_thumbnail_folder(foldername, _args.root_directory)
logger.info("processing contents", extra={"folder": folder})
@@ -331,11 +427,12 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
for item in tqdm(items, total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True):
if item not in EXCLUDES and not item.startswith("."):
if os.path.isdir(os.path.join(folder, item)):
process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)
subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo))
else:
contains_files = True
if os.path.splitext(item)[1].lower() in _args.file_extensions:
images.append(process_image(item, folder, _args, baseurl, metadata, raw))
img, metadata = process_image(item, folder, _args, baseurl, metadata, raw)
images.append(img)
if item == "info":
process_info_file(folder, item)
if item == "LICENSE":
@@ -344,24 +441,31 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
for item in items:
if item not in EXCLUDES and not item.startswith("."):
if os.path.isdir(os.path.join(folder, item)):
process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)
subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo))
else:
contains_files = True
if os.path.splitext(item)[1].lower() in _args.file_extensions:
images.append(process_image(item, folder, _args, baseurl, metadata, raw))
img, metadata = process_image(item, folder, _args, baseurl, metadata, raw)
images.append(img)
if item == "info":
process_info_file(folder, item)
if item == "LICENSE":
process_license(folder, item)
metadata["subfolders"] = subfolders
if _args.reverse_sort:
metadata["images"] = {key: metadata["images"][key] for key in sorted(metadata["images"], reverse=True)}
else:
metadata["images"] = {key: metadata["images"][key] for key in sorted(metadata["images"])}
update_metadata(metadata, folder)
if should_generate_html(images, contains_files, _args):
create_html_file(folder, title, foldername, images, subfolders, _args, version, logo)
subfoldertags = create_html_file(folder, title, foldername, images, subfolders, _args, version, logo, subfoldertags)
else:
if os.path.exists(os.path.join(folder, "index.html")):
logger.info("removing existing index.html", extra={"folder": folder})
os.remove(os.path.join(folder, "index.html"))
return subfoldertags
def create_thumbnail_folder(foldername: str, root_directory: str) -> None:
@@ -378,7 +482,7 @@ def create_thumbnail_folder(foldername: str, root_directory: str) -> None:
os.mkdir(thumbnails_path)
def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dict[str, str | None]], _args: Args, raw: list[str], version: str, logo: str) -> None:
def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dict[str, str | None]], _args: Args, raw: list[str], version: str, logo: str) -> list[str]:
"""
Processes a subfolder.
@@ -404,25 +508,28 @@ def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dic
else:
thumb = f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}/{urllib.parse.quote(thumbitems[0])}.jpg"
subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb})
if item not in _args.exclude_folders:
if not any(fnmatch.fnmatchcase(os.path.join(folder, item), exclude) for exclude in _args.exclude_folders):
generate_html(os.path.join(folder, item), os.path.join(folder, item).removeprefix(_args.root_directory), _args, raw, version, logo)
subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb, "metadata": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}/.metadata.json"})
return generate_html(os.path.join(folder, item), os.path.join(folder, item).removeprefix(_args.root_directory), _args, raw, version, logo)
subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb, "metadata": None})
return []
def process_license(folder: str, item: str) -> None:
"""
Processes a LICENSE file.
Processes a LICENSE file, preserving formatting in HTML.
Args:
folder (str): The folder containing the info file.
item (str): The licenses file name.
folder (str): The folder containing the LICENSE file.
item (str): The LICENSE file name.
"""
with open(os.path.join(folder, item), encoding="utf-8") as f:
logger.info("processing LICENSE", extra={"path": os.path.join(folder, item)})
licens[urllib.parse.quote(folder)] = (
f.read().replace("\n", "</br>\n").replace(" ", "&emsp;").replace(" ", "&ensp;").replace("sp; ", "sp;&ensp;").replace("&ensp;&ensp;", "&emsp;")
)
path = os.path.join(folder, item)
with open(path, encoding="utf-8") as f:
logger.info("processing LICENSE", extra={"path": path})
raw_text = f.read()
escaped_text = html.escape(raw_text)
licens[urllib.parse.quote(folder)] = f"<pre>{escaped_text}</pre>"
def process_info_file(folder: str, item: str) -> None:
@@ -452,7 +559,14 @@ def should_generate_html(images: list[dict[str, Any]], contains_files, _args: Ar
return images or (_args.use_fancy_folders and not contains_files) or (_args.use_fancy_folders and _args.ignore_other_files)
def create_html_file(folder: str, title: str, foldername: str, images: list[dict[str, Any]], subfolders: list[dict[str, str]], _args: Args, version: str, logo: str) -> None:
def format_html(html: str) -> str:
soup = BeautifulSoup(html, "html5lib")
return soup.prettify()
def create_html_file(
folder: str, title: str, foldername: str, images: list[dict[str, Any]], subfolders: list[dict[str, str]], _args: Args, version: str, logo: str, subfoldertags: list[str]
) -> list[str]:
"""
Creates the HTML file using the template.
@@ -485,9 +599,10 @@ def create_html_file(folder: str, title: str, foldername: str, images: list[dict
alltags = set()
for img in images:
for tag in img["tags"]:
alltags.add(tag)
alltags = sorted(alltags)
if img["tags"]:
alltags.update(img["tags"])
alltags.update(set(subfoldertags))
folder_info = info.get(urllib.parse.quote(folder), "").split("\n")
_info = [i for i in folder_info if len(i) > 1] if folder_info else None
@@ -518,7 +633,7 @@ def create_html_file(folder: str, title: str, foldername: str, images: list[dict
logo=logo,
licensefile=folder_license,
)
f.write(content)
f.write(format_html(content))
html = env.get_template("index.html.j2")
content = html.render(
@@ -531,18 +646,19 @@ def create_html_file(folder: str, title: str, foldername: str, images: list[dict
header=header,
license=license_info,
subdirectories=subfolders,
images=images,
info=_info,
webmanifest=_args.generate_webmanifest,
version=version,
logo=logo,
licensefile=license_url,
tags=alltags,
tags=parse_hierarchical_tags(alltags),
)
with open(html_file, "w", encoding="utf-8") as f:
logger.info("writing html file", extra={"path": html_file})
f.write(content)
logger.info("writing formatted html file", extra={"path": html_file})
f.write(format_html(content))
return sorted(alltags)
def list_folder(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[tuple[str, str, str]]:

View File

@@ -95,7 +95,7 @@ def setup_logger(level=logging.INFO):
"""
_logger = logging.getLogger(name="defaultlogger")
supported_keys = ["asctime", "created", "filename", "funcName", "levelname", "levelno", "lineno", "module", "msecs", "message", "name", "pathname", "process", "processName", "relativeCreated", "thread", "threadName", "taskName"]
supported_keys = ["asctime", "created", "filename", "funcName", "levelname", "levelno", "lineno", "module", "msecs", "message", "process", "processName", "relativeCreated", "thread", "threadName"]
custom_format = " ".join(log_format(supported_keys))
formatter = jsonlogger.JsonFormatter(custom_format)
@@ -121,7 +121,7 @@ def setup_consolelogger(level=logging.INFO):
"""
_logger = logging.getLogger(name="consolelogger")
supported_keys = ["asctime", "created", "filename", "funcName", "levelname", "levelno", "lineno", "module", "msecs", "message", "name", "pathname", "process", "processName", "relativeCreated", "thread", "threadName", "taskName"]
supported_keys = ["asctime", "created", "filename", "funcName", "levelname", "levelno", "lineno", "module", "msecs", "message", "process", "processName", "relativeCreated", "thread", "threadName"]
custom_format = " ".join(log_format(supported_keys))
formatter = jsonlogger.JsonFormatter(custom_format)

View File

@@ -146,7 +146,7 @@ def render_manifest_json(_args: Args, icon_list: list[Icon], colors: dict[str, s
colors : dict[str, str]
dictionary containing color scheme and theme color.
"""
manifest = env.get_template("manifest.json.j2")
manifest = env.get_template("manifest.webmanifest.j2")
content = manifest.render(
name=_args.web_root_url.replace("https://", "").replace("http://", "").replace("/", ""),
short_name=_args.site_title,
@@ -154,8 +154,8 @@ def render_manifest_json(_args: Args, icon_list: list[Icon], colors: dict[str, s
background_color=colors["bcolor1"],
theme_color=colors["theme_color"],
)
with open(os.path.join(_args.root_directory, ".static", "manifest.json"), "w", encoding="utf-8") as f:
logger.info("rendering manifest.json", extra={"path": os.path.join(_args.root_directory, ".static", "manifest.json")})
with open(os.path.join(_args.root_directory, ".static", "manifest.webmanifest"), "w", encoding="utf-8") as f:
logger.info("rendering manifest.webmanifest", extra={"path": os.path.join(_args.root_directory, ".static", "manifest.webmanifest")})
f.write(content)

View File

@@ -1,9 +1,12 @@
CairoSVG==2.7.1
defusedxml==0.7.1
Jinja2==3.1.5
Pillow==11.1.0
pyinstaller==6.11.1
python_json_logger==2.0.7
rich_argparse==1.7.0
selenium==4.28.1
tqdm==4.66.4
beautifulsoup4~=4.13.4
CairoSVG~=2.7.1
defusedxml~=0.7.1
html5lib~=1.1
Jinja2~=3.1.6
jsmin~=3.0.1
Pillow~=11.3.0
pyinstaller~=6.11.1
python_json_logger~=2.0.7
rich_argparse~=1.7.1
selenium~=4.34.2
tqdm~=4.66.4

View File

@@ -52,7 +52,11 @@
background-color: var(--color2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color7);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}

419
templates/functionality.js Normal file
View File

@@ -0,0 +1,419 @@
class PhotoGallery {
constructor() {
this.pswpElement = document.querySelector(".pswp");
this.items = [];
this.shown = [];
this.subfolders = [];
this.controllers = {};
this.tagDropdownShown = false;
this.debounce = this.debounce.bind(this);
this.openSwipe = this.openSwipe.bind(this);
this.prefetch = this.prefetch.bind(this);
this.cancel = this.cancel.bind(this);
this.reset = this.reset.bind(this);
this.recursive = this.recursive.bind(this);
this.requestMetadata = this.requestMetadata.bind(this);
this.filter = this.filter.bind(this);
this.updateImageList = this.updateImageList.bind(this);
this.setFilter = this.setFilter.bind(this);
this.toggleTag = this.toggleTag.bind(this);
this.setupDropdownToggle = this.setupDropdownToggle.bind(this);
this.setupTagHandlers = this.setupTagHandlers.bind(this);
this.setupClickHandlers = this.setupClickHandlers.bind(this);
this.scrollFunction = this.scrollFunction.bind(this);
this.topFunction = this.topFunction.bind(this);
this.onLoad = this.onLoad.bind(this);
this.init();
}
debounce(fn, delay) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
openSwipe(imgIndex) {
const options = { index: imgIndex };
const gallery = new PhotoSwipe(
this.pswpElement,
PhotoSwipeUI_Default,
this.shown,
options
);
gallery.init();
}
prefetch(imgIndex) {
if (this.controllers[imgIndex]) {
this.cancel(imgIndex);
}
const controller = new AbortController();
const signal = controller.signal;
this.controllers[imgIndex] = controller;
const urlToFetch = this.shown[imgIndex]?.src;
if (urlToFetch) {
fetch(urlToFetch, { method: "GET", signal }).catch(() => {});
}
}
cancel(imgIndex) {
if (this.controllers[imgIndex]) {
this.controllers[imgIndex].abort();
delete this.controllers[imgIndex];
}
}
reset() {
const content = document.documentElement.innerHTML;
const title = document.title;
const folders = document.querySelector(".folders");
let path = window.location.origin + window.location.pathname;
if (path.startsWith("null")) {
path = window.location.protocol + "//" + path.substring(4);
}
if (folders) folders.style.display = "";
document.getElementById("recursive").checked = false;
document
.querySelectorAll("#tagdropdown input.tagcheckbox:checked")
.forEach((checkbox) => (checkbox.checked = false));
window.history.replaceState({ html: content, pageTitle: title }, "", path);
this.requestMetadata();
}
showLoader() {
const imagelist = document.getElementById("imagelist");
imagelist.innerHTML = '<span class="loader"></span>';
imagelist.classList.add("centerload");
imagelist.classList.remove("row");
}
async recursive() {
this.showLoader();
const loc = new URL(window.location.href);
const content = document.documentElement.innerHTML;
const title = document.title;
const isChecked = document.getElementById("recursive")?.checked;
const folders = document.querySelector(".folders");
if (!isChecked) {
if (folders) folders.style.display = "";
loc.searchParams.delete("recursive");
window.history.replaceState({ html: content, pageTitle: title }, "", loc);
this.requestMetadata();
return;
}
if (folders) folders.style.display = "none";
loc.searchParams.delete("recursive");
loc.searchParams.append("recursive", true);
window.history.replaceState({ html: content, pageTitle: title }, "", loc);
const visited = new Set();
const existingItems = new Set();
const newItems = [];
try {
const response = await fetch(".metadata.json");
if (!response.ok) throw new Error("Failed to fetch metadata");
const data = await response.json();
this.items = [];
this.subfolders = data.subfolders || [];
for (const image of Object.values(data.images || {})) {
newItems.push(image);
existingItems.add(image.src);
}
} catch {
return;
}
const fetchFoldersRecursively = async (folderList) => {
if (!Array.isArray(folderList)) return;
const nextLevel = [];
await Promise.all(
folderList.map(async (folder) => {
if (!folder || !folder.metadata || visited.has(folder.url)) return;
visited.add(folder.url);
try {
const response = await fetch(folder.metadata);
if (!response.ok) throw new Error();
const data = await response.json();
for (const image of Object.values(data.images || {})) {
if (!existingItems.has(image.src)) {
newItems.push(image);
existingItems.add(image.src);
}
}
if (Array.isArray(data.subfolders))
nextLevel.push(...data.subfolders);
} catch {}
})
);
if (nextLevel.length > 0) await fetchFoldersRecursively(nextLevel);
};
await fetchFoldersRecursively(this.subfolders);
this.items = [...newItems];
this.filter();
}
requestMetadata() {
this.showLoader();
const hash = window.location.hash;
const searchParams = new URLSearchParams(window.location.search);
fetch(".metadata.json")
.then((response) => {
if (!response.ok) throw new Error("Failed to fetch metadata");
return response.json();
})
.then((data) => {
this.items = Object.values(data.images || {});
this.subfolders = data.subfolders || [];
if (hash != "") {
const selected = hash.replace("#", "").split(",");
this.setFilter(selected);
}
if (searchParams.get("recursive") != null) {
const recChk = document.getElementById("recursive");
if (recChk) recChk.checked = true;
this.recursive();
} else {
this.filter();
}
})
.catch(() => {});
}
filter() {
const searchParams = new URLSearchParams(window.location.search);
this.shown = [];
let path = decodeURIComponent(
window.location.origin +
window.location.pathname.replace("index.html", "")
);
if (path.startsWith("null")) {
path = window.location.protocol + "//" + path.substring(4);
}
const selectedTags = [];
document
.querySelectorAll("#tagdropdown input.tagcheckbox:checked")
.forEach((checkbox) => {
let tag = checkbox.parentElement.id.trim().substring(1);
if (checkbox.parentElement.parentElement.children.length > 1)
tag += "|";
selectedTags.push(tag);
});
const urltags = selectedTags.join(",");
let isRecursiveChecked = false;
try {
isRecursiveChecked =
document.getElementById("recursive")?.checked || false;
} catch {}
for (const item of this.items) {
const tags = item.tags || [];
const include = selectedTags.every((selected) => {
const isParent = selected.endsWith("|");
return isParent
? tags.some((t) => t.startsWith(selected))
: tags.includes(selected);
});
if (include || selectedTags.length === 0) {
if (!isRecursiveChecked) {
if (decodeURIComponent(item.src).replace(item.name, "") === path) {
this.shown.push(item);
}
} else {
this.shown.push(item);
}
}
}
this.updateImageList();
window.location.hash = urltags;
const pid = searchParams.get("pid") - 1;
if (pid != -1) {
this.openSwipe(pid);
}
}
updateImageList() {
const imagelist = document.getElementById("imagelist");
if (!imagelist) return;
let str = "";
this.shown.forEach((item, index) => {
str += `<div class="column"><figure><img src="${item.msrc}" data-index="${index}" /><figcaption class="caption">${item.name}`;
if (item.tiff) str += `&nbsp;<a href="${item.tiff}">TIFF</a>`;
if (item.raw) str += `&nbsp;<a href="${item.raw}">RAW</a>`;
str += "</figcaption></figure></div>";
});
imagelist.classList.add("row");
imagelist.classList.remove("centerload");
imagelist.innerHTML = str;
}
setFilter(selected) {
document
.querySelectorAll("#tagdropdown input.tagcheckbox")
.forEach((checkbox) => {
selected.forEach((tag) => {
if (
checkbox.parentElement.id
.trim()
.substring(1)
.replace(" ", "%20") === tag
) {
checkbox.checked = true;
}
});
});
}
toggleTag(tagid) {
const tag = document.getElementById(tagid);
const ol = tag?.closest(".tagentry")?.querySelector(".tagentryparent");
const svg = tag?.parentElement.querySelector(".tagtoggle svg");
if (!ol || !svg) return;
ol.classList.toggle("show");
svg.style.transform = ol.classList.contains("show")
? "rotate(180deg)"
: "rotate(0deg)";
}
setupDropdownToggle() {
const toggleLink = document.getElementById("tagtogglelink");
const dropdown = document.getElementById("tagdropdown");
if (!toggleLink) return;
toggleLink.addEventListener("click", (event) => {
event.stopPropagation();
const svg = toggleLink.querySelector("svg");
dropdown.classList.toggle("show");
if (svg)
svg.style.transform = dropdown.classList.contains("show")
? "rotate(180deg)"
: "rotate(0deg)";
this.tagDropdownShown = dropdown.classList.contains("show");
});
document.addEventListener("click", (event) => {
if (
!dropdown.contains(event.target) &&
!toggleLink.contains(event.target)
) {
dropdown.classList.remove("show");
this.tagDropdownShown = false;
const svg = toggleLink.querySelector("svg");
if (svg) svg.style.transform = "rotate(0deg)";
}
});
}
setupTagHandlers() {
const tagContainer = document.getElementById("tagdropdown");
if (!tagContainer) return;
const debouncedFilter = this.debounce(this.filter, 150);
tagContainer.addEventListener("change", debouncedFilter);
tagContainer.addEventListener("click", (event) => {
const toggle = event.target.closest(".tagtoggle");
if (toggle) {
event.stopPropagation();
const tagid = toggle.dataset.toggleid;
this.toggleTag(tagid);
}
});
}
setupClickHandlers() {
const resetEl = document
.getElementById("reset-filter")
?.querySelector("label");
if (resetEl) resetEl.addEventListener("click", this.reset);
const recurseEl = document.getElementById("recursive");
if (recurseEl)
recurseEl.addEventListener("change", this.debounce(this.recursive, 150));
const totop = document.getElementById("totop");
if (totop) totop.addEventListener("click", this.topFunction);
const imagelist = document.getElementById("imagelist");
if (imagelist) {
imagelist.addEventListener("click", (event) => {
const img = event.target.closest("img");
if (!img || !img.dataset.index) return;
const index = parseInt(img.dataset.index);
if (!isNaN(index)) this.openSwipe(index);
});
imagelist.addEventListener("mouseover", (event) => {
const img = event.target.closest("img");
if (!img || !img.dataset.index) return;
const index = parseInt(img.dataset.index);
if (!isNaN(index)) this.prefetch(index);
});
imagelist.addEventListener("mouseleave", (event) => {
const img = event.target.closest("img");
if (!img || !img.dataset.index) return;
const index = parseInt(img.dataset.index);
if (!isNaN(index)) this.cancel(index);
});
}
}
scrollFunction() {
const totopbutton = document.getElementById("totop");
if (!totopbutton) return;
if (
document.body.scrollTop > 20 ||
document.documentElement.scrollTop > 20
) {
totopbutton.style.display = "block";
} else {
totopbutton.style.display = "none";
}
}
topFunction() {
window.scrollTo({ top: 0, behavior: "smooth" });
}
onLoad() {
document.querySelectorAll(".tagtoggle").forEach((toggle) => {
toggle.addEventListener("mouseup", (event) => {
event.stopPropagation();
const tagid = toggle.getAttribute("data-tagid");
this.toggleTag(tagid);
});
});
this.requestMetadata();
this.setupDropdownToggle();
this.setupTagHandlers();
this.setupClickHandlers();
window.addEventListener("scroll", this.scrollFunction);
}
init() {
if (window.addEventListener) {
window.addEventListener("load", this.onLoad, false);
} else if (window.attachEvent) {
window.attachEvent("onload", this.onLoad);
}
}
}

View File

@@ -1,3 +1,25 @@
{%- macro render_tags(tag_tree, parent) -%}
{%- for key, value in tag_tree.items() %}
<li class="tagentry">
<div class="tagflex">
<label class="tag" title="{{ key }}" id="{{ parent }}|{{ key }}">
<input type="checkbox" class="tagcheckbox" />{{ key }}
</label>{% if value %} <span class="tagtoggle" data-tagid="{{ parent }}|{{ key }}">
<svg width="1em" height="1em" viewBox="0 0 129.87601 129.87624">
<g id="layer1" transform="translate(-33.816833,-52.685642)">
<path stroke="currentColor" style="fill:none;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 54.476483,95.484647 98.754836,139.76308 143.03319,95.484647" id="path1" />
</g>
</svg></span>{% endif %}
</div>
{%- if value %}
<ol class="tagentryparent">
{{ render_tags(value, parent + '|' + key) }}
</ol>
{%- endif %}
</li><br>
{%- endfor %}
{%- endmacro -%}
<!DOCTYPE html>
<html lang="en">
@@ -6,7 +28,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
{%- if webmanifest %}
<link rel="manifest" href="/.static/manifest.json">
<link rel="manifest" href="/.static/manifest.webmanifest">
{%- endif %}
<link rel="preload" href="{{ stylesheet }}" as="style">
{%- if theme %}
@@ -21,12 +43,12 @@
<link rel="preload" href="{{ root }}.static/pswp/default-skin/default-skin.css" as="style">
<link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe.min.js">
<link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe-ui-default.min.js">
{%- if images %}
<link rel="modulepreload" href="{{ root }}.static/functionality.min.js">
<link rel="stylesheet" href="{{ root }}.static/pswp/photoswipe.css">
<link rel="stylesheet" href="{{ root }}.static/pswp/default-skin/default-skin.css">
<script src="{{ root }}.static/pswp/photoswipe.min.js"></script>
<script src="{{ root }}.static/pswp/photoswipe-ui-default.min.js"></script>
{%- endif %}
<script src="{{ root }}.static/functionality.min.js"></script>
</head>
<body>
@@ -49,24 +71,31 @@
<li class="title"><span class="header">{{ header }}</span></li>
</div>
<div class="navright">
{%- if tags|length > 0 %}
<li class="tooltip"><a>Filter by Tags</a>
{% if tags %}
<li class="tooltip">
<a id="tagtogglelink">Filter by Tags <svg width="0.8em" height="0.8em" viewBox="0 0 129.87601 129.87624">
<g id="layer1" transform="translate(-33.816833,-52.685642)">
<path stroke="currentColor" style="fill:none;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 54.476483,95.484647 98.754836,139.76308 143.03319,95.484647" id="path1" />
</g>
</svg></a>
<ol class="tooltiptext tagdropdown" id="tagdropdown">
{%- for tag in tags -%}
<li class="tagentry"><label onclick="filter()"><input type="checkbox" />{{ tag }}</label></li><br />
{%- endfor -%}
<span class="tagentry" id="reset-filter"><label>reset filter</label></span>
<span class="tagentry">
<label>
<input type="checkbox" id="recursive" />recursive filter
</label>
</span>
{{ render_tags(tags, '') }}
</ol>
</li>
{%- endif %}
{% endif %}
{%- if licensefile %}
<li class="license"><a href="{{ licensefile }}">License</a></li>
{%- endif %}
</div>
</ol>
{% if subdirectories %}
{%- for subdirectory in subdirectories %}
<link rel="preload" href="{{ subdirectory.url }}/index.html" type="text/html">
{%- endfor %}
<div class="folders">
{%- for subdirectory in subdirectories %}
<a href="{{ subdirectory.url }}">
@@ -82,11 +111,8 @@
</div>
{%- endif %}
</div>
{% if images %}
{%- set ns = namespace(count = 0) -%}
<div class="row" id="imagelist">
</div>
{%- endif %}
{% if license %}
{%- if 'CC' in license.type %}
<div class="footer" xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/">
@@ -107,17 +133,16 @@
{%- endif %}
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
<button type="button" id="totop" title="Back to Top">Back to Top</button>
</div>
{%- endif %}
{%- else %}
<div class="footer">
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
<button type="button" id="totop" title="Back to Top">Back to Top</button>
</div>
{%- endif %}
{% if images %}
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<div class="pswp__bg"></div>
<div class="pswp__scroll-wrap">
@@ -154,114 +179,9 @@
</div>
</div>
</div>
<script>
var pswpElement = document.querySelectorAll('.pswp')[0];
var items = [
{%- for image in images %}
{%- if image.exifdata.DateTime %}
{ name: "{{ image.name }}", tiff: "{{ image.tiff }}", raw: "{{ image.raw }}", src: "{{ image.url }}", w: {{ image.width }}, h: {{ image.height }}, msrc: "{{ image.thumbnail }}", tags: "{{ image.tags }}", title: "Captured: {{ image.exifdata.DateTime }}" },
{%- else %}
{ name: "{{ image.name }}", tiff: "{{ image.tiff }}", raw: "{{ image.raw }}", src: "{{ image.url }}", w: {{ image.width }}, h: {{ image.height }}, msrc: "{{ image.thumbnail }}", tags: "{{ image.tags }}" },
{%- endif %}
{%- endfor %}
];
var shown = [];
var re = /pid=(\d+)/;
var controllers = {}
function openSwipe(img) {
var options = {
index: img
};
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, shown, options);
gallery.init();
}
let totopbutton = document.getElementById("totop");
window.onscroll = function () { scrollFunction() };
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
totopbutton.style.display = "block";
} else {
totopbutton.style.display = "none";
}
}
function topFunction() {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
window.onload = function () { filter() };
function updateImageList() {
var str = ""
var imagelist = document.getElementById("imagelist");
shown.forEach((item, index) => {
str += '<div class="column"><figure><img src="' + item.msrc + '" onclick="openSwipe(' + index + ')" onmouseover="prefetch(' + index + ')" onmouseleave="cancel(' + index + ')" /><figcaption class="caption">' + item.name;
if (item.tiff != "") {
str += ' <a href="' + item.tiff + '">TIFF</a>';
}
if (item.raw != "") {
str += ' <a href="' + item.raw + '">RAW</a>';
}
str += '</figcaption></figure></div>';
});
imagelist.innerHTML = str;
}
function prefetch(img) {
const controller = new AbortController()
const signal = controller.signal
controllers[img] = controller;
let urlToFetch = items[img].src;
fetch(urlToFetch, {
method: 'get',
signal: signal,
}).catch(function (err) { });
}
function cancel(img) {
controllers[img].abort();
delete controllers[img];
}
function filter() {
var selected_tags = [];
var tagdropdown, tags, incl;
shown = [];
tagdropdown = document.getElementById("tagdropdown").getElementsByTagName("li");
for (var i = 0; i < tagdropdown.length; i++) {
if (tagdropdown[i].firstChild.firstChild.checked) {
selected_tags.push([tagdropdown[i].innerText])
}
}
items.forEach((item, index) => {
tags = item.tags;
incl = true;
selected_tags.forEach((tag) => {
if (tags.indexOf(tag) == -1) {
incl = false;
}
});
if (incl | selected_tags == []) {
shown.push(item)
}
});
updateImageList();
if (re.test(window.location.href)) {
var pid = window.location.href.match(re)[1];
console.log(pid);
console.log(shown);
openSwipe(parseInt(pid));
}
}
</script>
{%- endif %}
</body>
<script>
new PhotoGallery();
</script>
</html>

View File

@@ -21,13 +21,16 @@
<body>
<div class="header">
<ul class="navbar">
<ol class="navbar">
<div class="navleft">
<li><a href="{{ root }}">Home</a></li>
{%- if parent %}
<li><a href="{{ parent }}">Parent Directory</a></li>
{%- endif %}
</div>
<div class="navcenter">
<li class="title"><span class="header">{{ header }}</span></li>
</ul>
</div>
</div>
{%- if licensefile %}
<div class="licensefile">

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC00009.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>aqueduct</rdf:li><rdf:li>arch</rdf:li><rdf:li>arch bridge</rdf:li><rdf:li>bridge</rdf:li><rdf:li>hillside</rdf:li><rdf:li>passenger train</rdf:li><rdf:li>railroad</rdf:li><rdf:li>railroad bridge</rdf:li><rdf:li>span</rdf:li><rdf:li>train track</rdf:li><rdf:li>tree</rdf:li><rdf:li>viaduct</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|aqueduct</rdf:li><rdf:li>|arch</rdf:li><rdf:li>|arch bridge</rdf:li><rdf:li>|bridge</rdf:li><rdf:li>|hillside</rdf:li><rdf:li>|passenger train</rdf:li><rdf:li>|railroad</rdf:li><rdf:li>|railroad bridge</rdf:li><rdf:li>|span</rdf:li><rdf:li>|train track</rdf:li><rdf:li>|tree</rdf:li><rdf:li>|viaduct</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
<dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>aqueduct</rdf:li><rdf:li>arch</rdf:li><rdf:li>arch bridge</rdf:li><rdf:li>bridge</rdf:li><rdf:li>hillside</rdf:li><rdf:li>passenger train</rdf:li><rdf:li>railroad</rdf:li><rdf:li>railroad bridge</rdf:li><rdf:li>span</rdf:li><rdf:li>train track</rdf:li><rdf:li>tree</rdf:li><rdf:li>viaduct</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|aqueduct</rdf:li><rdf:li>st|arch</rdf:li><rdf:li>st|arch bridge</rdf:li><rdf:li>st|bridge</rdf:li><rdf:li>st|hillside</rdf:li><rdf:li>st|passenger train</rdf:li><rdf:li>st|railroad</rdf:li><rdf:li>st|railroad bridge</rdf:li><rdf:li>st|span</rdf:li><rdf:li>st|train track</rdf:li><rdf:li>st|tree</rdf:li><rdf:li>st|viaduct</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -1,7 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03470.JPG">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>bus</rdf:li><rdf:li>illuminate</rdf:li><rdf:li>neon</rdf:li><rdf:li>passenger train</rdf:li><rdf:li>neon light</rdf:li><rdf:li>night</rdf:li><rdf:li>sign</rdf:li><rdf:li>train car</rdf:li><rdf:li>trolley</rdf:li><rdf:li>window</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|bus</rdf:li><rdf:li>|illuminate</rdf:li><rdf:li>|neon</rdf:li><rdf:li>|neon light</rdf:li><rdf:li>|night</rdf:li><rdf:li>|sign</rdf:li><rdf:li>|train car</rdf:li><rdf:li>|trolley</rdf:li><rdf:li>|window</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="DSC03470.JPG">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>bus</rdf:li>
<rdf:li>illuminate</rdf:li>
<rdf:li>neon</rdf:li>
<rdf:li>neon light</rdf:li>
<rdf:li>night</rdf:li>
<rdf:li>sign</rdf:li>
<rdf:li>train car</rdf:li>
<rdf:li>trolley</rdf:li>
<rdf:li>window</rdf:li>
<rdf:li>train</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|bus</rdf:li>
<rdf:li>st|illuminate</rdf:li>
<rdf:li>st|neon</rdf:li>
<rdf:li>st|neon light</rdf:li>
<rdf:li>st|night</rdf:li>
<rdf:li>st|sign</rdf:li>
<rdf:li>st|train car</rdf:li>
<rdf:li>st|trolley</rdf:li>
<rdf:li>st|window</rdf:li>
<rdf:li>st|train</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.ARW">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>pillar</rdf:li><rdf:li>display</rdf:li><rdf:li>rail</rdf:li><rdf:li>steam engine</rdf:li><rdf:li>steam locomotive</rdf:li><rdf:li>train</rdf:li><rdf:li>train car</rdf:li><rdf:li>train track</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|building</rdf:li><rdf:li>|ceiling</rdf:li><rdf:li>|pillar</rdf:li><rdf:li>|display</rdf:li><rdf:li>|rail</rdf:li><rdf:li>|steam engine</rdf:li><rdf:li>|steam locomotive</rdf:li><rdf:li>|train</rdf:li><rdf:li>|train car</rdf:li><rdf:li>|train track</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
<dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>pillar</rdf:li><rdf:li>display</rdf:li><rdf:li>rail</rdf:li><rdf:li>steam engine</rdf:li><rdf:li>steam locomotive</rdf:li><rdf:li>train</rdf:li><rdf:li>train car</rdf:li><rdf:li>train track</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|building</rdf:li><rdf:li>st|ceiling</rdf:li><rdf:li>st|pillar</rdf:li><rdf:li>st|display</rdf:li><rdf:li>st|rail</rdf:li><rdf:li>st|steam engine</rdf:li><rdf:li>st|steam locomotive</rdf:li><rdf:li>st|train</rdf:li><rdf:li>st|train car</rdf:li><rdf:li>st|train track</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -1,7 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.JPG">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>attach</rdf:li><rdf:li>basement</rdf:li><rdf:li>beam</rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>equipment</rdf:li><rdf:li>floor</rdf:li><rdf:li>pipe</rdf:li><rdf:li>red</rdf:li><rdf:li>room</rdf:li><rdf:li>scaffold</rdf:li><rdf:li>tube</rdf:li><rdf:li>warehouse</rdf:li><rdf:li>water pipe</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|attach</rdf:li><rdf:li>|basement</rdf:li><rdf:li>|beam</rdf:li><rdf:li>|building</rdf:li><rdf:li>|ceiling</rdf:li><rdf:li>|equipment</rdf:li><rdf:li>|floor</rdf:li><rdf:li>|pipe</rdf:li><rdf:li>|red</rdf:li><rdf:li>|room</rdf:li><rdf:li>|scaffold</rdf:li><rdf:li>|tube</rdf:li><rdf:li>|warehouse</rdf:li><rdf:li>|water pipe</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="DSC03508.JPG">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>attach</rdf:li>
<rdf:li>basement</rdf:li>
<rdf:li>beam</rdf:li>
<rdf:li>building</rdf:li>
<rdf:li>ceiling</rdf:li>
<rdf:li>equipment</rdf:li>
<rdf:li>floor</rdf:li>
<rdf:li>pipe</rdf:li>
<rdf:li>red</rdf:li>
<rdf:li>room</rdf:li>
<rdf:li>scaffold</rdf:li>
<rdf:li>tube</rdf:li>
<rdf:li>warehouse</rdf:li>
<rdf:li>water pipe</rdf:li>
<rdf:li>train</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|attach</rdf:li>
<rdf:li>st|basement</rdf:li>
<rdf:li>st|beam</rdf:li>
<rdf:li>st|building</rdf:li>
<rdf:li>st|ceiling</rdf:li>
<rdf:li>st|equipment</rdf:li>
<rdf:li>st|floor</rdf:li>
<rdf:li>st|pipe</rdf:li>
<rdf:li>st|red</rdf:li>
<rdf:li>st|room</rdf:li>
<rdf:li>st|scaffold</rdf:li>
<rdf:li>st|tube</rdf:li>
<rdf:li>st|warehouse</rdf:li>
<rdf:li>st|water pipe</rdf:li>
<rdf:li>st|train</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -1,7 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|cloud</rdf:li><rdf:li>|cloudy</rdf:li><rdf:li>|evening sky</rdf:li><rdf:li>|sea</rdf:li><rdf:li>|sky</rdf:li><rdf:li>|storm cloud</rdf:li><rdf:li>|stormy</rdf:li><rdf:li>|sun</rdf:li><rdf:li>|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="example.jpg">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>cloudy</rdf:li>
<rdf:li>evening sky</rdf:li>
<rdf:li>sea</rdf:li>
<rdf:li>sky</rdf:li>
<rdf:li>storm cloud</rdf:li>
<rdf:li>stormy</rdf:li>
<rdf:li>sun</rdf:li>
<rdf:li>sunset</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|cloudy</rdf:li>
<rdf:li>st|evening sky</rdf:li>
<rdf:li>st|sea</rdf:li>
<rdf:li>st|sky</rdf:li>
<rdf:li>st|storm cloud</rdf:li>
<rdf:li>st|stormy</rdf:li>
<rdf:li>st|sun</rdf:li>
<rdf:li>st|sunset</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.tif">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|cloud</rdf:li><rdf:li>|cloudy</rdf:li><rdf:li>|evening sky</rdf:li><rdf:li>|sea</rdf:li><rdf:li>|sky</rdf:li><rdf:li>|storm cloud</rdf:li><rdf:li>|stormy</rdf:li><rdf:li>|sun</rdf:li><rdf:li>|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
<dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|cloud</rdf:li><rdf:li>st|cloudy</rdf:li><rdf:li>st|evening sky</rdf:li><rdf:li>st|sea</rdf:li><rdf:li>st|sky</rdf:li><rdf:li>st|storm cloud</rdf:li><rdf:li>st|stormy</rdf:li><rdf:li>st|sun</rdf:li><rdf:li>st|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

Before

Width:  |  Height:  |  Size: 3.5 MiB

After

Width:  |  Height:  |  Size: 3.5 MiB

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="DSC01106.jpg">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>clear</rdf:li>
<rdf:li>dark</rdf:li>
<rdf:li>moon</rdf:li>
<rdf:li>night</rdf:li>
<rdf:li>night sky</rdf:li>
<rdf:li>sky</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|clear</rdf:li>
<rdf:li>st|dark</rdf:li>
<rdf:li>st|moon</rdf:li>
<rdf:li>st|night</rdf:li>
<rdf:li>st|sky|night sky</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 MiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="000041900001.jpg">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>cloud</rdf:li>
<rdf:li>fly</rdf:li>
<rdf:li>sky</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|cloud</rdf:li>
<rdf:li>st|fly</rdf:li>
<rdf:li>st|sky</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC01106.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>clear</rdf:li><rdf:li>dark</rdf:li><rdf:li>moon</rdf:li><rdf:li>night</rdf:li><rdf:li>night sky</rdf:li><rdf:li>sky</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|clear</rdf:li><rdf:li>|dark</rdf:li><rdf:li>|moon</rdf:li><rdf:li>|night</rdf:li><rdf:li>|night sky</rdf:li><rdf:li>|sky</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="000041900001.tif">
<dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>fly</rdf:li><rdf:li>sky</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|cloud</rdf:li><rdf:li>st|cloudy</rdf:li><rdf:li>st|fly</rdf:li><rdf:li>st|sky</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -97,7 +97,11 @@ body {
background-color: var(--color6);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
@@ -114,3 +118,23 @@ body {
color: var(--bcolor1);
font-weight: 600;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
display: inline-block;
border-top: 3px solid var(--bcolor1);
border-right: 3px solid transparent;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@@ -96,7 +96,11 @@ body {
background-color: var(--color3);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color7);
}
.tagentry .tagtoggle:hover {
background-color: var(--color7);
}
@@ -113,3 +117,23 @@ body {
color: var(--bcolor2);
font-weight: 600;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
display: inline-block;
border-top: 3px solid var(--bcolor2);
border-right: 3px solid transparent;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@@ -74,7 +74,11 @@
background-color: var(--bcolor1);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
@@ -92,6 +96,52 @@
font-weight: 600;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
position: relative;
animation: rotate 1s linear infinite
}
.loader::before {
content: "";
box-sizing: border-box;
position: absolute;
inset: 0px;
border-radius: 50%;
border: 5px solid var(--bcolor2);
animation: prixClipFix 2s linear infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg)
}
}
@keyframes prixClipFix {
0% {
clip-path: polygon(50% 50%, 0 0, 0 0, 0 0, 0 0, 0 0)
}
25% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 0, 100% 0, 100% 0)
}
50% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 100% 100%, 100% 100%)
}
75% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 100%)
}
100% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 0)
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);

View File

@@ -74,7 +74,11 @@
background-color: var(--bcolor1);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
@@ -92,6 +96,52 @@
font-weight: 600;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
position: relative;
animation: rotate 1s linear infinite
}
.loader::before {
content: "";
box-sizing: border-box;
position: absolute;
inset: 0px;
border-radius: 50%;
border: 5px solid var(--bcolor2);
animation: prixClipFix 2s linear infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg)
}
}
@keyframes prixClipFix {
0% {
clip-path: polygon(50% 50%, 0 0, 0 0, 0 0, 0 0, 0 0)
}
25% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 0, 100% 0, 100% 0)
}
50% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 100% 100%, 100% 100%)
}
75% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 100%)
}
100% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 0)
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);

View File

@@ -1,14 +1,22 @@
@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700;800;900&display=swap");
* {
--color1: #FF7F50; /* Coral */
--color2: #D2691E; /* Chocolate */
--color3: #8B4513; /* SaddleBrown */
--color4: #FFA07A; /* LightSalmon */
--bcolor1: #FFF8DC; /* Cornsilk */
--bcolor2: #2F4F4F; /* DarkSlateGray */
--bcolor3: #3E2723; /* Darker brown */
--bcolor4: #4E342E; /* Slightly lighter brown */
--color1: #FF7F50;
/* Coral */
--color2: #D2691E;
/* Chocolate */
--color3: #8B4513;
/* SaddleBrown */
--color4: #FFA07A;
/* LightSalmon */
--bcolor1: #FFF8DC;
/* Cornsilk */
--bcolor2: #2F4F4F;
/* DarkSlateGray */
--bcolor3: #3E2723;
/* Darker brown */
--bcolor4: #4E342E;
/* Slightly lighter brown */
}
.navbar {
@@ -79,7 +87,11 @@
font-family: "Playfair Display", serif;
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
@@ -98,6 +110,54 @@
font-family: "Playfair Display", serif;
}
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 2.5em;
height: 2.5em;
animation-fill-mode: both;
animation: bblFadInOut 1.8s infinite ease-in-out;
}
.loader {
color: var(--bcolor2);
font-size: 7px;
position: relative;
text-indent: -9999em;
transform: translateZ(0);
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
content: '';
position: absolute;
top: 0;
}
.loader:before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader:after {
left: 3.5em;
}
@keyframes bblFadInOut {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em
}
40% {
box-shadow: 0 2.5em 0 0
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);

View File

@@ -73,7 +73,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
@@ -91,6 +95,36 @@
font-weight: 800;
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--color1);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);

View File

@@ -79,7 +79,11 @@
font-family: "Nunito", sans-serif;
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color4);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}
@@ -99,6 +103,91 @@
font-family: "Nunito", sans-serif;
}
.loader {
transform: rotateZ(45deg);
perspective: 1000px;
border-radius: 50%;
width: 48px;
height: 48px;
color: var(--color1);
}
.loader:before,
.loader:after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
border-radius: 50%;
transform: rotateX(70deg);
animation: 1s spin linear infinite;
}
.loader:after {
color: var(--bcolor4);
transform: rotateY(70deg);
animation-delay: .4s;
}
@keyframes rotate {
0% {
transform: translate(-50%, -50%) rotateZ(0deg);
}
100% {
transform: translate(-50%, -50%) rotateZ(360deg);
}
}
@keyframes rotateccw {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(-360deg);
}
}
@keyframes spin {
0%,
100% {
box-shadow: .2em 0px 0 0px currentcolor;
}
12% {
box-shadow: .2em .2em 0 0 currentcolor;
}
25% {
box-shadow: 0 .2em 0 0px currentcolor;
}
37% {
box-shadow: -.2em .2em 0 0 currentcolor;
}
50% {
box-shadow: -.2em 0 0 0 currentcolor;
}
62% {
box-shadow: -.2em -.2em 0 0 currentcolor;
}
75% {
box-shadow: 0px -.2em 0 0 currentcolor;
}
87% {
box-shadow: .2em -.2em 0 0 currentcolor;
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);

View File

@@ -73,7 +73,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
@@ -91,6 +95,36 @@
font-weight: 800;
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--color1);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);

View File

@@ -52,7 +52,11 @@
background-color: var(--color3);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color4);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}
@@ -70,6 +74,27 @@
font-weight: 800;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
display: inline-block;
border-top: 3px solid var(--bcolor1);
border-right: 3px solid transparent;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
body {
color: var(--bcolor1);
background-color: var(--color4);

View File

@@ -52,7 +52,11 @@
background-color: var(--color2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color4);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}
@@ -70,6 +74,27 @@
font-weight: 800;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
display: inline-block;
border-top: 3px solid var(--bcolor2);
border-right: 3px solid transparent;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor1);

View File

@@ -73,7 +73,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
@@ -89,6 +93,36 @@
background-color: var(--color1);
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--color1);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);

View File

@@ -72,7 +72,11 @@
background-color: var(--color3);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color2);
}
.tagentry .tagtoggle:hover {
background-color: var(--color2);
}
@@ -90,6 +94,36 @@
font-weight: 800;
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--bcolor1);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor2);

View File

@@ -55,7 +55,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
@@ -73,6 +77,91 @@
font-weight: 800;
}
.loader {
transform: rotateZ(45deg);
perspective: 1000px;
border-radius: 50%;
width: 48px;
height: 48px;
color: var(--color2);
}
.loader:before,
.loader:after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
border-radius: 50%;
transform: rotateX(70deg);
animation: 1s spin linear infinite;
}
.loader:after {
color: var(--color4);
transform: rotateY(70deg);
animation-delay: .4s;
}
@keyframes rotate {
0% {
transform: translate(-50%, -50%) rotateZ(0deg);
}
100% {
transform: translate(-50%, -50%) rotateZ(360deg);
}
}
@keyframes rotateccw {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(-360deg);
}
}
@keyframes spin {
0%,
100% {
box-shadow: .2em 0px 0 0px currentcolor;
}
12% {
box-shadow: .2em .2em 0 0 currentcolor;
}
25% {
box-shadow: 0 .2em 0 0px currentcolor;
}
37% {
box-shadow: -.2em .2em 0 0 currentcolor;
}
50% {
box-shadow: -.2em 0 0 0 currentcolor;
}
62% {
box-shadow: -.2em -.2em 0 0 currentcolor;
}
75% {
box-shadow: 0px -.2em 0 0 currentcolor;
}
87% {
box-shadow: .2em -.2em 0 0 currentcolor;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor4);

View File

@@ -76,7 +76,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
@@ -94,6 +98,36 @@
font-weight: 800;
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--color4);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor3);
background-color: var(--bcolor1);

View File

@@ -1,14 +1,22 @@
@import url("https://fonts.googleapis.com/css2?family=Lora:wght@300;400;500;600;700&display=swap");
* {
--color1: #FFB6C1; /* LightPink */
--color2: #98FB98; /* PaleGreen */
--color3: #FFD700; /* Gold */
--color4: #87CEFA; /* LightSkyBlue */
--bcolor1: #FFFFFF; /* White */
--bcolor2: #2F4F4F; /* DarkSlateGray */
--bcolor3: #FAF0E6; /* Linen */
--bcolor4: #E6E6FA; /* Lavender */
--color1: #FFB6C1;
/* LightPink */
--color2: #98FB98;
/* PaleGreen */
--color3: #FFD700;
/* Gold */
--color4: #87CEFA;
/* LightSkyBlue */
--bcolor1: #FFFFFF;
/* White */
--bcolor2: #2F4F4F;
/* DarkSlateGray */
--bcolor3: #FAF0E6;
/* Linen */
--bcolor4: #E6E6FA;
/* Lavender */
}
.navbar {
@@ -79,7 +87,11 @@
font-family: "Lora", serif;
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
@@ -98,6 +110,54 @@
font-family: "Lora", serif;
}
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 2.5em;
height: 2.5em;
animation-fill-mode: both;
animation: bblFadInOut 1.8s infinite ease-in-out;
}
.loader {
color: var(--bcolor2);
font-size: 7px;
position: relative;
text-indent: -9999em;
transform: translateZ(0);
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
content: '';
position: absolute;
top: 0;
}
.loader:before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader:after {
left: 3.5em;
}
@keyframes bblFadInOut {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em
}
40% {
box-shadow: 0 2.5em 0 0
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);

View File

@@ -80,7 +80,11 @@
background-color: var(--color4);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
@@ -98,6 +102,52 @@
font-weight: 700;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
position: relative;
animation: rotate 1s linear infinite
}
.loader::before {
content: "";
box-sizing: border-box;
position: absolute;
inset: 0px;
border-radius: 50%;
border: 5px solid var(--color2);
animation: prixClipFix 2s linear infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg)
}
}
@keyframes prixClipFix {
0% {
clip-path: polygon(50% 50%, 0 0, 0 0, 0 0, 0 0, 0 0)
}
25% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 0, 100% 0, 100% 0)
}
50% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 100% 100%, 100% 100%)
}
75% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 100%)
}
100% {
clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 0)
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor2);

View File

@@ -80,7 +80,11 @@
font-family: "Roboto", sans-serif;
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
color: var(--bcolor2);
}
@@ -100,6 +104,54 @@
font-family: "Roboto", sans-serif;
}
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 2.5em;
height: 2.5em;
animation-fill-mode: both;
animation: bblFadInOut 1.8s infinite ease-in-out;
}
.loader {
color: var(--bcolor2);
font-size: 7px;
position: relative;
text-indent: -9999em;
transform: translateZ(0);
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
content: '';
position: absolute;
top: 0;
}
.loader:before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader:after {
left: 3.5em;
}
@keyframes bblFadInOut {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em
}
40% {
box-shadow: 0 2.5em 0 0
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);

View File

@@ -74,7 +74,11 @@
background-color: var(--bcolor2);
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
@@ -92,6 +96,36 @@
font-weight: 800;
}
.loader {
width: 12px;
height: 12px;
border-radius: 50%;
display: block;
margin: 15px auto;
position: relative;
color: var(--color1);
box-sizing: border-box;
animation: animloader 1s linear infinite alternate;
}
@keyframes animloader {
0% {
box-shadow: -38px -12px, -14px 0, 14px 0, 38px 0;
}
33% {
box-shadow: -38px 0px, -14px -12px, 14px 0, 38px 0;
}
66% {
box-shadow: -38px 0px, -14px 0, 14px -12px, 38px 0;
}
100% {
box-shadow: -38px 0, -14px 0, 14px 0, 38px -12px;
}
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);

View File

@@ -88,7 +88,11 @@
font-family: "Montserrat", sans-serif;
}
.tagentry:hover {
.tagentry label:hover {
background-color: var(--color2);
}
.tagentry .tagtoggle:hover {
background-color: var(--color2);
}
@@ -107,6 +111,54 @@
font-family: "Montserrat", sans-serif;
}
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 2.5em;
height: 2.5em;
animation-fill-mode: both;
animation: bblFadInOut 1.8s infinite ease-in-out;
}
.loader {
color: var(--bcolor2);
font-size: 7px;
position: relative;
text-indent: -9999em;
transform: translateZ(0);
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
content: '';
position: absolute;
top: 0;
}
.loader:before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader:after {
left: 3.5em;
}
@keyframes bblFadInOut {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em
}
40% {
box-shadow: 0 2.5em 0 0
}
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);