39 Commits

Author SHA1 Message Date
6593e63ea9 updated themes version 2026-02-04 08:41:54 +01:00
027a5688cb updated dependencies 2026-02-04 07:53:28 +01:00
1aa9dd716b recursive darktheme applied 2026-02-04 07:17:29 +01:00
d1f7f62229 added automatic dark theme detection and dark mode switch 2026-02-03 15:35:45 +01:00
2f37f78039 updated subproject 2026-01-26 15:49:28 +01:00
b109627bf9 fixed so symlink gets resolved 2026-01-26 15:47:10 +01:00
4ef1b429f2 version bump 2026-01-07 14:36:21 +01:00
b8314c0e3d don't leave progressbar 2026-01-07 08:15:56 +01:00
60f3ca1f20 reduced thumbnail quality 2025-12-11 08:59:40 +01:00
bc519ac5d0 Remove duplicate 'Star History' section
Removed duplicate 'Star History' section from README.
2025-12-10 13:30:26 +01:00
b0c1b2ce48 Add Star History section to README 2025-12-10 13:29:56 +01:00
faa283efa3 tags optional 2025-11-25 07:07:47 +01:00
ce70aa7bd9 changed python version 2025-11-07 09:22:47 +01:00
59c7cfd406 breaking change: new requirement ConfigArgParse 2025-11-07 09:04:17 +01:00
cfe1585c39 added exception to log 2025-10-27 15:05:10 +01:00
57b6b56388 fixed TypeError 2025-10-27 12:06:14 +01:00
2c6f8fbcb7 move thumbdir declare 2025-10-27 11:12:03 +01:00
30eb1ed8df added metadata dataclass 2025-10-27 09:51:00 +01:00
0ef6e1ccf6 default [] 2025-10-27 06:49:55 +01:00
f24a24bcd2 fixed extension exclude 2025-10-22 14:53:07 +02:00
d1bf0fbc9a added --ignore-extension argument 2025-10-17 15:11:54 +02:00
285227dea7 updated themes 2025-10-10 09:32:31 +02:00
3867d56896 added submodule 2025-10-10 09:26:38 +02:00
d86da24963 moved themes to submodule 2025-10-10 09:25:29 +02:00
922b56c27e update default theme 2025-10-01 10:07:32 +02:00
a67968d222 fixed tag render in title 2025-09-29 17:33:56 +02:00
d094cd6683 test show tags in title 2025-09-29 15:14:17 +02:00
83a29bf62b fixed centering 2025-09-28 17:45:15 +02:00
0f955993ca added title 2025-09-28 16:40:06 +02:00
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
75 changed files with 4624 additions and 3014 deletions

View File

@@ -8,7 +8,9 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with: with:
python-version: '3.x' python-version: '3.12'
- name: Install PyInstaller
run: pip install pyinstaller
- name: Install Dependencies - name: Install Dependencies
run: pip install -r requirements.txt run: pip install -r requirements.txt
- name: Build Package - name: Build Package

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "themes"]
path = themes
url = https://github.com/greflm13/SGBthemes

View File

@@ -1 +1 @@
2.8.3 2.9.0

View File

@@ -103,3 +103,7 @@ To generate a web manifest file:
## License ## License
This project is licensed under the AGPL-3.0 License. See the [LICENSE](LICENSE) file for details. This project is licensed under the AGPL-3.0 License. See the [LICENSE](LICENSE) file for details.
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=greflm13/StaticGalleryBuilder&type=date&legend=top-left)](https://www.star-history.com/#greflm13/StaticGalleryBuilder&type=date&legend=top-left)

View File

@@ -90,6 +90,8 @@
"Scans", "Scans",
"--exclude-folder", "--exclude-folder",
"*/Galleries/*", "*/Galleries/*",
"--exclude-folder",
"*/Wallpaper/*",
"--folderthumbnails" "--folderthumbnails"
], ],
"console": "integratedTerminal", "console": "integratedTerminal",
@@ -160,10 +162,12 @@
} }
], ],
"prettier.htmlWhitespaceSensitivity": "css", "prettier.htmlWhitespaceSensitivity": "css",
"pylint.args": [ "python-envs.pythonProjects": [
"--disable=C0111", {
"--disable=C0301", "path": "",
"--good-names-rgxs=^[_a-z][_a-z0-9]?$" "envManager": "ms-python.python:pyenv",
"packageManager": "ms-python.python:pip"
}
], ],
"python.analysis.inlayHints.callArgumentNames": "off", "python.analysis.inlayHints.callArgumentNames": "off",
"python.analysis.inlayHints.functionReturnTypes": false, "python.analysis.inlayHints.functionReturnTypes": false,

View File

