diff --git a/src/zona/config.py b/src/zona/config.py index c66ee58..db0d5fe 100644 --- a/src/zona/config.py +++ b/src/zona/config.py @@ -8,7 +8,7 @@ def find_config(start: Path | None = None) -> Path | None: current = (start or Path.cwd()).resolve() for parent in [current, *current.parents]: - candidate = parent / "zona.yml" + candidate = parent / "config.yml" if candidate.is_file(): return candidate return None diff --git a/src/zona/data/content/static/style.css b/src/zona/data/content/static/style.css new file mode 100644 index 0000000..d6d538e --- /dev/null +++ b/src/zona/data/content/static/style.css @@ -0,0 +1,236 @@ +:root { + --main-text-color: #b4b4b4; + --main-bg-color: #121212; + --main-link-color: #df6464; + --main-heading-color: #df6464; + --main-bullet-color: #d87c4a; + --main-transparent: rgba(255, 255, 255, 0.15); + --main-small-text-color: rgba(255, 255, 255, 0.45); +} + +body { + line-height: 1.6; + font-size: 18px; + font-family: sans-serif; + background: var(--main-bg-color); + color: var(--main-text-color); + padding-left: calc(100vw - 100%); +} + +/* h1, */ +h2, +h3, +h4, +h5, +h6 { + color: var(--main-heading-color); +} + +h1 { + margin-block-start: 0.67rem; + margin-block-end: 0.67rem; + font-size: 2rem; + font-weight: bold; +} + +article h1:first-of-type { + margin-block-start: 1.67rem; +} + +h2 { + margin-block-start: 0.83rem; + margin-block-end: 0.83rem; + font-size: 1.5rem; + font-weight: bold; +} + +h3 { + margin-block-start: 1rem; + margin-block-end: 1rem; + font-size: 1.17em; + font-weight: bold; +} + +h4 { + margin-block-start: 1.33rem; + margin-block-end: 1.33rem; + font-size: 1rem; + font-weight: bold; +} + +article h1+h4:first-of-type { + margin-block-start: 0rem; +} + +h5 { + margin-block-start: 1.67rem; + margin-block-end: 1.67rem; + font-size: 0.83rem; + font-weight: bold; +} + +h6 { + margin-block-start: 2.33rem; + margin-block-end: 2.33rem; + font-size: 0.67rem; + font-weight: bold; +} + +ul { + list-style-type: disc; + /* or any other list style */ +} + +li::marker { + color: var(--main-bullet-color); + /* Change this to your desired color */ +} + +a { + color: var(--main-link-color); +} + +a:hover { + background: var(--main-transparent); +} + +img { + display: block; + margin-left: auto; + margin-right: auto; + width: auto; + height: auto; +} + +blockquote { + color: var(--main-small-text-color); + border-left: 3px solid var(--main-transparent); + padding: 0 1rem; + margin-left: 0; + margin-right: 0; +} + +hr { + border: none; + height: 1px; + background: var(--main-small-text-color); +} + +code { + background: var(--main-transparent); + border-radius: 0.1875rem; + /* padding: .0625rem .1875rem; */ + /* margin: 0 .1875rem; */ +} + +code, +pre { + white-space: pre; + word-wrap: break-word; + overflow-wrap: break-word; + font-family: 'Fira Code', 'Consolas', 'Courier New', monospace; + font-size: 0.95em; +} + +pre { + background-color: #1d1d1d; + color: #d5d5d5; + padding: 1em; + border-radius: 5px; + line-height: 1.5; + overflow-x: auto; +} + +code { + background-color: #1d1d1d; + color: #d5d5d5; + padding: 0.2em 0.4em; + border-radius: 3px; +} + + +small { + font-size: 0.95rem; + color: var(--main-small-text-color); +} + +small a { + color: inherit; + /* Inherit the color of the surrounding text */ + text-decoration: underline; + /* Optional: Keep the underline to indicate a link */ +} + +.title-container { + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} + +.title-container h1 { + margin: 0; +} + +.image-container { + text-align: center; + margin: 20px 0; + /* Optional: add some spacing around the image container */ +} + +.image-container img { + /* max-width: 308px; */ + max-height: 308px; +} + +.image-container small { + display: block; + /* Ensure the caption is on a new line */ + margin-top: 5px; + /* Optional: adjust spacing between image and caption */ +} + +.image-container small a { + color: inherit; + /* Ensure the link color matches the small text */ + text-decoration: underline; + /* Optional: underline to indicate a link */ +} + +#header ul { + list-style-type: none; + padding-left: 0; +} + +#header li { + display: inline; + font-size: 1.2rem; + margin-right: 1.2rem; +} + +#container { + margin: 2.5rem auto; + width: 90%; + max-width: 60ch; +} + +#postlistdiv ul { + list-style-type: none; + padding-left: 0; +} + +.moreposts { + font-size: 0.95rem; + padding-left: 0.5rem; +} + +#nextprev { + text-align: center; + margin-top: 1.4rem; + font-size: 0.95rem; +} + +#footer { + color: var(--main-small-text-color); +} + diff --git a/src/zona/layout.py b/src/zona/layout.py index 9ee3b00..77a97e3 100644 --- a/src/zona/layout.py +++ b/src/zona/layout.py @@ -1,4 +1,6 @@ from pathlib import Path +from rich import print +import typer from dataclasses import dataclass, asdict from zona.config import ZonaConfig, find_config from zona import util @@ -24,7 +26,9 @@ class Layout: ) if validate: if not layout.content.is_dir(): - raise FileNotFoundError("Missing required content directory!") + raise FileNotFoundError( + "Missing required content directory!" + ) if not layout.templates.is_dir(): # use the included defaults layout.templates = util.get_resource_dir("templates") @@ -53,21 +57,29 @@ def initialize_site(root: Path | None = None): root = root.absolute().resolve() config = find_config(root) if config is not None: - raise FileExistsError(f"Config file already exists at {config}") + ans = typer.confirm( + text=( + f"A config file already exists at {config}.\n" + f"Delete it and restore defaults?" + ) + ) + if ans: + config.unlink() # create requires layout layout = Layout.from_input(root=root, validate=False) # load template resources templates = util.get_resources("templates") + static = util.get_resources("content") for dir, resources in [ (layout.root, None), - (layout.content, None), + (layout.content, static), (layout.templates, templates), ]: if not dir.is_dir(): dir.mkdir() if resources is not None: for r in resources: - Path(r.name).write_text(r.contents) + (root / Path(r.name)).write_text(r.contents) config_path = layout.root / "config.yml" config = ZonaConfig() diff --git a/src/zona/util.py b/src/zona/util.py index 823180f..c3caaed 100644 --- a/src/zona/util.py +++ b/src/zona/util.py @@ -1,3 +1,4 @@ +from importlib.resources.abc import Traversable from typing import NamedTuple from rich import print from importlib import resources @@ -15,13 +16,21 @@ class ZonaResource(NamedTuple): def get_resources(subdir: str) -> list[ZonaResource]: """Load the packaged resources in data/subdir""" out: list[ZonaResource] = [] - for resource in ( - resources.files("zona").joinpath(f"data/{subdir}").iterdir() - ): - out.append( - ZonaResource(f"{subdir}/{resource.name}", resource.read_text()) - ) - print(out) + base = resources.files("zona").joinpath("data", subdir) + + def walk(trav: Traversable, prefix: str = ""): + for item in trav.iterdir(): + path = f"{prefix}{item.name}" + if item.is_dir(): + walk(item, prefix=f"{path}/") + else: + out.append( + ZonaResource( + name=f"{subdir}/{path}", contents=item.read_text() + ) + ) + + walk(base) return out @@ -58,4 +67,6 @@ def normalize_url(url: str) -> str: def should_ignore(path: Path, patterns: list[str], base: Path) -> bool: rel_path = path.relative_to(base) - return any(fnmatch.fnmatch(str(rel_path), pattern) for pattern in patterns) + return any( + fnmatch.fnmatch(str(rel_path), pattern) for pattern in patterns + )