@@ -18,11 +18,7 @@ from modules.argumentparser import parse_arguments, Args
# fmt: off # fmt: off
# Constants # Constants
if __package__ is None: SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)).removesuffix(__package__ if __package__ else "")
PACKAGE = ""
else:
PACKAGE = __package__
SCRIPTDIR = os.path.abspath(os.path.dirname(__file__).removesuffix(PACKAGE))
STATIC_FILES_DIR = os.path.join(os.path.abspath(SCRIPTDIR), "files") STATIC_FILES_DIR = os.path.join(os.path.abspath(SCRIPTDIR), "files")
VERSION = open(os.path.join(SCRIPTDIR, ".version"), "r", encoding="utf-8").read() VERSION = open(os.path.join(SCRIPTDIR, ".version"), "r", encoding="utf-8").read()
RAW_EXTENSIONS = [ RAW_EXTENSIONS = [
@@ -37,8 +33,8 @@ NOT_LIST = ["*/Galleries/*", "Archives"]
args = parse_arguments(VERSION) args = parse_arguments(VERSION)
lock_file = os.path.join(args.root_directory, ".lock") LOCKFILE = os.path.join(args.root_directory, ".lock")
if os.path.exists(lock_file): if os.path.exists(LOCKFILE):
print("Another instance of this program is running.") print("Another instance of this program is running.")
sys.exit() sys.exit()
else: else:
@@ -75,7 +71,48 @@ def init_globals(_args: Args, raw: list[str]) -> tuple[Args, list[str]]:
return _args, raw return _args, raw
def copy_static_files(_args: Args) -> None: def handle_theme_icon(themepath: str, dest: str) -> None:
"""
Handle the icon specified in the theme file.
"""
logger.info("reading theme file", extra={"theme": themepath})
with open(themepath, "r", encoding="utf-8") as f:
theme = f.read()
split = theme.split(".foldericon {")
split2 = split[1].split("}", maxsplit=1)
themehead = split[0]
themetail = split2[1]
foldericon = split2[0].strip()
foldericon = re.sub(r"/\*.*\*/", "", foldericon)
for match in re.finditer(r"content: (.*);", foldericon):
foldericon = match[1]
foldericon = foldericon.replace('"', "")
logger.info("found foldericon", extra={"foldericon": foldericon})
break
if "url" in foldericon:
logger.info("foldericon in theme file, using it")
shutil.copyfile(themepath, dest)
else:
with open(os.path.join(SCRIPTDIR, foldericon), "r", encoding="utf-8") as f:
logger.info("Reading foldericon svg")
svg = f.read()
if "svg.j2" in foldericon:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(themepath)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
with open(dest, "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)
def copy_static_files(_args: Args) -> bool:
""" """
Copy static files to the root directory. Copy static files to the root directory.
@@ -85,6 +122,7 @@ def copy_static_files(_args: Args) -> None:
Parsed command-line arguments. Parsed command-line arguments.
""" """
static_dir = os.path.join(_args.root_directory, ".static") static_dir = os.path.join(_args.root_directory, ".static")
darktheme = False
if os.path.exists(static_dir): if os.path.exists(static_dir):
print("Removing existing .static folder...") print("Removing existing .static folder...")
logger.info("removing existing .static folder") logger.info("removing existing .static folder")
@@ -93,42 +131,21 @@ def copy_static_files(_args: Args) -> None:
print("Copying static files...") print("Copying static files...")
logger.info("copying static files") logger.info("copying static files")
shutil.copytree(STATIC_FILES_DIR, static_dir, dirs_exist_ok=True) shutil.copytree(STATIC_FILES_DIR, static_dir, dirs_exist_ok=True)
logger.info("reading theme file", extra={"theme": _args.theme_path})
with open(_args.theme_path, "r", encoding="utf-8") as f: theme = os.path.splitext(os.path.abspath(_args.theme_path))[0]
theme = f.read() darktheme_path = f"{theme}-dark.css"
split = theme.split(".foldericon {") if os.path.exists(darktheme_path):
split2 = split[1].split("}", maxsplit=1) handle_theme_icon(darktheme_path, os.path.join(static_dir, "theme-dark.css"))
themehead = split[0] darktheme = True
themetail = split2[1] handle_theme_icon(_args.theme_path, os.path.join(static_dir, "theme.css"))
foldericon = split2[0].strip()
foldericon = re.sub(r"/\*.*\*/", "", foldericon)
for match in re.finditer(r"content: (.*);", foldericon):
foldericon = match[1]
foldericon = foldericon.replace('"', "")
logger.info("found foldericon", extra={"foldericon": foldericon})
break
if "url" in foldericon:
logger.info("foldericon in theme file, using it")
shutil.copyfile(_args.theme_path, os.path.join(static_dir, "theme.css"))
return
with open(os.path.join(SCRIPTDIR, foldericon), "r", encoding="utf-8") as f:
logger.info("Reading foldericon svg")
svg = f.read()
if "svg.j2" in foldericon:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(_args.theme_path)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
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") 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(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: with open(os.path.join(static_dir, "functionality.min.js"), "w+", encoding="utf-8") as min_file:
min_file.write(jsmin(js_file.read())) min_file.write(jsmin(js_file.read()))
return darktheme
def generate_thumbnail(arguments: tuple[str, str, str]) -> None: def generate_thumbnail(arguments: tuple[str, str, str]) -> None:
""" """
@@ -155,7 +172,7 @@ def generate_thumbnail(arguments: tuple[str, str, str]) -> None:
imgrgb = imgfile.convert("RGB") imgrgb = imgfile.convert("RGB")
img = ImageOps.exif_transpose(imgrgb) img = ImageOps.exif_transpose(imgrgb)
img.thumbnail((512, 512)) img.thumbnail((512, 512))
img.save(path, "JPEG", quality=75, optimize=True, mode="RGB") img.save(path, "JPEG", quality=50, optimize=True, mode="RGB", subsampling=2)
except OSError: except OSError:
logger.error("Failed to generate thumbnail for %s", item, extra={"path": image}) logger.error("Failed to generate thumbnail for %s", item, extra={"path": image})
print(f"Failed to generate thumbnail for {image}") print(f"Failed to generate thumbnail for {image}")
@@ -168,12 +185,13 @@ def main(args) -> None:
""" """
Main function to process images and generate a static image hosting website. Main function to process images and generate a static image hosting website.
""" """
thumbnails: list[tuple[str, str, str, bool]] = [] thumbnails: list[tuple[str, str, str]] = []
args, raw = init_globals(args, RAW_EXTENSIONS) args, raw = init_globals(args, RAW_EXTENSIONS)
thumbdir = os.path.join(args.root_directory, ".thumbnails")
try: try:
Path(lock_file).touch() Path(LOCKFILE).touch()
logger.info("starting builder", extra={"version": VERSION, "arguments": args}) logger.info("starting builder", extra={"version": VERSION, "arguments": args})
logger.info("getting logo from sorogon.eu") logger.info("getting logo from sorogon.eu")
@@ -195,12 +213,12 @@ def main(args) -> None:
logger.warning("reread metadata flag is set to true, all image metadata will be reread") logger.warning("reread metadata flag is set to true, all image metadata will be reread")
if args.regenerate_thumbnails: if args.regenerate_thumbnails:
logger.warning("regenerate thumbnails flag is set to true, all thumbnails will be regenerated") logger.warning("regenerate thumbnails flag is set to true, all thumbnails will be regenerated")
if os.path.exists(os.path.join(args.root_directory, ".thumbnails")): if os.path.exists(thumbdir):
logger.info("removing old thumbnails folder") logger.info("removing old thumbnails folder")
shutil.rmtree(os.path.join(args.root_directory, ".thumbnails")) shutil.rmtree(thumbdir)
os.makedirs(os.path.join(args.root_directory, ".thumbnails"), exist_ok=True) os.makedirs(thumbdir, exist_ok=True)
copy_static_files(args) args.darktheme = copy_static_files(args)
icons(args) icons(args)
if args.generate_webmanifest: if args.generate_webmanifest:
@@ -229,8 +247,11 @@ def main(args) -> None:
dynamic_ncols=True, dynamic_ncols=True,
): ):
pass pass
except Exception as e:
logger.critical("an unhandled exception occurred: %s", str(e), exc_info=True)
print(f"An unhandled exception occurred: {str(e)}")
finally: finally:
os.remove(lock_file) os.remove(LOCKFILE)
logger.info("finished builder", extra={"version": VERSION}) logger.info("finished builder", extra={"version": VERSION})

3
example.config Normal file
View File

@@ -0,0 +1,3 @@
root-directory = /path/to/webroot
site-title = Website Title
web-root-url = https://www.example.com

View File

@@ -66,12 +66,15 @@ body {
padding: 0 2px; padding: 0 2px;
} }
figure { .centerload {
margin: 0; margin-top: 100px;
display: flex;
justify-content: center;
align-items: center;
} }
.licensefile { figure {
padding: 30px; margin: 0;
} }
.caption { .caption {
@@ -86,7 +89,6 @@ figure {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
right: 0; right: 0;
font-size: xx-small;
padding: 6px; padding: 6px;
} }
@@ -95,7 +97,8 @@ figure {
bottom: 0; bottom: 0;
width: 100%; width: 100%;
padding: 6px; padding: 6px;
min-height: calc(6.75pt + 12px); height: calc(9.75pt + 12px);
font-size: small;
} }
.footer a { .footer a {
@@ -103,7 +106,7 @@ figure {
} }
.footer a img { .footer a img {
height: 22px !important; height: 9.75pt !important;
margin-left: 3px; margin-left: 3px;
vertical-align: text-bottom; vertical-align: text-bottom;
} }
@@ -133,16 +136,19 @@ figure {
.navbar .navleft { .navbar .navleft {
float: left; float: left;
height: 100%;
} }
.navbar .navcenter { .navbar .navcenter {
position: absolute; position: absolute;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
height: 100%;
} }
.navbar .navright { .navbar .navright {
float: right float: right;
height: 100%;
} }
.navbar li .header { .navbar li .header {
@@ -296,6 +302,59 @@ input {
border-style: none; border-style: none;
} }
.darkmodeswitch {
font-size: smaller;
height: 100%;
}
#dark-mode-switch {
display: flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
position: relative;
}
#dark-mode-switch .checkbox {
position: absolute;
width: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
z-index: 2;
}
#dark-mode-switch .knobs {
display: flex;
align-items: center;
justify-content: center;
column-gap: 1em;
position: relative;
width: 100%;
}
#dark-mode-switch .light,
#dark-mode-switch .dark {
text-align: center;
}
#dark-mode-switch .slider {
position: absolute;
width: calc(2em - 2px);
height: calc(2em - 2px);
border: 1px solid currentColor;
border-radius: 3px;
top: 50%;
transform: translate(-50%, -50%);
transition: left 0.25s ease, transform 0.25s ease;
left: calc(50% - 1em + 1px);
}
#dark-mode-switch .checkbox:checked+.knobs .slider {
left: calc(50% + 1em - 1px);
}
@media screen and (max-width: 1000px) { @media screen and (max-width: 1000px) {
.column { .column {
-ms-flex: 25%; -ms-flex: 25%;
@@ -303,6 +362,14 @@ input {
max-width: 25%; max-width: 25%;
} }
.footer {
font-size: small;
}
.footer a img {
height: 9.75pt !important;
}
.folders figure { .folders figure {
width: 160px; width: 160px;
} }
@@ -336,6 +403,14 @@ input {
max-width: 50%; max-width: 50%;
} }
.footer {
font-size: x-small;
}
.footer a img {
height: 7.5pt !important;
}
.folders figure { .folders figure {
width: 140px; width: 140px;
} }
@@ -377,6 +452,14 @@ input {
max-width: 100%; max-width: 100%;
} }
.footer {
font-size: xx-small;
}
.footer a img {
height: 6.75pt !important;
}
.folders figure { .folders figure {
width: 120px; width: 120px;
} }

View File

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

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

View File

@@ -1,268 +0,0 @@
import os
import re
import sys
import shutil
import base64
import fileinput
import urllib.parse
import urllib.request
from typing import List
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from modules.logger import consolelogger as logger
from modules.css_color import extract_colorscheme
def replace_all(file, search_exp, replace_exp):
for line in fileinput.input(file, inplace=1):
line = re.sub(search_exp, replace_exp, line)
sys.stdout.write(line)
def take_screenshot(html_file_path: str, css_file: str, output_file: str, driver: webdriver.Chrome) -> None:
"""
Takes a screenshot of the given HTML file with the specified CSS applied.
Args:
html_file_path (str): Path to the HTML file or URL.
css_file (str): Path to the CSS file to be applied.
output_file (str): Path where the screenshot will be saved.
driver (webdriver.Chrome): The Chrome WebDriver instance.
"""
logger.info("taking screenshot for %s", css_file)
try:
# Open the HTML file or URL
if html_file_path.startswith(("http://", "https://")):
logger.info("opening URL: %s", html_file_path)
driver.get(html_file_path)
else:
logger.info("opening file: %s", html_file_path)
driver.get(f"file://{os.path.abspath(html_file_path)}")
# Remove current theme.css
remove_css_script = """
var links = document.querySelectorAll("link[rel='stylesheet']");
links.forEach(link => {
if (link.href.includes('theme.css')) {
link.parentNode.removeChild(link);
}
});
"""
logger.info("removing current theme.css")
driver.execute_script(remove_css_script)
with open(css_file, "r", encoding="utf-8") as f:
logger.info("reading CSS file: %s", css_file)
css_content = f.read()
# Extract folder icon content
css_parts = css_content.split(".foldericon {")
css_head = css_parts[0]
css_tail = css_parts[1].split("}", maxsplit=1)[1]
folder_icon_content = css_parts[1].split("}", maxsplit=1)[0].strip()
folder_icon_content = re.sub(r"/\*.*\*/", "", folder_icon_content)
for match in re.finditer(r"content: (.*);", folder_icon_content):
logger.info("found foldericon", extra={"foldericon": folder_icon_content})
folder_icon_content = match.group(1).replace('"', "")
break
if "url" not in folder_icon_content:
logger.info("Reading foldericon svg")
with open(folder_icon_content, "r", encoding="utf-8") as f:
svg = f.read()
if "svg.j2" in folder_icon_content:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(css_file)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
css_content = f'{css_head}\n.foldericon {{\n content: url("data:image/svg+xml,{svg}");\n}}\n{css_tail}'
# Encode CSS content as Base64
logger.info("encoding css content as base64")
encoded_css = base64.b64encode(css_content.encode("utf-8")).decode("utf-8")
# Inject CSS into HTML using JavaScript
apply_css_script = f"""
var style = document.createElement('style');
style.innerHTML = atob('{encoded_css}');
document.head.appendChild(style);
"""
logger.info("injecting CSS into HTML")
driver.execute_script(apply_css_script)
# Wait for a while to ensure CSS is applied
# time.sleep(1)
# Move mouse to info
logger.info("moving mouse to info")
hoverable = driver.find_element(By.CLASS_NAME, "tooltip")
webdriver.ActionChains(driver).move_to_element(hoverable).perform()
# Capture screenshot
logger.info("taking screenshot")
driver.save_screenshot(output_file)
logger.info("screenshot saved to %s", output_file)
except Exception as e:
logger.error("failed to take screenshot for %s: %s", css_file, e)
def create_preview(html_file_path: str, css_file: str, previews_folder: str):
logger.info("creating preview for %s", css_file)
out_file = os.path.basename(css_file).removesuffix(".css") + ".html"
urllib.request.urlretrieve(html_file_path, os.path.join(previews_folder, out_file))
basename = os.path.basename(css_file)
path = css_file.removesuffix(basename)
replace_all(
os.path.join(previews_folder, out_file),
r'^\s*?<link rel="stylesheet" href=".*theme.css">\s*?$',
f' <link rel="stylesheet" href="file://{path}previews/{basename}">',
)
with open(css_file, "r", encoding="utf-8") as f:
theme = f.read()
split = theme.split(".foldericon {")
split2 = split[1].split("}", maxsplit=1)
themehead = split[0]
themetail = split2[1]
foldericon = split2[0].strip()
foldericon = re.sub(r"/\*.*\*/", "", foldericon)
for match in re.finditer(r"content: (.*);", foldericon):
foldericon = match[1]
foldericon = foldericon.replace('"', "")
break
if "url" in foldericon:
logger.info("foldericon in theme file, using it")
shutil.copyfile(css_file, os.path.join(path, "previews", basename))
return
with open(os.path.join(path, foldericon.removeprefix("themes/")), "r", encoding="utf-8") as f:
logger.info("Reading foldericon svg")
svg = f.read()
if "svg.j2" in foldericon:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(css_file)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
if os.path.exists(os.path.join(path, "previews", basename)):
os.remove(os.path.join(path, "previews", basename))
with open(os.path.join(path, "previews", basename), "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("preview created for %s", css_file)
def write_readme(directory_path: str, themes: List[str]) -> None:
"""
Writes the README file with previews of included themes.
Args:
directory_path (str): Path to the folder containing the themes and README.md.
themes (List[str]): List of theme names.
"""
readme_path = os.path.join(directory_path, "README.md")
try:
with open(readme_path, "r", encoding="utf-8") as f:
logger.info("reading README.md", extra={"file": readme_path})
readme = f.read()
readme_head = readme.split("## Previews of included themes")[0]
readme_head += "## Previews of included themes\n"
readme_head += "".join([f"\n### {theme}\n\n![{theme}](screenshots/{theme}.png)\n" for theme in themes])
with open(readme_path, "w", encoding="utf-8") as f:
logger.info("writing README.md", extra={"file": readme_path})
f.write(readme_head)
logger.info("README.md updated with previews of included themes.")
except FileNotFoundError:
logger.error("README.md not found in %s", directory_path)
except Exception as e:
logger.error("failed to write README.md: %s", e)
def write_index(directory_path: str, themes: List[str]) -> None:
with open(os.path.join(directory_path, "index.html"), "w", encoding="utf-8") as f:
f.write(
"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Themes</title>
</head>
<body>"""
)
for theme in themes:
f.write(f'<a href="previews/{theme}.html">{theme}</a><br>\n')
f.write("</body></html>")
def main(directory_path: str, html_file_path: str) -> None:
"""
Main function to take screenshots for each CSS file in the folder and update the README.md.
Args:
directory_path (str): Path to the folder containing CSS files.
html_file_path (str): Path to the HTML file or URL for rendering.
"""
if not os.path.exists(directory_path):
logger.error('Error: Folder path "%s" does not exist.', directory_path)
return
# Setup Chrome options
chrome_options = Options()
chrome_options.add_argument("--headless") # Run in headless mode, no GUI
chrome_options.add_argument("--window-size=1920,1080") # Set window size to at least 1920x1080
# Initialize Chrome WebDriver
chromedriver_path = "/usr/bin/chromedriver"
service = Service(chromedriver_path)
logger.info("Using chromedriver at %s", chromedriver_path, extra={"chrome_options": chrome_options})
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
themes = []
# Iterate over all files in the folder
for filename in sorted(os.listdir(directory_path)):
if filename.endswith(".css"):
theme_name = os.path.splitext(filename)[0]
themes.append(theme_name)
css_file = os.path.join(directory_path, filename)
output_file = os.path.join(directory_path, "screenshots", f"{theme_name}.png")
previews_folder = os.path.join(directory_path, "previews")
# Create screenshots folder if it doesn't exist
os.makedirs(os.path.dirname(output_file), exist_ok=True)
os.makedirs(previews_folder, exist_ok=True)
# Take screenshot for this CSS file
take_screenshot(html_file_path, css_file, output_file, driver)
create_preview(html_file_path, css_file, previews_folder)
# Write the README file with the new previews
write_readme(directory_path, themes)
write_index(directory_path, themes)
finally:
logger.info("closing chrome webdriver")
driver.quit()
if __name__ == "__main__":
if len(sys.argv) != 3:
logger.error("Usage: python script_name.py directory_path html_file_path")
else:
dir_path = sys.argv[1]
html_path = sys.argv[2]
logger.info("Starting script", extra={"directory_path": dir_path, "html_file_path": html_path})
main(dir_path, html_path)
logger.info("Done!", extra={"directory_path": dir_path})

192
help.svg
View File

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

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,7 +1,8 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional from typing import Optional
import os import os
import argparse
import configargparse
try: try:
from rich_argparse import RichHelpFormatter, HelpPreviewAction from rich_argparse import RichHelpFormatter, HelpPreviewAction
@@ -11,14 +12,18 @@ except ModuleNotFoundError:
RICH = False RICH = False
if __package__ is None: SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)).removesuffix(__package__)
PACKAGE = ""
else:
PACKAGE = __package__
SCRIPTDIR = os.path.abspath(os.path.dirname(__file__).removesuffix(PACKAGE))
DEFAULT_THEME_PATH = os.path.join(SCRIPTDIR, "templates", "default.css") DEFAULT_THEME_PATH = os.path.join(SCRIPTDIR, "templates", "default.css")
DEFAULT_AUTHOR = "Author" DEFAULT_AUTHOR = "Author"
if "APPDATA" in os.environ:
CONFIGHOME = os.environ["APPDATA"]
elif "XDG_CONFIG_HOME" in os.environ:
CONFIGHOME = os.environ["XDG_CONFIG_HOME"]
else:
CONFIGHOME = os.path.join(os.environ["HOME"], ".config")
CONFIGPATH = os.path.join(CONFIGHOME, "StaticGalleryBuilder")
@dataclass(init=True) @dataclass(init=True)
class Args: class Args:
@@ -55,6 +60,8 @@ class Args:
Whether to enable fancy folder view. Whether to enable fancy folder view.
web_root_url : str web_root_url : str
The base URL of the web root for the image hosting site. The base URL of the web root for the image hosting site.
darktheme : bool
Whether a dark theme is present.
""" """
author_name: str author_name: str
@@ -62,6 +69,7 @@ class Args:
file_extensions: list[str] file_extensions: list[str]
folder_thumbs: bool folder_thumbs: bool
generate_webmanifest: bool generate_webmanifest: bool
ignore_extensions: list[str]
ignore_other_files: bool ignore_other_files: bool
license_type: Optional[str] license_type: Optional[str]
non_interactive_mode: bool non_interactive_mode: bool
@@ -74,6 +82,7 @@ class Args:
theme_path: str theme_path: str
use_fancy_folders: bool use_fancy_folders: bool
web_root_url: str web_root_url: str
darktheme: bool = False
def to_dict(self) -> dict: def to_dict(self) -> dict:
result: dict = {} result: dict = {}
@@ -82,6 +91,7 @@ class Args:
result["file_extensions"] = self.file_extensions result["file_extensions"] = self.file_extensions
result["folder_thumbs"] = self.folder_thumbs result["folder_thumbs"] = self.folder_thumbs
result["generate_webmanifest"] = self.generate_webmanifest result["generate_webmanifest"] = self.generate_webmanifest
result["ignore_extensions"] = self.ignore_extensions
result["ignore_other_files"] = self.ignore_other_files result["ignore_other_files"] = self.ignore_other_files
if self.license_type is not None: if self.license_type is not None:
result["license_type"] = self.license_type result["license_type"] = self.license_type
@@ -95,6 +105,7 @@ class Args:
result["theme_path"] = self.theme_path result["theme_path"] = self.theme_path
result["use_fancy_folders"] = self.use_fancy_folders result["use_fancy_folders"] = self.use_fancy_folders
result["web_root_url"] = self.web_root_url result["web_root_url"] = self.web_root_url
result["darktheme"] = self.darktheme
return result return result
@@ -114,9 +125,9 @@ def parse_arguments(version: str) -> Args:
""" """
# fmt: off # fmt: off
if RICH: if RICH:
parser = argparse.ArgumentParser(description="generate HTML files for a static image hosting website", formatter_class=RichHelpFormatter) parser = configargparse.ArgumentParser(default_config_files=[CONFIGPATH], add_config_file_help=False, description="generate HTML files for a static image hosting website", formatter_class=RichHelpFormatter)
else: else:
parser = argparse.ArgumentParser(description="generate HTML files for a static image hosting website") parser = configargparse.ArgumentParser(default_config_files=[CONFIGPATH], add_config_file_help=False, 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("-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("-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("-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")
@@ -125,11 +136,13 @@ def parse_arguments(version: str) -> Args:
parser.add_argument("-p", "--root-directory", help="root directory containing the images", required=True, type=str, dest="root_directory", metavar="ROOT") 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("-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("-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('-c', '--config-file', is_config_file=True, help='config file path', metavar="CONFIG_FILE")
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("--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.add_argument("--folderthumbnails", help="generate subfolder thumbnails (first image in folder will be shown)", action="store_true", default=False, dest="folder_thumbs")
if RICH: if RICH:
parser.add_argument("--generate-help-preview", action=HelpPreviewAction, path="help.svg", ) 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("--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("--ignore-extension", help="file extensions to ignore (can be specified multiple times)", action="append", default=[], dest="ignore_extensions", metavar="EXTENSION")
parser.add_argument("--regenerate-thumbnails", help="regenerate thumbnails even if they already exist", action="store_true", default=False, dest="regenerate_thumbnails") 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-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("--reread-sidecar", help="reread sidecar files", action="store_true", default=False, dest="reread_sidecar")
@@ -137,7 +150,12 @@ def parse_arguments(version: str) -> Args:
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("--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("--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}") parser.add_argument("--version", action="version", version=f"%(prog)s {version}")
parser.add_argument("--write-config", type=str, required=False, help="write current command line args to config file", metavar="CONFIG_FILE")
parsed_args = parser.parse_args() parsed_args = parser.parse_args()
if parsed_args.write_config:
config_path = parsed_args.write_config
del parsed_args.write_config
parser.write_config_file(parsed_args, [config_path], exit_after=False)
# fmt: on # fmt: on
_args = Args( _args = Args(
author_name=parsed_args.author_name, author_name=parsed_args.author_name,
@@ -146,6 +164,7 @@ def parse_arguments(version: str) -> Args:
folder_thumbs=parsed_args.folder_thumbs, folder_thumbs=parsed_args.folder_thumbs,
generate_webmanifest=parsed_args.generate_webmanifest, generate_webmanifest=parsed_args.generate_webmanifest,
ignore_other_files=parsed_args.ignore_other_files, ignore_other_files=parsed_args.ignore_other_files,
ignore_extensions=parsed_args.ignore_extensions,
license_type=parsed_args.license_type, license_type=parsed_args.license_type,
non_interactive_mode=parsed_args.non_interactive_mode, non_interactive_mode=parsed_args.non_interactive_mode,
regenerate_thumbnails=parsed_args.regenerate_thumbnails, regenerate_thumbnails=parsed_args.regenerate_thumbnails,
@@ -157,5 +176,6 @@ def parse_arguments(version: str) -> Args:
theme_path=parsed_args.theme_path, theme_path=parsed_args.theme_path,
use_fancy_folders=parsed_args.use_fancy_folders, use_fancy_folders=parsed_args.use_fancy_folders,
web_root_url=parsed_args.web_root_url, web_root_url=parsed_args.web_root_url,
darktheme=False,
) )
return _args return _args

View File

@@ -19,7 +19,7 @@ def extract_colorscheme(theme_path: str) -> dict[str, str]:
dictionary containing color scheme variables and their hexadecimal values. dictionary containing color scheme variables and their hexadecimal values.
""" """
logger.info("extracting color scheme from theme file", extra={"theme_path": theme_path}) logger.info("extracting color scheme from theme file", extra={"theme_path": theme_path})
pattern = r"--(color[1-4]|bcolor1):\s*(#[0-9a-fA-F]+|rgba?\([^)]*\)|hsla?\([^)]*\)|[a-zA-Z]+);" pattern = r"--(color\d+|bcolor\d+):\s*(#[0-9a-fA-F]+|rgba?\([^)]*\)|hsla?\([^)]*\)|[a-zA-Z]+);"
colorscheme = {} colorscheme = {}
with open(theme_path, "r", encoding="utf-8") as f: with open(theme_path, "r", encoding="utf-8") as f:
@@ -95,7 +95,8 @@ def css_color_to_hex(css_color: str) -> str:
# Helper function to convert HSL tuple to RGB tuple # Helper function to convert HSL tuple to RGB tuple
def hsl_to_rgb(hsl: tuple[int, float, float]) -> tuple[int, int, int]: def hsl_to_rgb(hsl: tuple[int, float, float]) -> tuple[int, int, int]:
logger.debug("converting hsl tuple to rgb tuple", extra={"hsl": hsl}) logger.debug("converting hsl tuple to rgb tuple", extra={"hsl": hsl})
return tuple(round(c * 255) for c in colorsys.hls_to_rgb(hsl[0] / 360, hsl[1] / 100, hsl[2] / 100)) r, g, b = colorsys.hls_to_rgb(hsl[0] / 360, hsl[1] / 100, hsl[2] / 100)
return (round(r * 255), round(g * 255), round(b * 255))
# Regular expression pattern to match CSS colors # Regular expression pattern to match CSS colors
color_pattern = re.compile( color_pattern = re.compile(

View File

@@ -0,0 +1,158 @@
from dataclasses import dataclass
from typing import List, Optional, Any, Dict, TypeVar, Callable, Type, cast
T = TypeVar("T")
def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
assert isinstance(x, list)
return [f(y) for y in x]
def from_none(x: Any) -> Any:
assert x is None
return x
def from_union(fs, x):
for f in fs:
try:
return f(x)
except AssertionError:
pass
assert False
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
assert isinstance(x, dict)
return {k: f(v) for (k, v) in x.items()}
def from_native_dict(f: Callable[[Any], T], x: Any) -> Dict[Any, T]:
assert isinstance(x, dict)
return x
@dataclass
class ImageMetadata:
w: Optional[int]
h: Optional[int]
tags: Optional[List[str]]
exifdata: Optional[Dict[str, Any]]
xmp: Optional[Dict[str, Any]]
src: str
msrc: str
name: str
title: str
tiff: Optional[str] = None
raw: Optional[str] = None
@staticmethod
def from_dict(obj: Any) -> "ImageMetadata":
assert isinstance(obj, dict)
w = from_union([from_int, from_none], obj.get("w"))
h = from_union([from_int, from_none], obj.get("h"))
tags = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tags"))
exifdata = from_union([lambda x: from_native_dict(dict, x), from_none], obj.get("exifdata"))
xmp = from_union([lambda x: from_native_dict(dict, x), from_none], obj.get("xmp"))
src = from_str(obj.get("src"))
msrc = from_str(obj.get("msrc"))
name = from_str(obj.get("name"))
title = from_str(obj.get("title"))
tiff = from_union([from_str, from_none], obj.get("tiff"))
raw = from_union([from_str, from_none], obj.get("raw"))
return ImageMetadata(w, h, tags, exifdata, xmp, src, msrc, name, title, tiff, raw)
def to_dict(self) -> dict:
result: dict = {}
if self.w is not None:
result["w"] = from_union([from_int, from_none], self.w)
if self.h is not None:
result["h"] = from_union([from_int, from_none], self.h)
if self.tags is not None:
result["tags"] = from_union([lambda x: from_list(from_str, x), from_none], self.tags)
result["src"] = from_str(self.src)
result["msrc"] = from_str(self.msrc)
result["name"] = from_str(self.name)
result["title"] = from_str(self.title)
if self.tiff is not None:
result["tiff"] = from_union([from_str, from_none], self.tiff)
if self.raw is not None:
result["raw"] = from_union([from_str, from_none], self.raw)
if self.exifdata is not None:
result["exifdata"] = from_union([lambda x: from_native_dict(dict, x), from_none], self.exifdata)
if self.xmp is not None:
result["xmp"] = from_union([lambda x: from_native_dict(dict, x), from_none], self.xmp)
return result
@dataclass
class SubfolderMetadata:
url: str
name: str
metadata: Optional[str] = None
thumb: Optional[str] = None
@staticmethod
def from_dict(obj: Any) -> "SubfolderMetadata":
assert isinstance(obj, dict)
url = from_str(obj.get("url"))
name = from_str(obj.get("name"))
metadata = from_union([from_none, from_str], obj.get("metadata"))
thumb = from_union([from_none, from_str], obj.get("thumb"))
return SubfolderMetadata(url, name, metadata, thumb)
def to_dict(self) -> dict:
result: dict = {}
result["url"] = from_str(self.url)
result["name"] = from_str(self.name)
result["metadata"] = from_union([from_none, from_str], self.metadata)
result["thumb"] = from_union([from_none, from_str], self.thumb)
return result
@dataclass
class Metadata:
images: Dict[str, ImageMetadata]
subfolders: Optional[List[SubfolderMetadata]] = None
@staticmethod
def from_dict(obj: Any) -> "Metadata":
assert isinstance(obj, dict)
images = from_dict(ImageMetadata.from_dict, obj.get("images"))
subfolders = from_union([lambda x: from_list(SubfolderMetadata.from_dict, x), from_none], obj.get("subfolders"))
return Metadata(images, subfolders)
def to_dict(self) -> dict:
result: dict = {}
result["images"] = from_dict(lambda x: to_class(ImageMetadata, x), self.images)
if self.subfolders is not None:
result["subfolders"] = from_union([lambda x: from_list(lambda x: to_class(SubfolderMetadata, x), x), from_none], self.subfolders)
return result
def sort(self, reverse=False) -> "Metadata":
self.images = {key: self.images[key] for key in sorted(self.images, reverse=reverse)}
return self
def top_level_from_dict(s: Any) -> Metadata:
return Metadata.from_dict(s)
def top_level_to_dict(x: Metadata) -> Any:
return to_class(Metadata, x)

View File

@@ -17,13 +17,10 @@ from bs4 import BeautifulSoup
from modules.logger import logger from modules.logger import logger
from modules import cclicense from modules import cclicense
from modules.argumentparser import Args from modules.argumentparser import Args
from modules.datatypes.metadata import Metadata, ImageMetadata, SubfolderMetadata
# Constants for file paths and exclusions # Constants for file paths and exclusions
if __package__ is None: SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)).removesuffix(__package__)
PACKAGE = ""
else:
PACKAGE = __package__
SCRIPTDIR = os.path.abspath(os.path.dirname(__file__).removesuffix(PACKAGE))
FAVICON_PATH = ".static/favicon.ico" FAVICON_PATH = ".static/favicon.ico"
GLOBAL_CSS_PATH = ".static/global.css" GLOBAL_CSS_PATH = ".static/global.css"
EXCLUDES = ["index.html", "manifest.json", "robots.txt"] EXCLUDES = ["index.html", "manifest.json", "robots.txt"]
@@ -73,7 +70,7 @@ def getxmp(strbuffer: str) -> dict[str, Any]:
return {get_name(root.tag): get_value(root)} return {get_name(root.tag): get_value(root)}
def initialize_metadata(folder: str) -> dict[str, dict[str, int]]: def initialize_metadata(folder: str) -> Metadata:
""" """
Initializes the metadata JSON file if it doesn't exist. Initializes the metadata JSON file if it doesn't exist.
@@ -125,11 +122,13 @@ def initialize_metadata(folder: str) -> dict[str, dict[str, int]]:
metadata["images"][k]["exifdata"] = None metadata["images"][k]["exifdata"] = None
if "xmp" not in v: if "xmp" not in v:
metadata["images"][k]["xmp"] = None metadata["images"][k]["xmp"] = None
if "title" not in v:
metadata["images"][k]["title"] = v["name"]
return metadata return Metadata.from_dict(metadata)
def update_metadata(metadata: dict[str, dict[str, Any]], folder: str) -> None: def update_metadata(metadata: Metadata, folder: str) -> None:
""" """
Updates the metadata JSON file. Updates the metadata JSON file.
@@ -141,14 +140,14 @@ def update_metadata(metadata: dict[str, dict[str, Any]], folder: str) -> None:
if metadata: if metadata:
with open(metadata_path, "w", encoding="utf-8") as metadatafile: with open(metadata_path, "w", encoding="utf-8") as metadatafile:
logger.info("writing metadata file", extra={"file": metadata_path}) logger.info("writing metadata file", extra={"file": metadata_path})
metadatafile.write(json.dumps(metadata, indent=4)) metadatafile.write(json.dumps(metadata.to_dict(), indent=4))
else: else:
if os.path.exists(metadata_path): if os.path.exists(metadata_path):
logger.info("deleting empty metadata file", extra={"file": metadata_path}) logger.info("deleting empty metadata file", extra={"file": metadata_path})
os.remove(metadata_path) os.remove(metadata_path)
def get_image_info(item: str, folder: str) -> dict[str, Any]: def get_image_info(item: str, folder: str) -> ImageMetadata:
""" """
Extracts image information and EXIF data. Extracts image information and EXIF data.
@@ -170,7 +169,7 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
except UnidentifiedImageError: except UnidentifiedImageError:
logger.error("cannot identify image file", extra={"file": file}) logger.error("cannot identify image file", extra={"file": file})
print(f"cannot identify image file: {file}") print(f"cannot identify image file: {file}")
return {"w": None, "h": None, "tags": None, "exifdata": None, "xmp": None} return ImageMetadata(w=None, h=None, tags=[], exifdata=None, xmp=None, src="", msrc="", name="", title="")
if exif: if exif:
logger.info("extracting EXIF data", extra={"file": file}) logger.info("extracting EXIF data", extra={"file": file})
ifd = exif.get_ifd(ExifTags.IFD.Exif) ifd = exif.get_ifd(ExifTags.IFD.Exif)
@@ -251,9 +250,11 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
tags = get_tags(sidecarfile) tags = get_tags(sidecarfile)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
if None in tags: if None in tags: # type: ignore
tags.remove(None) tags.remove(None) # type: ignore
return {"w": width, "h": height, "tags": tags, "exifdata": exifdata, "xmp": xmp} if not isinstance(tags, list):
tags = []
return ImageMetadata(w=width, h=height, tags=tags, exifdata=exifdata, xmp=xmp, src="", msrc="", name="", title="")
def nested_dict(): def nested_dict():
@@ -329,12 +330,12 @@ def get_tags(sidecarfile: str) -> list[str]:
pass pass
except KeyError: except KeyError:
pass pass
if None in tags: if None in tags: # type: ignore
tags.remove(None) tags.remove(None) # type: ignore
return tags return tags # type: ignore
def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: dict[str, dict[str, int]], raw: list[str]) -> dict[str, Any]: def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: Metadata, raw: list[str]) -> tuple[ImageMetadata, Metadata]:
""" """
Processes an image and prepares its data for the HTML template. Processes an image and prepares its data for the HTML template.
@@ -351,23 +352,21 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
""" """
extsplit = os.path.splitext(item) extsplit = os.path.splitext(item)
sidecarfile = os.path.join(folder, item + ".xmp") sidecarfile = os.path.join(folder, item + ".xmp")
if item not in metadata["images"] or _args.reread_metadata: if item not in metadata.images or _args.reread_metadata:
metadata["images"][item] = get_image_info(item, folder) metadata.images[item] = get_image_info(item, folder)
if _args.reread_sidecar and os.path.exists(sidecarfile): if _args.reread_sidecar and os.path.exists(sidecarfile):
logger.info("xmp sidecar file found", extra={"file": sidecarfile}) logger.info("xmp sidecar file found", extra={"file": sidecarfile})
try: try:
metadata["images"][item]["tags"] = get_tags(sidecarfile) metadata.images[item].tags = get_tags(sidecarfile)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
image = { image = metadata.images[item]
"src": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}", image.src = f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}"
"msrc": f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg", image.msrc = f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg"
"name": item, image.name = item
"w": metadata["images"][item]["w"], image.title = item
"h": metadata["images"][item]["h"],
"tags": metadata["images"][item]["tags"],
}
path = os.path.join(_args.root_directory, ".thumbnails", baseurl, item + ".jpg") path = os.path.join(_args.root_directory, ".thumbnails", baseurl, item + ".jpg")
if not os.path.exists(path) or _args.regenerate_thumbnails: if not os.path.exists(path) or _args.regenerate_thumbnails:
if os.path.exists(path): if os.path.exists(path):
@@ -380,17 +379,17 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
url = f"{_args.web_root_url}{baseurl}{urllib.parse.quote(extsplit[0])}{_raw}" url = f"{_args.web_root_url}{baseurl}{urllib.parse.quote(extsplit[0])}{_raw}"
if _raw in (".tif", ".tiff"): if _raw in (".tif", ".tiff"):
logger.info("tiff file found", extra={"file": file}) logger.info("tiff file found", extra={"file": file})
image["tiff"] = url image.tiff = url
else: else:
logger.info("raw file found", extra={"file": file, "extension": _raw}) logger.info("raw file found", extra={"file": file, "extension": _raw})
image["raw"] = url image.raw = url
metadata["images"][item].update(image) metadata.images[item] = image
return image, metadata return image, metadata
def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[str]: def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> set[str]:
""" """
Generates HTML content for a folder of images. Generates HTML content for a folder of images.
@@ -409,23 +408,23 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
items = sorted(os.listdir(folder)) items = sorted(os.listdir(folder))
contains_files = False contains_files = False
images = [] images: list[ImageMetadata] = []
subfolders = [] subfolders: list[SubfolderMetadata] = []
subfoldertags = set() subfoldertags: set[str] = set()
foldername = folder.removeprefix(_args.root_directory) foldername = folder.removeprefix(_args.root_directory)
foldername = f"{foldername}/" if foldername else "" foldername = f"{foldername}/" if foldername else ""
baseurl = urllib.parse.quote(foldername) baseurl = urllib.parse.quote(foldername)
gone = [item for item in metadata["images"] if item not in items] gone = [item for item in metadata.images if item not in items]
for gon in gone: for gon in gone:
del metadata["images"][gon] del metadata.images[gon]
create_thumbnail_folder(foldername, _args.root_directory) create_thumbnail_folder(foldername, _args.root_directory)
logger.info("processing contents", extra={"folder": folder}) logger.info("processing contents", extra={"folder": folder})
if not _args.non_interactive_mode: if not _args.non_interactive_mode:
for item in tqdm(items, total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True): for item in tqdm(items, total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True, leave=False):
if item not in EXCLUDES and not item.startswith("."): if item not in EXCLUDES and not item.startswith(".") and os.path.splitext(item)[1][1:].lower() not in _args.ignore_extensions:
if os.path.isdir(os.path.join(folder, item)): if os.path.isdir(os.path.join(folder, item)):
subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)) subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo))
else: else:
@@ -439,7 +438,7 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
process_license(folder, item) process_license(folder, item)
else: else:
for item in items: for item in items:
if item not in EXCLUDES and not item.startswith("."): if item not in EXCLUDES and not item.startswith(".") and os.path.splitext(item)[1][1:].lower() not in _args.ignore_extensions:
if os.path.isdir(os.path.join(folder, item)): if os.path.isdir(os.path.join(folder, item)):
subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)) subfoldertags.update(process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo))
else: else:
@@ -452,11 +451,11 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
if item == "LICENSE": if item == "LICENSE":
process_license(folder, item) process_license(folder, item)
metadata["subfolders"] = subfolders metadata.subfolders = subfolders
if _args.reverse_sort: if _args.reverse_sort:
metadata["images"] = {key: metadata["images"][key] for key in sorted(metadata["images"], reverse=True)} metadata.sort(reverse=True)
else: else:
metadata["images"] = {key: metadata["images"][key] for key in sorted(metadata["images"])} metadata.sort()
update_metadata(metadata, folder) update_metadata(metadata, folder)
if should_generate_html(images, contains_files, _args): if should_generate_html(images, contains_files, _args):
@@ -482,7 +481,7 @@ def create_thumbnail_folder(foldername: str, root_directory: str) -> None:
os.mkdir(thumbnails_path) 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) -> list[str]: def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[SubfolderMetadata], _args: Args, raw: list[str], version: str, logo: str) -> set[str]:
""" """
Processes a subfolder. Processes a subfolder.
@@ -510,10 +509,10 @@ def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dic
if item not in _args.exclude_folders: if item not in _args.exclude_folders:
if not any(fnmatch.fnmatchcase(os.path.join(folder, item), exclude) for exclude in _args.exclude_folders): if not any(fnmatch.fnmatchcase(os.path.join(folder, item), exclude) for exclude in _args.exclude_folders):
subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb, "metadata": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}/.metadata.json"}) subfolders.append(SubfolderMetadata(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) 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}) subfolders.append(SubfolderMetadata(url=subfolder_url, name=item, thumb=thumb))
return [] return set()
def process_license(folder: str, item: str) -> None: def process_license(folder: str, item: str) -> None:
@@ -545,7 +544,7 @@ def process_info_file(folder: str, item: str) -> None:
info[urllib.parse.quote(folder)] = f.read() info[urllib.parse.quote(folder)] = f.read()
def should_generate_html(images: list[dict[str, Any]], contains_files, _args: Args) -> bool: def should_generate_html(images: list[ImageMetadata], contains_files, _args: Args) -> bool:
""" """
Determines if HTML should be generated. Determines if HTML should be generated.
@@ -556,7 +555,7 @@ def should_generate_html(images: list[dict[str, Any]], contains_files, _args: Ar
Returns: Returns:
bool: True if HTML should be generated, False otherwise. bool: True if HTML should be generated, False otherwise.
""" """
return images or (_args.use_fancy_folders and not contains_files) or (_args.use_fancy_folders and _args.ignore_other_files) return bool(images) or (_args.use_fancy_folders and not contains_files) or (_args.use_fancy_folders and _args.ignore_other_files)
def format_html(html: str) -> str: def format_html(html: str) -> str:
@@ -565,8 +564,8 @@ def format_html(html: str) -> str:
def create_html_file( 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] folder: str, title: str, foldername: str, images: list[ImageMetadata], subfolders: list[SubfolderMetadata], _args: Args, version: str, logo: str, subfoldertags: set[str]
) -> list[str]: ) -> set[str]:
""" """
Creates the HTML file using the template. Creates the HTML file using the template.
@@ -599,15 +598,13 @@ def create_html_file(
alltags = set() alltags = set()
for img in images: for img in images:
if img["tags"]: if img.tags:
alltags.update(img["tags"]) alltags.update(img.tags)
alltags.update(set(subfoldertags)) alltags.update(subfoldertags)
folder_info = info.get(urllib.parse.quote(folder), "").split("\n") 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 _info = [i for i in folder_info if len(i) > 1] if folder_info else None
if _args.reverse_sort:
images.sort(key=lambda i: i["name"], reverse=True)
folder_license = licens.get(urllib.parse.quote(folder), False) folder_license = licens.get(urllib.parse.quote(folder), False)
@@ -624,6 +621,7 @@ def create_html_file(
favicon=f"{_args.web_root_url}{FAVICON_PATH}", favicon=f"{_args.web_root_url}{FAVICON_PATH}",
stylesheet=f"{_args.web_root_url}{GLOBAL_CSS_PATH}", stylesheet=f"{_args.web_root_url}{GLOBAL_CSS_PATH}",
theme=f"{_args.web_root_url}.static/theme.css", theme=f"{_args.web_root_url}.static/theme.css",
darktheme=f"{_args.web_root_url}.static/theme-dark.css" if _args.darktheme else None,
root=_args.web_root_url, root=_args.web_root_url,
parent=f"{_args.web_root_url}{urllib.parse.quote(foldername)}", parent=f"{_args.web_root_url}{urllib.parse.quote(foldername)}",
header=f"{header} - LICENSE", header=f"{header} - LICENSE",
@@ -641,6 +639,7 @@ def create_html_file(
favicon=f"{_args.web_root_url}{FAVICON_PATH}", favicon=f"{_args.web_root_url}{FAVICON_PATH}",
stylesheet=f"{_args.web_root_url}{GLOBAL_CSS_PATH}", stylesheet=f"{_args.web_root_url}{GLOBAL_CSS_PATH}",
theme=f"{_args.web_root_url}.static/theme.css", theme=f"{_args.web_root_url}.static/theme.css",
darktheme=f"{_args.web_root_url}.static/theme-dark.css" if _args.darktheme else None,
root=_args.web_root_url, root=_args.web_root_url,
parent=parent, parent=parent,
header=header, header=header,
@@ -658,7 +657,7 @@ def create_html_file(
logger.info("writing formatted html file", extra={"path": html_file}) logger.info("writing formatted html file", extra={"path": html_file})
f.write(format_html(content)) f.write(format_html(content))
return sorted(alltags) return set(sorted(alltags))
def list_folder(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[tuple[str, str, str]]: def list_folder(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[tuple[str, str, str]]:

View File

@@ -21,11 +21,7 @@ from datetime import datetime
from pythonjsonlogger import jsonlogger from pythonjsonlogger import jsonlogger
# Constants for file paths and exclusions # Constants for file paths and exclusions
if __package__ is None: SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)).removesuffix(__package__)
PACKAGE = ""
else:
PACKAGE = __package__
SCRIPTDIR = os.path.abspath(os.path.dirname(__file__).removesuffix(PACKAGE))
LOG_DIR = os.path.join(SCRIPTDIR, "logs") LOG_DIR = os.path.join(SCRIPTDIR, "logs")
LATEST_LOG_FILE = os.path.join(LOG_DIR, "latest.jsonl") LATEST_LOG_FILE = os.path.join(LOG_DIR, "latest.jsonl")

View File

@@ -18,11 +18,7 @@ from modules.argumentparser import Args
from modules.css_color import extract_theme_color, extract_colorscheme from modules.css_color import extract_theme_color, extract_colorscheme
# Define constants for static files directory and icon sizes # Define constants for static files directory and icon sizes
if __package__ is None: SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)).removesuffix(__package__)
PACKAGE = ""
else:
PACKAGE = __package__
SCRIPTDIR = os.path.abspath(os.path.dirname(__file__).removesuffix(PACKAGE))
STATIC_FILES_DIR = os.path.join(SCRIPTDIR, "files") STATIC_FILES_DIR = os.path.join(SCRIPTDIR, "files")
ICON_SIZES = ["36x36", "48x48", "72x72", "96x96", "144x144", "192x192", "512x512"] ICON_SIZES = ["36x36", "48x48", "72x72", "96x96", "144x144", "192x192", "512x512"]

View File

@@ -1,12 +1,12 @@
beautifulsoup4~=4.13.4 beautifulsoup4~=4.14.3
CairoSVG~=2.7.1 CairoSVG~=2.7.1
ConfigArgParse~=1.7.1
defusedxml~=0.7.1 defusedxml~=0.7.1
html5lib~=1.1 html5lib~=1.1
Jinja2~=3.1.6 Jinja2~=3.1.6
jsmin~=3.0.1 jsmin~=3.0.1
Pillow~=11.3.0 Pillow~=12.1.0
pyinstaller~=6.11.1
python_json_logger~=2.0.7 python_json_logger~=2.0.7
rich_argparse~=1.7.1 rich_argparse~=1.7.2
selenium~=4.34.2 selenium~=4.40.0
tqdm~=4.66.4 tqdm~=4.66.6

View File

@@ -74,6 +74,27 @@
font-weight: 800; 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 { body {
color: var(--bcolor1); color: var(--bcolor1);
background-color: var(--color4); background-color: var(--color4);

View File

@@ -53,7 +53,7 @@
} }
.tagentry label:hover { .tagentry label:hover {
background-color: var(--color7); background-color: var(--color4);
} }
.tagentry .tagtoggle:hover { .tagentry .tagtoggle:hover {
@@ -74,6 +74,27 @@
font-weight: 800; 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 { body {
color: var(--bcolor2); color: var(--bcolor2);
background-color: var(--bcolor1); background-color: var(--bcolor1);

View File

@@ -1,9 +1,6 @@
class PhotoGallery { class PhotoGallery {
constructor() { constructor() {
this.pswpElement = document.querySelector(".pswp"); this.pswpElement = document.querySelector(".pswp");
this.re = /pid=(\d+)/;
this.filterRe = /#(.*)/;
this.recursiveRe = /\?recursive/;
this.items = []; this.items = [];
this.shown = []; this.shown = [];
this.subfolders = []; this.subfolders = [];
@@ -27,6 +24,10 @@ class PhotoGallery {
this.scrollFunction = this.scrollFunction.bind(this); this.scrollFunction = this.scrollFunction.bind(this);
this.topFunction = this.topFunction.bind(this); this.topFunction = this.topFunction.bind(this);
this.onLoad = this.onLoad.bind(this); this.onLoad = this.onLoad.bind(this);
this.darkMode = this.darkMode.bind(this);
this.lightMode = this.lightMode.bind(this);
this.darkModeToggle = this.darkModeToggle.bind(this);
this.detectDarkMode = this.detectDarkMode.bind(this);
this.init(); this.init();
} }
@@ -41,12 +42,7 @@ class PhotoGallery {
openSwipe(imgIndex) { openSwipe(imgIndex) {
const options = { index: imgIndex }; const options = { index: imgIndex };
const gallery = new PhotoSwipe( const gallery = new PhotoSwipe(this.pswpElement, PhotoSwipeUI_Default, this.shown, options);
this.pswpElement,
PhotoSwipeUI_Default,
this.shown,
options
);
gallery.init(); gallery.init();
} }
@@ -57,7 +53,7 @@ class PhotoGallery {
const controller = new AbortController(); const controller = new AbortController();
const signal = controller.signal; const signal = controller.signal;
this.controllers[imgIndex] = controller; this.controllers[imgIndex] = controller;
const urlToFetch = this.items[imgIndex]?.src; const urlToFetch = this.shown[imgIndex]?.src;
if (urlToFetch) { if (urlToFetch) {
fetch(urlToFetch, { method: "GET", signal }).catch(() => {}); fetch(urlToFetch, { method: "GET", signal }).catch(() => {});
} }
@@ -71,25 +67,31 @@ class PhotoGallery {
} }
reset() { reset() {
const curr = window.location.href.split("#");
const content = document.documentElement.innerHTML; const content = document.documentElement.innerHTML;
const title = document.title; const title = document.title;
const folders = document.querySelector(".folders"); 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 = ""; if (folders) folders.style.display = "";
document.getElementById("recursive").checked = false; document.getElementById("recursive").checked = false;
document document.querySelectorAll("#tagdropdown input.tagcheckbox:checked").forEach((checkbox) => (checkbox.checked = false));
.querySelectorAll("#tagdropdown input.tagcheckbox:checked") window.history.replaceState({ html: content, pageTitle: title }, "", path);
.forEach((checkbox) => (checkbox.checked = false));
window.history.replaceState(
{ html: content, pageTitle: title },
"",
curr[0].split("?")[0] + "#"
);
this.requestMetadata(); this.requestMetadata();
} }
showLoader() {
const imagelist = document.getElementById("imagelist");
imagelist.innerHTML = '<span class="loader"></span>';
imagelist.classList.add("centerload");
imagelist.classList.remove("row");
}
async recursive() { async recursive() {
const curr = window.location.href.split("#"); this.showLoader();
const loc = new URL(window.location.href);
const content = document.documentElement.innerHTML; const content = document.documentElement.innerHTML;
const title = document.title; const title = document.title;
const isChecked = document.getElementById("recursive")?.checked; const isChecked = document.getElementById("recursive")?.checked;
@@ -97,21 +99,16 @@ class PhotoGallery {
if (!isChecked) { if (!isChecked) {
if (folders) folders.style.display = ""; if (folders) folders.style.display = "";
window.history.replaceState( loc.searchParams.delete("recursive");
{ html: content, pageTitle: title }, window.history.replaceState({ html: content, pageTitle: title }, "", loc);
"",
curr[0].split("?")[0] + "#" + (curr[1] || "")
);
this.requestMetadata(); this.requestMetadata();
return; return;
} }
if (folders) folders.style.display = "none"; if (folders) folders.style.display = "none";
window.history.replaceState( loc.searchParams.delete("recursive");
{ html: content, pageTitle: title }, loc.searchParams.append("recursive", true);
"", window.history.replaceState({ html: content, pageTitle: title }, "", loc);
curr[0].split("?")[0] + "?recursive#" + (curr[1] || "")
);
const visited = new Set(); const visited = new Set();
const existingItems = new Set(); const existingItems = new Set();
@@ -150,10 +147,9 @@ class PhotoGallery {
existingItems.add(image.src); existingItems.add(image.src);
} }
} }
if (Array.isArray(data.subfolders)) if (Array.isArray(data.subfolders)) nextLevel.push(...data.subfolders);
nextLevel.push(...data.subfolders);
} catch {} } catch {}
}) }),
); );
if (nextLevel.length > 0) await fetchFoldersRecursively(nextLevel); if (nextLevel.length > 0) await fetchFoldersRecursively(nextLevel);
}; };
@@ -164,6 +160,9 @@ class PhotoGallery {
} }
requestMetadata() { requestMetadata() {
this.showLoader();
const hash = window.location.hash;
const searchParams = new URLSearchParams(window.location.search);
fetch(".metadata.json") fetch(".metadata.json")
.then((response) => { .then((response) => {
if (!response.ok) throw new Error("Failed to fetch metadata"); if (!response.ok) throw new Error("Failed to fetch metadata");
@@ -173,64 +172,53 @@ class PhotoGallery {
this.items = Object.values(data.images || {}); this.items = Object.values(data.images || {});
this.subfolders = data.subfolders || []; this.subfolders = data.subfolders || [];
if (this.filterRe.test(window.location.href)) { if (hash != "") {
const selected = window.location.href const selected = hash.replace("#", "").split(",");
.match(this.filterRe)[1]
.split(",");
this.setFilter(selected); this.setFilter(selected);
} }
if (this.recursiveRe.test(window.location.href)) { if (searchParams.get("recursive") != null) {
const recChk = document.getElementById("recursive"); const recChk = document.getElementById("recursive");
if (recChk) recChk.checked = true; if (recChk) recChk.checked = true;
this.recursive(); this.recursive();
} else { } else {
this.filter(); this.filter();
} }
if (this.re.test(window.location.href)) {
const pid = window.location.href.match(this.re)[1];
this.openSwipe(parseInt(pid));
}
}) })
.catch(() => {}); .catch(() => {});
} }
filter() { filter() {
const searchParams = new URLSearchParams(window.location.search);
this.shown = []; this.shown = [];
const curr = window.location.href.split("#")[0] + "#"; let path = decodeURIComponent(window.location.origin + window.location.pathname.replace("index.html", ""));
const path = decodeURIComponent( if (path.startsWith("null")) {
window.location.href.split("#")[0].replace("index.html", "") path = window.location.protocol + "//" + path.substring(4);
); }
const selectedTags = []; const selectedTags = [];
document document.querySelectorAll("#tagdropdown input.tagcheckbox:checked").forEach((checkbox) => {
.querySelectorAll("#tagdropdown input.tagcheckbox:checked") let tag = checkbox.parentElement.id.trim().substring(1);
.forEach((checkbox) => { if (checkbox.parentElement.parentElement.children.length > 1) tag += "|";
let tag = checkbox.parentElement.id.trim().substring(1); selectedTags.push(tag);
if (checkbox.parentElement.parentElement.children.length > 1) });
tag += "|";
selectedTags.push(tag);
});
const urltags = selectedTags.join(","); const urltags = selectedTags.join(",");
let isRecursiveChecked = false; let isRecursiveChecked = false;
try { try {
isRecursiveChecked = isRecursiveChecked = document.getElementById("recursive")?.checked || false;
document.getElementById("recursive")?.checked || false;
} catch {} } catch {}
for (const item of this.items) { for (const item of this.items) {
const tags = item.tags || []; const tags = item.tags || [];
const include = selectedTags.every((selected) => { const include = selectedTags.every((selected) => {
const isParent = selected.endsWith("|"); const isParent = selected.endsWith("|");
return isParent return isParent ? tags.some((t) => t.startsWith(selected)) : tags.includes(selected);
? tags.some((t) => t.startsWith(selected))
: tags.includes(selected);
}); });
if (include || selectedTags.length === 0) { if (include || selectedTags.length === 0) {
if (!isRecursiveChecked) { if (!isRecursiveChecked) {
if (decodeURIComponent(item.src.replace(item.name, "")) === path) { if (decodeURIComponent(item.src).replace(item.name, "") === path) {
this.shown.push(item); this.shown.push(item);
} }
} else { } else {
@@ -239,37 +227,99 @@ class PhotoGallery {
} }
} }
this.updateImageList(); this.updateImageList();
window.location.href = curr + urltags; window.location.hash = urltags;
const pid = searchParams.get("pid") - 1;
if (pid != -1) {
this.openSwipe(pid);
}
} }
insertPath(obj, path) {
let current = obj;
for (let i = 0; i < path.length; i++) {
const part = path[i];
if (i === path.length - 1) {
if (!current[part]) {
current[part] = null;
}
} else {
if (!current[part] || typeof current[part] !== "object") {
current[part] = {};
}
current = current[part];
}
}
}
finalize(obj) {
if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
const result = {};
Object.keys(obj)
.sort()
.forEach((key) => {
if (obj[key] === null) {
result[key] = [];
} else {
result[key] = this.finalize(obj[key]);
}
});
return result;
}
return obj || [];
}
parseHierarchicalTags(tags, delimiter = "|") {
const tree = {};
for (const tag of tags) {
const parts = tag.split(delimiter);
this.insertPath(tree, parts);
}
return this.finalize(tree);
}
renderTree = (obj, depth = 0) => {
let lines = [];
const indent = "&nbsp;&nbsp;".repeat(depth);
for (const key of Object.keys(obj)) {
lines.push(indent + key);
if (Array.isArray(obj[key])) {
for (const val of obj[key]) {
lines.push("&nbsp;&nbsp;".repeat(depth + 1) + val);
}
} else if (typeof obj[key] === "object" && obj[key] !== null) {
lines = lines.concat(this.renderTree(obj[key], depth + 1));
}
}
return lines.join("\n");
};
updateImageList() { updateImageList() {
const imagelist = document.getElementById("imagelist"); const imagelist = document.getElementById("imagelist");
if (!imagelist) return; if (!imagelist) return;
let str = ""; let str = "";
this.shown.forEach((item, index) => { this.shown.forEach((item, index) => {
str += `<div class="column"><figure><img src="${item.msrc}" data-index="${index}" /><figcaption class="caption">${item.name}`; let tags = this.parseHierarchicalTags(item.tags || []);
if (item.tiff) str += ` <a href="${item.tiff}">TIFF</a>`; str += `<div class="column"><figure title="${this.renderTree(tags)}"><img src="${
if (item.raw) str += ` <a href="${item.raw}">RAW</a>`; 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>"; str += "</figcaption></figure></div>";
}); });
imagelist.classList.add("row");
imagelist.classList.remove("centerload");
imagelist.innerHTML = str; imagelist.innerHTML = str;
} }
setFilter(selected) { setFilter(selected) {
document document.querySelectorAll("#tagdropdown input.tagcheckbox").forEach((checkbox) => {
.querySelectorAll("#tagdropdown input.tagcheckbox") selected.forEach((tag) => {
.forEach((checkbox) => { if (checkbox.parentElement.id.trim().substring(1).replace(" ", "%20") === tag) {
selected.forEach((tag) => { checkbox.checked = true;
if ( }
checkbox.parentElement.id
.trim()
.substring(1)
.replace(" ", "%20") === tag
) {
checkbox.checked = true;
}
});
}); });
});
} }
toggleTag(tagid) { toggleTag(tagid) {
@@ -278,9 +328,7 @@ class PhotoGallery {
const svg = tag?.parentElement.querySelector(".tagtoggle svg"); const svg = tag?.parentElement.querySelector(".tagtoggle svg");
if (!ol || !svg) return; if (!ol || !svg) return;
ol.classList.toggle("show"); ol.classList.toggle("show");
svg.style.transform = ol.classList.contains("show") svg.style.transform = ol.classList.contains("show") ? "rotate(180deg)" : "rotate(0deg)";
? "rotate(180deg)"
: "rotate(0deg)";
} }
setupDropdownToggle() { setupDropdownToggle() {
@@ -292,18 +340,12 @@ class PhotoGallery {
event.stopPropagation(); event.stopPropagation();
const svg = toggleLink.querySelector("svg"); const svg = toggleLink.querySelector("svg");
dropdown.classList.toggle("show"); dropdown.classList.toggle("show");
if (svg) if (svg) svg.style.transform = dropdown.classList.contains("show") ? "rotate(180deg)" : "rotate(0deg)";
svg.style.transform = dropdown.classList.contains("show")
? "rotate(180deg)"
: "rotate(0deg)";
this.tagDropdownShown = dropdown.classList.contains("show"); this.tagDropdownShown = dropdown.classList.contains("show");
}); });
document.addEventListener("click", (event) => { document.addEventListener("click", (event) => {
if ( if (!dropdown.contains(event.target) && !toggleLink.contains(event.target)) {
!dropdown.contains(event.target) &&
!toggleLink.contains(event.target)
) {
dropdown.classList.remove("show"); dropdown.classList.remove("show");
this.tagDropdownShown = false; this.tagDropdownShown = false;
const svg = toggleLink.querySelector("svg"); const svg = toggleLink.querySelector("svg");
@@ -330,18 +372,18 @@ class PhotoGallery {
} }
setupClickHandlers() { setupClickHandlers() {
const resetEl = document const resetEl = document.getElementById("reset-filter")?.querySelector("label");
.getElementById("reset-filter")
?.querySelector("label");
if (resetEl) resetEl.addEventListener("click", this.reset); if (resetEl) resetEl.addEventListener("click", this.reset);
const recurseEl = document.getElementById("recursive"); const recurseEl = document.getElementById("recursive");
if (recurseEl) if (recurseEl) recurseEl.addEventListener("change", this.debounce(this.recursive, 150));
recurseEl.addEventListener("change", this.debounce(this.recursive, 150));
const totop = document.getElementById("totop"); const totop = document.getElementById("totop");
if (totop) totop.addEventListener("click", this.topFunction); if (totop) totop.addEventListener("click", this.topFunction);
const darkModeSwitch = document.getElementById("dark-mode-switch");
if (darkModeSwitch) darkModeSwitch.addEventListener("click", this.darkModeToggle);
const imagelist = document.getElementById("imagelist"); const imagelist = document.getElementById("imagelist");
if (imagelist) { if (imagelist) {
imagelist.addEventListener("click", (event) => { imagelist.addEventListener("click", (event) => {
@@ -370,10 +412,7 @@ class PhotoGallery {
scrollFunction() { scrollFunction() {
const totopbutton = document.getElementById("totop"); const totopbutton = document.getElementById("totop");
if (!totopbutton) return; if (!totopbutton) return;
if ( if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
document.body.scrollTop > 20 ||
document.documentElement.scrollTop > 20
) {
totopbutton.style.display = "block"; totopbutton.style.display = "block";
} else { } else {
totopbutton.style.display = "none"; totopbutton.style.display = "none";
@@ -384,6 +423,53 @@ class PhotoGallery {
window.scrollTo({ top: 0, behavior: "smooth" }); window.scrollTo({ top: 0, behavior: "smooth" });
} }
darkMode() {
const themeLink = document.getElementById("theme");
const darkThemeLink = document.getElementById("darktheme");
if (themeLink) themeLink.disabled = true;
if (darkThemeLink) darkThemeLink.disabled = false;
}
lightMode() {
const themeLink = document.getElementById("theme");
const darkThemeLink = document.getElementById("darktheme");
if (themeLink) themeLink.disabled = false;
if (darkThemeLink) darkThemeLink.disabled = true;
}
darkModeToggle(mode) {
const switchState = document.getElementById("dark-mode-switch-check");
if (mode == "dark") {
this.darkMode();
if (switchState) {
switchState.checked = true;
}
} else if (mode == "light") {
this.lightMode();
if (switchState) {
switchState.checked = false;
}
} else {
if (switchState.checked) {
switchState.checked = false;
this.lightMode();
} else {
switchState.checked = true;
this.darkMode();
}
}
}
detectDarkMode() {
if (document.getElementById("darktheme")) {
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
this.darkModeToggle("dark");
} else {
this.darkModeToggle("light");
}
}
}
onLoad() { onLoad() {
document.querySelectorAll(".tagtoggle").forEach((toggle) => { document.querySelectorAll(".tagtoggle").forEach((toggle) => {
toggle.addEventListener("mouseup", (event) => { toggle.addEventListener("mouseup", (event) => {
@@ -397,6 +483,7 @@ class PhotoGallery {
this.setupDropdownToggle(); this.setupDropdownToggle();
this.setupTagHandlers(); this.setupTagHandlers();
this.setupClickHandlers(); this.setupClickHandlers();
this.detectDarkMode();
window.addEventListener("scroll", this.scrollFunction); window.addEventListener("scroll", this.scrollFunction);
} }

View File

@@ -34,10 +34,16 @@
{%- if theme %} {%- if theme %}
<link rel="preload" href="{{ theme }}" as="style"> <link rel="preload" href="{{ theme }}" as="style">
{%- endif %} {%- endif %}
{%- if darktheme %}
<link rel="preload" href="{{ darktheme }}" as="style">
{%- endif %}
<link rel="icon" type="image/x-icon" href="{{ favicon }}"> <link rel="icon" type="image/x-icon" href="{{ favicon }}">
<link rel="stylesheet" href="{{ stylesheet }}"> <link rel="stylesheet" href="{{ stylesheet }}">
{%- if theme %} {%- if theme %}
<link rel="stylesheet" href="{{ theme }}"> <link rel="stylesheet" href="{{ theme }}" id="theme">
{%- endif %}
{%- if darktheme %}
<link rel="stylesheet" href="{{ darktheme }}" id="darktheme" disabled>
{%- endif %} {%- endif %}
<link rel="preload" href="{{ root }}.static/pswp/photoswipe.css" as="style"> <link rel="preload" href="{{ root }}.static/pswp/photoswipe.css" as="style">
<link rel="preload" href="{{ root }}.static/pswp/default-skin/default-skin.css" as="style"> <link rel="preload" href="{{ root }}.static/pswp/default-skin/default-skin.css" as="style">
@@ -89,10 +95,22 @@
{{ render_tags(tags, '') }} {{ render_tags(tags, '') }}
</ol> </ol>
</li> </li>
{% endif %} {%- endif %}
{%- if licensefile %} {%- if licensefile %}
<li class="license"><a href="{{ licensefile }}">License</a></li> <li class="license"><a href="{{ licensefile }}">License</a></li>
{%- endif %} {%- endif %}
{%- if darktheme %}
<li class="darkmodeswitch">
<a class="button" id="dark-mode-switch">
<input type="checkbox" class="checkbox" id="dark-mode-switch-check" />
<div class="knobs">
<span class="light">☀︎</span>
<span class="slider"></span>
<span class="dark">☽</span>
</div>
</a>
</li>
{%- endif %}
</div> </div>
</ol> </ol>
{% if subdirectories %} {% if subdirectories %}
@@ -120,7 +138,7 @@
<a property="dct:title" rel="cc:attributionURL" href="{{ root }}">{{ license.project }}</a> by <span property="cc:attributionName">{{ license.author }}</span> is marked with <a property="dct:title" rel="cc:attributionURL" href="{{ root }}">{{ license.project }}</a> by <span property="cc:attributionName">{{ license.author }}</span> is marked with
<a href="{{ license.url }}" target="_blank" rel="license noopener noreferrer" style="display: inline-block">CC0 1.0 <a href="{{ license.url }}" target="_blank" rel="license noopener noreferrer" style="display: inline-block">CC0 1.0
{%- for pic in license.pics %} {%- for pic in license.pics %}
<img style="height: 22px !important; margin-left: 3px; vertical-align: text-bottom" src="{{ pic }}" alt="" /> <img src="{{ pic }}" alt="" />
{%- endfor %} {%- endfor %}
</a> </a>
{%- else %} {%- else %}

1
themes Submodule

Submodule themes added at 3bb36480e7

View File

@@ -1,106 +0,0 @@
# Custom CSS Themes
You can create custom Themes. They must at least include the following:
## Requirements for Themes
### Required Variables
Define the following variables in your theme:
- `--color1`: Primary color
- `--color2`: Secondary color
- `--color3`: Additional color
- `--color4`: Another color
These variables are essential for automatic icon generation.
### Folder Icon Specification
Include the following CSS rule to specify the folder icon used in your theme:
```css
.foldericon {
content: url("data:image/svg+xml,%3Csvg width='800px' height='800px' viewBox='0 0 1024 1024' class='icon' version='1.1' xmlns='http://www.w3.org/2000/svg' fill='%23000000'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0' /%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Cpath d='M853.333333 256H469.333333l-85.333333-85.333333H170.666667c-46.933333 0-85.333333 38.4-85.333334 85.333333v170.666667h853.333334v-85.333334c0-46.933333-38.4-85.333333-85.333334-85.333333z' fill='%233674e7' /%3E%3Cpath d='M853.333333 256H170.666667c-46.933333 0-85.333333 38.4-85.333334 85.333333v426.666667c0 46.933333 38.4 85.333333 85.333334 85.333333h682.666666c46.933333 0 85.333333-38.4 85.333334-85.333333V341.333333c0-46.933333-38.4-85.333333-85.333334-85.333333z' fill='%236495ed' /%3E%3C/g%3E%3C/svg%3E");
}
```
Replace the SVG data URI (`url("data:image/svg+xml,...")`) with your desired SVG icon content.
## Previews of included themes
### alpenglow-dark
![alpenglow-dark](screenshots/alpenglow-dark.png)
### alpenglow
![alpenglow](screenshots/alpenglow.png)
### aritim-dark
![aritim-dark](screenshots/aritim-dark.png)
### aritim
![aritim](screenshots/aritim.png)
### autumn
![autumn](screenshots/autumn.png)
### carnation
![carnation](screenshots/carnation.png)
### catpuccin
![catpuccin](screenshots/catpuccin.png)
### cornflower
![cornflower](screenshots/cornflower.png)
### default-dark
![default-dark](screenshots/default-dark.png)
### default
![default](screenshots/default.png)
### ivy
![ivy](screenshots/ivy.png)
### kjoe
![kjoe](screenshots/kjoe.png)
### monokai-vibrant
![monokai-vibrant](screenshots/monokai-vibrant.png)
### rainbow
![rainbow](screenshots/rainbow.png)
### spring
![spring](screenshots/spring.png)
### steam
![steam](screenshots/steam.png)
### summer
![summer](screenshots/summer.png)
### sunflower
![sunflower](screenshots/sunflower.png)
### winter
![winter](screenshots/winter.png)

View File

@@ -1,120 +0,0 @@
@import url("https://fonts.cdnfonts.com/css/metropolis-2");
* {
--color1: #ffa769;
--color2: #fc4ca0;
--color3: #7542e5;
--color4: #ff4ad9;
--color5: #5f2eca;
--color6: #7033ca;
--color7: #ff778e;
--bcolor1: #e2d9f8;
--bcolor2: #20123a;
--bcolor3: #2b1753;
--bcolor4: #321c64;
--gradient: linear-gradient(
80deg,
var(--bcolor2) 0%,
var(--color5) 1%,
var(--color3) 2%,
var(--color2) 3%,
var(--color1) 4%,
var(--color1) 96%,
var(--color2) 97%,
var(--color3) 98%,
var(--color5) 99%,
var(--bcolor2) 100%
);
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Metropolis", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.navbar {
font-weight: 800;
color: var(--bcolor1);
background-color: var(--color3);
background-image: var(--gradient);
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
}
.navbar li a:hover {
text-decoration: none;
background-color: var(--color4);
}
.footer {
color: var(--bcolor2);
background-color: var(--color1);
font-weight: 600;
}
.footer a {
color: var(--color2);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/catpuccin.svg.j2";
}
.folders a {
font-weight: 500;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color7);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 500;
background-color: var(--color6);
}
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
.column img {
background-color: var(--bcolor2);
}
#totop:hover {
background-color: var(--color6);
}
#totop {
background-color: var(--bcolor4);
color: var(--bcolor1);
font-weight: 600;
}

View File

@@ -1,119 +0,0 @@
@import url("https://fonts.cdnfonts.com/css/metropolis-2");
* {
--color1: #ffa769;
--color2: #fc4ca0;
--color3: #7542e5;
--color4: #ff4ad9;
--color5: #ff778e;
--color6: #fff5f6;
--color7: #5f2eca;
--bcolor1: #ffe7ea;
--bcolor2: #20123b;
--bcolor3: #2b1753;
--bcolor4: #321c64;
--gradient: linear-gradient(80deg,
var(--bcolor2) 0%,
var(--color3) 1%,
var(--color4) 2%,
var(--color5) 3%,
var(--color1) 4%,
var(--color1) 96%,
var(--color5) 97%,
var(--color4) 98%,
var(--color3) 99%,
var(--bcolor2) 100%);
}
body {
color: var(--bcolor2);
background-color: var(--color6);
font-family: "Metropolis", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.navbar {
font-weight: 800;
color: var(--bcolor2);
background-color: var(--color5);
background-image: var(--gradient);
}
.navbar li a {
font-weight: 800;
color: var(--bcolor2);
}
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor1);
background-color: var(--bcolor4);
font-weight: 600;
}
.footer a {
color: var(--color5);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/catpuccin.svg.j2";
}
.folders a {
font-weight: 500;
color: var(--bcolor2);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color7);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 500;
color: var(--bcolor1);
background-color: var(--color3);
}
.tagentry label:hover {
background-color: var(--color7);
}
.tagentry .tagtoggle:hover {
background-color: var(--color7);
}
.column img {
background-color: var(--bcolor1);
}
#totop:hover {
background-color: var(--color3);
}
#totop {
background-color: var(--color2);
color: var(--bcolor2);
font-weight: 600;
}

View File

@@ -1,106 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
* {
--color1: #5d88ca;
--color2: #27ae60;
--color3: #f67400;
--color4: #da4453;
--color5: #212b36;
--bcolor1: #10151a;
--bcolor2: #d3dae3;
--bcolor3: #141a21;
}
.navbar {
font-weight: 600;
color: var(--bcolor2);
background-color: var(--color5);
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--bcolor3);
}
.footer {
color: var(--bcolor1);
background-color: var(--color2);
font-weight: 500;
}
.footer a {
color: var(--color4);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-papirus.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color1);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
background-color: var(--bcolor1);
}
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
.column img {
background-color: var(--bcolor1);
}
#totop:hover {
background-color: var(--color3);
}
#totop {
background-color: var(--color5);
color: var(--bcolor2);
font-weight: 600;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Poppins", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,106 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
* {
--color1: #1d99f3;
--color2: #27ae60;
--color3: #f67400;
--color4: #da4453;
--color5: #eef2f5;
--bcolor1: #a3a5ac;
--bcolor2: #303030;
--bcolor3: #eff0f1;
}
.navbar {
font-weight: 600;
color: var(--bcolor2);
background-color: var(--bcolor1);
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
color: var(--bcolor1);
background-color: var(--bcolor2);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 500;
}
.footer a {
color: var(--color4);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-papirus.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color1);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
background-color: var(--bcolor1);
}
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
.column img {
background-color: var(--bcolor1);
}
#totop:hover {
background-color: var(--color4);
}
#totop {
background-color: var(--color5);
color: var(--bcolor2);
font-weight: 600;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Poppins", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,112 +0,0 @@
@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 */
}
.navbar {
font-weight: 600;
color: var(--bcolor1);
background-color: var(--color1);
font-family: "Playfair Display", serif;
}
.navbar li a {
font-weight: 500;
color: var(--bcolor1);
font-family: "Playfair Display", serif;
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor1);
background-color: var(--color3);
font-weight: 500;
font-family: "Playfair Display", serif;
}
.footer a {
color: var(--color4);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-3.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor1);
text-decoration: none;
font-family: "Playfair Display", serif;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color2);
text-decoration: none;
font-family: "Playfair Display", serif;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
background-color: var(--bcolor2);
font-family: "Playfair Display", serif;
}
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 600;
font-family: "Playfair Display", serif;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Playfair Display", serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,105 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: #8b0000;
--color2: #b22222;
--color3: #ff4500;
--color4: #6e0000;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor3);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-1.svg.j2";
}
.folders a {
font-weight: 800;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color2);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

View File

@@ -1,113 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700&display=swap");
* {
--color1: #F28FAD;
--color2: #ABE9B3;
--color3: #FAE3B0;
--color4: #96CDFB;
--bcolor1: #F5E0DC;
--bcolor2: #575268;
--bcolor3: #D9E0EE;
--bcolor4: #C9CBFF;
}
.navbar {
font-weight: 600;
color: var(--bcolor2);
background-color: var(--color1);
font-family: "Nunito", sans-serif;
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
font-family: "Nunito", sans-serif;
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 500;
font-family: "Nunito", sans-serif;
}
.footer a {
color: var(--color1);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/catpuccin.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
font-family: "Nunito", sans-serif;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color1);
text-decoration: none;
font-family: "Nunito", sans-serif;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
background-color: var(--color3);
font-family: "Nunito", sans-serif;
}
.tagentry label:hover {
background-color: var(--color4);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
color: var(--bcolor2);
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 600;
font-family: "Nunito", sans-serif;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Nunito", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,105 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: cornflowerblue;
--color2: #1346a4;
--color3: #0e3377;
--color4: #3674e7;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor3);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-1.svg.j2";
}
.folders a {
font-weight: 800;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color2);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

View File

@@ -1,90 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap");
* {
--color1: #333333;
--color2: #888888;
--color3: #dddddd;
--color4: #111111;
--color5: #0055ff;
--bcolor1: #ffffff;
--bcolor2: #000000;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
background-color: var(--color1);
}
.navbar li a {
font-weight: 700;
color: var(--bcolor1);
}
/* Change the link color on hover */
.navbar li a:hover {
background-color: var(--color4);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 500;
}
.footer a {
color: var(--color5);
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-2.svg.j2";
}
.folders a {
font-weight: 700;
color: var(--color5);
text-decoration: none;
}
.tooltiptext {
font-weight: 400;
background-color: var(--color2);
}
.tagentry label:hover {
background-color: var(--color4);
}
.tagentry .tagtoggle:hover {
background-color: var(--color4);
}
.column img {
background-color: var(--color2);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor1);
font-family: "Ubuntu", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}
body a {
font-weight: 400;
color: var(--color5);
text-decoration: none;
}

View File

@@ -1,6 +0,0 @@
<svg width='64' height='64' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path d='M20 6H10L8 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V8C22 6.89543 21.1046 6 20 6Z' fill='{{ color1 }}' />
<path d='M4 4H8L10 6H20C21.1046 6 22 6.89543 22 8H2C2 6.89543 2.89543 6 4 6V4Z' fill='{{ color4 }}' />
<path d='M10 6H14L12 4H8L10 6Z' fill='{{ color3 }}' />
<path d='M14 6H18L16 4H12L14 6Z' fill='{{ color2 }}' />
</svg>

Before

Width:  |  Height:  |  Size: 493 B

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<path style="fill:{{ color2 }};" d="M44.5,41h-41C2.119,41,1,39.881,1,38.5v-31C1,6.119,2.119,5,3.5,5h11.597
c1.519,0,2.955,0.69,3.904,1.877L21.5,10h23c1.381,0,2.5,1.119,2.5,2.5v26C47,39.881,45.881,41,44.5,41z" />
<path style="fill:{{ color2 }};" d="M2,25h20V11H4c-1.105,0-2,0.895-2,2V25z" />
<path style="fill:#FFFFFF;" d="M2,26h20V12H4c-1.105,0-2,0.895-2,2V26z" />
<path style="fill:{{ color1 }};" d="M1,37.875V38.5C1,39.881,2.119,41,3.5,41h41c1.381,0,2.5-1.119,2.5-2.5v-0.625H1z" />
<path style="fill:{{ color2 }};"
d="M44.5,11h-23l-1.237,0.824C19.114,12.591,17.763,13,16.381,13H3.5C2.119,13,1,14.119,1,15.5v22C1,38.881,2.119,40,3.5,40h41c1.381,0,2.5-1.119,2.5-2.5v-24C47,12.119,45.881,11,44.5,11z" />
<path style="fill:{{ color1 }};" d="M44.5,40h-41C2.119,40,1,38.881,1,37.5v-21C1,15.119,2.119,14,3.5,14h13.256
c1.382,0,2.733-0.409,3.883-1.176L21.875,12H44.5c1.381,0,2.5,1.119,2.5,2.5v23C47,38.881,45.881,40,44.5,40z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img"
preserveAspectRatio="xMidYMid meet">
<path fill="{{ color2 }}"
d="M491 326V92.143C491 79.021 480.259 68 467.137 68H341.13c-9.287 0-17.723 5.603-21.596 14.044l-12.709 27.903C302.952 118.388 294.516 124 285.229 124H67.538C54.416 124 44 134.426 44 147.549v216.363C44 377.034 54.416 388 67.538 388h399.599c.628 0 1.248-.36 1.863-.408V433h.342c0 6 4.877 10.636 10.829 10.636c5.952 0 10.829-4.967 10.829-10.919V326z">
</path>
<path fill="{{ color1 }}"
d="M480.171 443.636c-5.952 0-10.829-4.636-10.829-10.636H469V210.181C469 197.058 458.661 186 445.539 186H45.94C32.818 186 22 197.058 22 210.181V449.37C22 462.492 32.818 473 45.94 473h399.599c1.385 0 2.741-.06 4.061-.288c1.639.227 3.31.385 5.012.385c20.04 0 36.136-16.229 36.136-36.269c0-.534-.036-1.058-.058-1.586c-1.147 4.766-5.435 8.394-10.519 8.394z">
</path>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,34 +0,0 @@
<svg height="200px" width="200px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-51.2 -51.2 614.40 614.40" xml:space="preserve"
fill="#000000" stroke="#000000" stroke-width="0.00512" transform="matrix(1, 0, 0, 1, 0, 0)rotate(0)">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="10.24">
</g>
<g id="SVGRepo_iconCarrier">
<g transform="translate(0 1)">
<path style="fill: {{ color2 }};"
d="M422.4,144.067c0-18.773-13.653-34.133-29.867-34.133h-107.52l-37.547-51.2H81.92 c-11.947,0-22.187,11.947-22.187,25.6v59.733H422.4z"></path>
<path style="fill: {{ color3 }};" d="M426.667,109.933h-34.133c16.213,0,29.867,15.36,29.867,34.133h38.4 C460.8,125.293,445.44,109.933,426.667,109.933"></path>
<path style="fill: rgb(255, 255, 255);"
d="M81.92,58.733H59.733c-14.507,0-25.6,11.947-25.6,25.6v59.733h25.6V84.333 C59.733,70.68,69.973,58.733,81.92,58.733"></path>
<path style="fill: {{ color1 }};"
d="M34.133,169.667v256c0,14.507,10.24,25.6,23.04,25.6h397.653c12.8,0,23.04-11.093,23.04-25.6v-256 c0-14.507-10.24-25.6-23.04-25.6H57.173C44.373,144.067,34.133,156.013,34.133,169.667">
</path>
<path style="fill: rgb(255, 255, 255);"
d="M34.133,425.667v-256c0-14.507,10.24-25.6,23.04-25.6h-23.04c-14.507,0-25.6,11.093-25.6,25.6v256 c0,14.507,11.093,25.6,25.6,25.6h23.04C44.373,451.267,34.133,440.173,34.133,425.667">
</path>
<path style="fill: {{ color2 }};"
d="M477.867,144.067h-23.04c12.8,0,23.04,11.093,23.04,25.6v256c0,14.507-10.24,25.6-23.04,25.6h23.04 c14.507,0,25.6-11.093,25.6-25.6v-256C503.467,156.013,492.373,144.067,477.867,144.067">
</path>
<path
d="M477.867,459.8H34.133C15.36,459.8,0,444.44,0,425.667v-51.2c0-5.12,3.413-8.533,8.533-8.533s8.533,3.413,8.533,8.533v51.2 c0,9.387,7.68,17.067,17.067,17.067h443.733c9.387,0,17.067-7.68,17.067-17.067v-256c0-9.387-7.68-17.067-17.067-17.067H34.133 c-9.387,0-17.067,7.68-17.067,17.067V306.2c0,5.12-3.413,8.533-8.533,8.533S0,311.32,0,306.2V169.667 c0-18.773,15.36-34.133,34.133-34.133h443.733c18.773,0,34.133,15.36,34.133,34.133v256C512,444.44,496.64,459.8,477.867,459.8z">
</path>
<path d="M17.067,340.333c0-5.12-3.413-8.533-8.533-8.533S0,335.213,0,340.333c0,5.12,3.413,8.533,8.533,8.533 S17.067,345.453,17.067,340.333"></path>
<path
d="M460.8,152.6H34.133c-5.12,0-8.533-3.413-8.533-8.533V84.333C25.6,65.56,40.96,50.2,59.733,50.2h187.733 c2.56,0,5.12,0.853,6.827,3.413L294.4,101.4h132.267c23.893,0,42.667,18.773,42.667,42.667 C469.333,149.187,465.92,152.6,460.8,152.6z M42.667,135.533H450.56c-3.413-10.24-12.8-17.067-23.893-17.067H290.133 c-2.56,0-5.12-0.853-6.827-3.413L243.2,67.267H59.733c-9.387,0-17.067,7.68-17.067,17.067V135.533z">
</path>
<path d="M162.133,203.8h-102.4c-5.12,0-8.533-3.413-8.533-8.533c0-5.12,3.413-8.533,8.533-8.533h102.4 c5.12,0,8.533,3.413,8.533,8.533C170.667,200.387,167.253,203.8,162.133,203.8z"></path>
<path d="M162.133,237.933h-102.4c-5.12,0-8.533-3.413-8.533-8.533c0-5.12,3.413-8.533,8.533-8.533h102.4 c5.12,0,8.533,3.413,8.533,8.533C170.667,234.52,167.253,237.933,162.133,237.933z">
</path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="WQEfvoQAcpQgQgyjQQ4Hqa" x1="24" x2="24" y1="6.708" y2="14.977" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#eba600"/><stop offset="1" stop-color="#c28200"/></linearGradient><path fill="url(#WQEfvoQAcpQgQgyjQQ4Hqa)" d="M24.414,10.414l-2.536-2.536C21.316,7.316,20.553,7,19.757,7L5,7C3.895,7,3,7.895,3,9l0,30 c0,1.105,0.895,2,2,2l38,0c1.105,0,2-0.895,2-2V13c0-1.105-0.895-2-2-2l-17.172,0C25.298,11,24.789,10.789,24.414,10.414z"/><linearGradient id="WQEfvoQAcpQgQgyjQQ4Hqb" x1="24" x2="24" y1="10.854" y2="40.983" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffd869"/><stop offset="1" stop-color="#fec52b"/></linearGradient><path fill="url(#WQEfvoQAcpQgQgyjQQ4Hqb)" d="M21.586,14.414l3.268-3.268C24.947,11.053,25.074,11,25.207,11H43c1.105,0,2,0.895,2,2v26 c0,1.105-0.895,2-2,2H5c-1.105,0-2-0.895-2-2V15.5C3,15.224,3.224,15,3.5,15h16.672C20.702,15,21.211,14.789,21.586,14.414z"/></svg>

Before

Width:  |  Height:  |  Size: 1020 B

View File

@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" version="1">
<rect style="opacity:0.2" width="56" height="36" x="4" y="22" rx="2.8" ry="2.8" />
<path style="fill:{{ color2 }}"
d="M 4,46.2 C 4,47.751 5.2488,49 6.8,49 H 57.2 C 58.751,49 60,47.751 60,46.2 V 15.8 C 60,14.249 58.751,13 57.2,13 H 32 C 27.8,13 26.4,7 22.2,7 H 6.8 C 5.2488,7 4,8.2488 4,9.8" />
<rect style="opacity:0.2" width="56" height="36" x="4" y="20" rx="2.8" ry="2.8" />
<rect style="fill:#e4e4e4" width="48" height="22" x="8" y="16" rx="2.8" ry="2.8" />
<rect style="fill:{{ color1 }}" width="56" height="36" x="4" y="21" rx="2.8" ry="2.8" />
<path style="opacity:0.1;fill:#ffffff"
d="M 6.8008,7 C 5.2496,7 4,8.2496 4,9.8008 V 10.801 C 4,9.2496 5.2496,8 6.8008,8 H 22.199 C 26.399,8 27.8,14 32,14 H 57.199 C 58.75,14 60,15.25 60,16.801 V 15.801 C 60,14.25 58.75,13 57.199,13 H 32 C 27.8,13 26.399,7 22.199,7 Z" />
</svg>

Before

Width:  |  Height:  |  Size: 943 B

View File

@@ -1,11 +0,0 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='512' width='512' version='1.1' id='Layer_1' viewBox='0 0 327.68 327.68' xml:space='preserve' xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'>
<defs id='defs1' />
<g id='icon' transform='translate(-128.08785,-19.123746)'>
<path id='fg' style='fill:#dcdedf;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round'
d='m 428.2793,160.97461 c -78.34525,0.002 -156.69075,-0.007 -235.03585,0.0159 -6.54719,0.16827 -12.82625,4.35683 -15.37415,10.41233 -1.13922,2.74038 -1.79474,5.64883 -2.74311,8.45618 -10.27476,33.32809 -20.56379,66.65251 -30.78952,99.99526 -1.21885,4.66702 0.98496,9.97729 5.17832,12.3776 2.40372,1.49255 5.31559,1.67974 8.07056,1.58986 78.16762,-0.0305 156.33557,0.008 234.503,-0.0259 6.43644,-0.17102 12.61041,-4.22124 15.23762,-10.1162 1.2077,-2.75858 1.84495,-5.72012 2.81312,-8.56426 10.08283,-32.66775 20.13843,-65.34481 30.20361,-98.01744 0.84274,-2.37238 1.35887,-4.96865 0.67937,-7.45078 -0.98831,-4.2533 -4.6015,-7.82876 -8.96172,-8.48315 -1.24947,-0.20685 -2.51789,-0.23068 -3.78125,-0.18945 z' />
<path id='bg' style='fill:#dcdedf;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;paint-order:normal'
d='m 214.44922,72.089844 c -20.32611,0.01324 -40.65359,-0.03032 -60.97883,0.03325 -5.06767,0.228794 -9.72081,4.176673 -10.64873,9.186171 -0.54368,2.865585 -0.16202,5.794266 -0.28069,8.688777 -4.6e-4,27.527908 -0.008,55.056498 0.0176,82.583978 0.17186,3.22428 3.44977,5.89016 6.64757,5.28488 2.4037,-0.30447 4.32209,-2.31086 4.87898,-4.61617 3.53052,-10.60549 6.98896,-21.23707 10.60492,-31.81263 1.14174,-2.71356 4.14972,-4.41014 7.06111,-4.12697 16.80704,-0.0631 33.61433,-0.01 50.42149,-0.0279 55.72175,-0.002 111.44406,0.006 167.16547,-0.0191 5.71319,-0.19462 10.82844,-5.25566 10.91838,-11.00339 0.12602,-2.9908 -0.0352,-5.98579 0.0574,-8.97822 0.0534,-2.61272 -0.3941,-5.33067 -1.94259,-7.50013 -2.21535,-3.37352 -6.26106,-5.45808 -10.30253,-5.1988 -44.42303,-0.0315 -88.8461,0.006 -133.26914,-0.0339 -1.35699,0.0355 -2.86726,0.10531 -3.94821,-0.87625 -1.14131,-0.86056 -1.57137,-2.31551 -1.50179,-3.694889 -0.0148,-5.79966 0.0803,-11.603104 -0.0604,-17.400318 -0.41681,-5.210159 -4.80455,-9.807583 -10.02134,-10.361315 -2.37314,-0.240789 -4.76368,-0.0457 -7.14443,-0.12428 -5.89141,-0.0074 -11.78281,-0.0066 -17.67422,-0.0028 z' />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="100"
height="100"
viewBox="0 0 100 100"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="10"
y="30"
width="80"
height="50"
fill="{{ color1 }}"
rx="5"
ry="5"
id="rect1" />
<rect
x="10"
y="20"
width="40"
height="20"
fill="{{ color1 }}"
rx="5"
ry="5"
id="rect2" />
<rect
x="20"
y="40"
width="60"
height="40"
fill="{{ color2 }}"
rx="3"
ry="3"
id="rect3" />
<rect
x="30"
y="50"
width="40"
height="30"
fill="{{ color1 }}"
rx="2"
ry="2"
id="rect4" />
</svg>

Before

Width:  |  Height:  |  Size: 876 B

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Themes</title>
</head>
<body><a href="previews/alpenglow-dark.html">alpenglow-dark</a><br>
<a href="previews/alpenglow.html">alpenglow</a><br>
<a href="previews/aritim-dark.html">aritim-dark</a><br>
<a href="previews/aritim.html">aritim</a><br>
<a href="previews/autumn.html">autumn</a><br>
<a href="previews/carnation.html">carnation</a><br>
<a href="previews/catpuccin.html">catpuccin</a><br>
<a href="previews/cornflower.html">cornflower</a><br>
<a href="previews/default-dark.html">default-dark</a><br>
<a href="previews/default.html">default</a><br>
<a href="previews/ivy.html">ivy</a><br>
<a href="previews/kjoe.html">kjoe</a><br>
<a href="previews/monokai-vibrant.html">monokai-vibrant</a><br>
<a href="previews/rainbow.html">rainbow</a><br>
<a href="previews/spring.html">spring</a><br>
<a href="previews/steam.html">steam</a><br>
<a href="previews/summer.html">summer</a><br>
<a href="previews/sunflower.html">sunflower</a><br>
<a href="previews/winter.html">winter</a><br>
</body></html>

View File

@@ -1,103 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: #006400;
--color2: #008000;
--color3: #32cd32;
--color4: #004300;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor3);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-1.svg.j2";
}
.folders a {
font-weight: 800;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color2);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

View File

@@ -1,104 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: #260000;
--color2: #470000;
--color3: #191313;
--color4: #ff2727;
--bcolor1: #ebebeb;
--bcolor2: #171717;
--bcolor3: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor1);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: url("data:image/svg+xml,%3Csvg width='800px' height='800px' viewBox='0 0 1024 1024' class='icon' version='1.1' xmlns='http://www.w3.org/2000/svg' fill='%23000000'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0' /%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Cpath d='M853.333333 256H469.333333l-85.333333-85.333333H170.666667c-46.933333 0-85.333333 38.4-85.333334 85.333333v170.666667h853.333334v-85.333334c0-46.933333-38.4-85.333333-85.333334-85.333333z' fill='%238e0000' /%3E%3Cpath d='M853.333333 256H170.666667c-46.933333 0-85.333333 38.4-85.333334 85.333333v426.666667c0 46.933333 38.4 85.333333 85.333334 85.333333h682.666666c46.933333 0 85.333333-38.4 85.333334-85.333333V341.333333c0-46.933333-38.4-85.333333-85.333334-85.333333z' fill='%23FF2727' /%3E%3C/g%3E%3C/svg%3E");
}
.folders a {
font-weight: 800;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color4);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
background-color: var(--color3);
}
.tagentry label:hover {
background-color: var(--color2);
}
.tagentry .tagtoggle:hover {
background-color: var(--color2);
}
.column img {
background-color: var(--bcolor3);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor2);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

View File

@@ -1,93 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: #81f900;
--color2: #e542ff;
--color3: #ffd945;
--color4: #528bff;
--bcolor1: #f6f6f6;
--bcolor2: #2c313a;
--bcolor3: #191b20;
--bcolor4: #16171d;
--bcolor5: #0b0c0f;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
background-color: var(--bcolor3);
font-weight: 900;
}
.navbar li a {
font-weight: 900;
color: var(--bcolor1);
}
/* Change the link color on hover */
.navbar li a:hover {
background-color: var(--bcolor2);
}
.footer {
color: var(--bcolor1);
background-color: var(--bcolor2);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.foldericon {
content: "themes/icons/subfolder.svg.j2";
}
.folders a {
font-weight: 900;
color: var(--color3);
text-decoration: none;
}
.tooltiptext {
font-weight: 600;
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
.column img {
background-color: var(--bcolor5);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor4);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 800;
font-style: normal;
}
body a {
font-weight: 900;
color: var(--color2);
text-decoration: none;
}

View File

@@ -1,108 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color5: #e50000;
--color6: #ff8d00;
--color3: #ffee00;
--color4: #028121;
--color1: #004cff;
--color2: #770088;
--bcolor1: #ebebeb;
--bcolor2: #191919;
--bcolor3: #171717;
--bcolor4: #0a0a0a;
--bcolor5: #929292;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
background-color: var(--color5);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color6);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/subfolder.svg.j2";
}
.folders a {
font-weight: 800;
color: var(--bcolor3);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color4);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
.column img {
background-color: var(--bcolor5);
}
#totop:hover {
background-color: var(--color3);
}
#totop {
background-color: var(--color6);
color: var(--bcolor4);
font-weight: 800;
}
body {
color: var(--bcolor3);
background-color: var(--bcolor1);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -1,112 +0,0 @@
@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 */
}
.navbar {
font-weight: 600;
color: var(--bcolor2);
background-color: var(--color1);
font-family: "Lora", serif;
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
font-family: "Lora", serif;
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 500;
font-family: "Lora", serif;
}
.footer a {
color: var(--color4);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-3.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
font-family: "Lora", serif;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color2);
text-decoration: none;
font-family: "Lora", serif;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
background-color: var(--bcolor4);
font-family: "Lora", serif;
}
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 600;
font-family: "Lora", serif;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Lora", serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,112 +0,0 @@
@import url('https://fonts.cdnfonts.com/css/arial');
* {
--color1: #171d25;
--color2: #1a9fff;
--color3: #17191b;
--color4: #3d4450;
--bcolor1: #dcdedf;
--bcolor2: #262a32;
}
.navbar {
font-weight: 900;
color: var(--bcolor1);
background-color: var(--color1);
}
.navbar li a {
font-weight: 900;
color: var(--bcolor1);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: underline;
text-decoration-thickness: 0.3ex;
text-underline-offset: 0.5ex;
color: var(--color2)
}
.footer {
color: var(--bcolor1);
background-color: var(--color3);
font-weight: 500;
}
.footer a {
color: var(--color2);
text-decoration: none;
font-weight: 700;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg height='512' width='512' version='1.1' id='Layer_1' viewBox='0 0 327.68 327.68' xml:space='preserve' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs1' /%3E%3Cg id='icon' transform='translate(-128.08785,-19.123746)'%3E%3Cpath id='fg' style='fill:%23dcdedf;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round' d='m 428.2793,160.97461 c -78.34525,0.002 -156.69075,-0.007 -235.03585,0.0159 -6.54719,0.16827 -12.82625,4.35683 -15.37415,10.41233 -1.13922,2.74038 -1.79474,5.64883 -2.74311,8.45618 -10.27476,33.32809 -20.56379,66.65251 -30.78952,99.99526 -1.21885,4.66702 0.98496,9.97729 5.17832,12.3776 2.40372,1.49255 5.31559,1.67974 8.07056,1.58986 78.16762,-0.0305 156.33557,0.008 234.503,-0.0259 6.43644,-0.17102 12.61041,-4.22124 15.23762,-10.1162 1.2077,-2.75858 1.84495,-5.72012 2.81312,-8.56426 10.08283,-32.66775 20.13843,-65.34481 30.20361,-98.01744 0.84274,-2.37238 1.35887,-4.96865 0.67937,-7.45078 -0.98831,-4.2533 -4.6015,-7.82876 -8.96172,-8.48315 -1.24947,-0.20685 -2.51789,-0.23068 -3.78125,-0.18945 z' /%3E%3Cpath id='bg' style='fill:%23dcdedf;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;paint-order:normal' d='m 214.44922,72.089844 c -20.32611,0.01324 -40.65359,-0.03032 -60.97883,0.03325 -5.06767,0.228794 -9.72081,4.176673 -10.64873,9.186171 -0.54368,2.865585 -0.16202,5.794266 -0.28069,8.688777 -4.6e-4,27.527908 -0.008,55.056498 0.0176,82.583978 0.17186,3.22428 3.44977,5.89016 6.64757,5.28488 2.4037,-0.30447 4.32209,-2.31086 4.87898,-4.61617 3.53052,-10.60549 6.98896,-21.23707 10.60492,-31.81263 1.14174,-2.71356 4.14972,-4.41014 7.06111,-4.12697 16.80704,-0.0631 33.61433,-0.01 50.42149,-0.0279 55.72175,-0.002 111.44406,0.006 167.16547,-0.0191 5.71319,-0.19462 10.82844,-5.25566 10.91838,-11.00339 0.12602,-2.9908 -0.0352,-5.98579 0.0574,-8.97822 0.0534,-2.61272 -0.3941,-5.33067 -1.94259,-7.50013 -2.21535,-3.37352 -6.26106,-5.45808 -10.30253,-5.1988 -44.42303,-0.0315 -88.8461,0.006 -133.26914,-0.0339 -1.35699,0.0355 -2.86726,0.10531 -3.94821,-0.87625 -1.14131,-0.86056 -1.57137,-2.31551 -1.50179,-3.694889 -0.0148,-5.79966 0.0803,-11.603104 -0.0604,-17.400318 -0.41681,-5.210159 -4.80455,-9.807583 -10.02134,-10.361315 -2.37314,-0.240789 -4.76368,-0.0457 -7.14443,-0.12428 -5.89141,-0.0074 -11.78281,-0.0066 -17.67422,-0.0028 z' /%3E%3C/g%3E%3C/svg%3E%0A");
}
.folders a {
font-weight: 700;
color: var(--bcolor1);
text-decoration: none;
}
.folders figure:hover img {
content: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg height='512' width='512' version='1.1' id='Layer_1' viewBox='0 0 327.68 327.68' xml:space='preserve' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs1' /%3E%3Cg id='icon' transform='translate(-128.08785,-19.123746)'%3E%3Cpath id='fg' style='fill:%23dcdedf;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round' d='m 428.2793,160.97461 c -78.34525,0.002 -156.69075,-0.007 -235.03585,0.0159 -6.54719,0.16827 -12.82625,4.35683 -15.37415,10.41233 -1.13922,2.74038 -1.79474,5.64883 -2.74311,8.45618 -10.27476,33.32809 -20.56379,66.65251 -30.78952,99.99526 -1.21885,4.66702 0.98496,9.97729 5.17832,12.3776 2.40372,1.49255 5.31559,1.67974 8.07056,1.58986 78.16762,-0.0305 156.33557,0.008 234.503,-0.0259 6.43644,-0.17102 12.61041,-4.22124 15.23762,-10.1162 1.2077,-2.75858 1.84495,-5.72012 2.81312,-8.56426 10.08283,-32.66775 20.13843,-65.34481 30.20361,-98.01744 0.84274,-2.37238 1.35887,-4.96865 0.67937,-7.45078 -0.98831,-4.2533 -4.6015,-7.82876 -8.96172,-8.48315 -1.24947,-0.20685 -2.51789,-0.23068 -3.78125,-0.18945 z' /%3E%3Cpath id='bg' style='fill:%231a9fff;fill-opacity:1;stroke:none;stroke-width:6.4;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;paint-order:normal' d='m 214.44922,72.089844 c -20.32611,0.01324 -40.65359,-0.03032 -60.97883,0.03325 -5.06767,0.228794 -9.72081,4.176673 -10.64873,9.186171 -0.54368,2.865585 -0.16202,5.794266 -0.28069,8.688777 -4.6e-4,27.527908 -0.008,55.056498 0.0176,82.583978 0.17186,3.22428 3.44977,5.89016 6.64757,5.28488 2.4037,-0.30447 4.32209,-2.31086 4.87898,-4.61617 3.53052,-10.60549 6.98896,-21.23707 10.60492,-31.81263 1.14174,-2.71356 4.14972,-4.41014 7.06111,-4.12697 16.80704,-0.0631 33.61433,-0.01 50.42149,-0.0279 55.72175,-0.002 111.44406,0.006 167.16547,-0.0191 5.71319,-0.19462 10.82844,-5.25566 10.91838,-11.00339 0.12602,-2.9908 -0.0352,-5.98579 0.0574,-8.97822 0.0534,-2.61272 -0.3941,-5.33067 -1.94259,-7.50013 -2.21535,-3.37352 -6.26106,-5.45808 -10.30253,-5.1988 -44.42303,-0.0315 -88.8461,0.006 -133.26914,-0.0339 -1.35699,0.0355 -2.86726,0.10531 -3.94821,-0.87625 -1.14131,-0.86056 -1.57137,-2.31551 -1.50179,-3.694889 -0.0148,-5.79966 0.0803,-11.603104 -0.0604,-17.400318 -0.41681,-5.210159 -4.80455,-9.807583 -10.02134,-10.361315 -2.37314,-0.240789 -4.76368,-0.0457 -7.14443,-0.12428 -5.89141,-0.0074 -11.78281,-0.0066 -17.67422,-0.0028 z' /%3E%3C/g%3E%3C/svg%3E%0A");
}
.folders a:hover {
text-decoration: underline;
text-decoration-thickness: 0.3ex;
text-underline-offset: 0.5ex;
color: var(--color2)
}
.row a {
font-weight: 500;
color: var(--color2);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 500;
background-color: var(--color4);
}
.tagentry label:hover {
background-color: var(--color3);
}
.tagentry .tagtoggle:hover {
background-color: var(--color3);
}
.column img {
background-color: var(--color4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 700;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor2);
font-family: "Arial", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}

View File

@@ -1,114 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap");
* {
--color1: #FFD700; /* Gold */
--color2: #00BFFF; /* DeepSkyBlue */
--color3: #32CD32; /* LimeGreen */
--color4: #FFA500; /* Orange */
--bcolor1: #FFFFFF; /* White */
--bcolor2: #1E1E1E; /* DarkGrey */
--bcolor3: #F0F8FF; /* AliceBlue */
--bcolor4: #E0FFFF; /* LightCyan */
}
.navbar {
font-weight: 700;
color: var(--bcolor2);
background-color: var(--color1);
font-family: "Roboto", sans-serif;
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
font-family: "Roboto", sans-serif;
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor1);
background-color: var(--color3);
font-weight: 500;
font-family: "Roboto", sans-serif;
}
.footer a {
color: var(--color4);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-3.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
font-family: "Roboto", sans-serif;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color2);
text-decoration: none;
font-family: "Roboto", sans-serif;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
color: var(--bcolor1);
background-color: var(--bcolor2);
font-family: "Roboto", sans-serif;
}
.tagentry label:hover {
background-color: var(--bcolor3);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor3);
color: var(--bcolor2);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 600;
font-family: "Roboto", sans-serif;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Roboto", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

View File

@@ -1,106 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
* {
--color1: #ffb000;
--color2: #ffd700;
--color3: #ffe135;
--color4: #ce8c00;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor2);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor2);
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 700;
}
.footer a {
color: var(--color4);
text-decoration: none;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-1.svg.j2";
}
.folders a {
font-weight: 800;
color: var(--bcolor1);
text-decoration: none;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 800;
color: var(--color1);
text-decoration: none;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 600;
color: var(--bcolor3);
background-color: var(--bcolor2);
}
.tagentry label:hover {
background-color: var(--bcolor4);
}
.tagentry .tagtoggle:hover {
background-color: var(--bcolor4);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 800;
}
body {
color: var(--bcolor1);
background-color: var(--bcolor3);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}

View File

@@ -1,121 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap");
* {
--color1: #00CED1;
/* DarkTurquoise */
--color2: #4682B4;
/* SteelBlue */
--color3: #B0C4DE;
/* LightSteelBlue */
--color4: #5F9EA0;
/* CadetBlue */
--bcolor1: #FFFFFF;
/* White */
--bcolor2: #2F4F4F;
/* DarkSlateGray */
--bcolor3: #E0E0E0;
/* LightGray */
--bcolor4: #D3D3D3;
/* LightGray */
}
.navbar {
font-weight: 600;
color: var(--bcolor2);
background-color: var(--color1);
font-family: "Montserrat", sans-serif;
}
.navbar li a {
font-weight: 500;
color: var(--bcolor2);
font-family: "Montserrat", sans-serif;
}
/* Change the link color on hover */
.navbar li a:hover {
text-decoration: none;
background-color: var(--color2);
}
.footer {
color: var(--bcolor2);
background-color: var(--color3);
font-weight: 500;
font-family: "Montserrat", sans-serif;
}
.footer a {
color: var(--color2);
text-decoration: none;
font-weight: 400;
}
.footer a:hover {
text-decoration: none;
}
.foldericon {
content: "themes/icons/folder-3.svg.j2";
}
.folders a {
font-weight: 600;
color: var(--bcolor2);
text-decoration: none;
font-family: "Montserrat", sans-serif;
}
.folders a:hover {
text-decoration: none;
}
.row a {
font-weight: 500;
color: var(--color2);
text-decoration: none;
font-family: "Montserrat", sans-serif;
}
.row a:hover {
text-decoration: underline;
}
.tooltiptext {
font-weight: 400;
color: var(--bcolor3);
background-color: var(--bcolor2);
font-family: "Montserrat", sans-serif;
}
.tagentry label:hover {
background-color: var(--color2);
}
.tagentry .tagtoggle:hover {
background-color: var(--color2);
}
.column img {
background-color: var(--bcolor4);
}
#totop:hover {
background-color: var(--color2);
}
#totop {
background-color: var(--color1);
color: var(--bcolor1);
font-weight: 600;
font-family: "Montserrat", sans-serif;
}
body {
color: var(--bcolor2);
background-color: var(--bcolor3);
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}