From 310b31d673636f0ef3f4268cf8ed5933c1e32f7d Mon Sep 17 00:00:00 2001 From: VAN BOSSUYT Nicolas Date: Sun, 8 Sep 2024 13:19:59 +0200 Subject: [PATCH] Initial release. --- .github/workflows/publish-site.yml | 55 ++++++++ .gitignore | 3 + license.md | 21 ++++ meta/plugins/__init__.py | 195 +++++++++++++++++++++++++++++ meta/plugins/default.css | 159 +++++++++++++++++++++++ meta/plugins/requirements.txt | 1 + meta/site/blog/index.md | 1 + meta/site/blog/initial-release.md | 1 + meta/site/cat.jpg | Bin 0 -> 30364 bytes meta/site/index.md | 3 + meta/site/site.json | 7 ++ project.json | 6 + readme.md | 26 ++++ 13 files changed, 478 insertions(+) create mode 100644 .github/workflows/publish-site.yml create mode 100644 .gitignore create mode 100644 license.md create mode 100644 meta/plugins/__init__.py create mode 100644 meta/plugins/default.css create mode 100644 meta/plugins/requirements.txt create mode 100644 meta/site/blog/index.md create mode 100644 meta/site/blog/initial-release.md create mode 100644 meta/site/cat.jpg create mode 100644 meta/site/index.md create mode 100644 meta/site/site.json create mode 100644 project.json create mode 100644 readme.md diff --git a/.github/workflows/publish-site.yml b/.github/workflows/publish-site.yml new file mode 100644 index 0000000..6d3a8bf --- /dev/null +++ b/.github/workflows/publish-site.yml @@ -0,0 +1,55 @@ +name: Docs + +on: + push: + branches: ["main"] + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install CuteKit + run: | + pip install git+https://github.com/cute-engineering/cutekit.git@0.7.4 + pip install -r meta/plugins/requirements.txt + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v4 + + - name: Build with cat + run: | + python -m cutekit cat build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: .cutekit/build/site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c30db7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.cutekit +.mypy_cache +__pycache__ diff --git a/license.md b/license.md new file mode 100644 index 0000000..00040ae --- /dev/null +++ b/license.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Cute Engineering + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/meta/plugins/__init__.py b/meta/plugins/__init__.py new file mode 100644 index 0000000..4fdcb8d --- /dev/null +++ b/meta/plugins/__init__.py @@ -0,0 +1,195 @@ +from cutekit import ensure + +ensure((0, 7, 0)) + +import http.server +import os +from pathlib import Path +import markdown +import dataclasses as dt +from dataclasses_json import DataClassJsonMixin + +from cutekit import cli, const, shell, jexpr + +CAT = "ᓚ₍ ^. .^₎" +DEFAULT_STYLE_PATH = __file__.replace("__init__.py", "default.css") + +SITE_DIR = os.path.join(const.META_DIR, "site") +SITE_BUILD_DIR = os.path.join(const.BUILD_DIR, "site") + + +# MARK: Model ------------------------------------------------------------------ + + +def readFile(path: str) -> str: + with open(path, "r") as f: + return f.read() + + +def writeFile(path: str, content: str): + with open(path, "w") as f: + f.write(content) + + +def fixupLinks(html: str, path: str) -> str: + rootPath = os.path.relpath(".", os.path.dirname(path)) + return ( + html.replace('.md"', '.html"') + .replace(".md#", ".html#") + .replace('"/', f'"{rootPath}/') + ) + + +@dt.dataclass +class Site(DataClassJsonMixin): + title: str = dt.field() + header: str | None = dt.field(default=None) + favicon: str = dt.field(default="🐱") + navbar: str = dt.field(default="") + footer: str = dt.field(default="") + + path: str = dt.field(default="") + + @staticmethod + def load() -> "Site": + siteFile = os.path.join(SITE_DIR, "site.json") + siteJson = jexpr.include(Path(siteFile)) + site = Site.from_dict(siteJson) + site.path = siteFile + return site + + def renderFavicon(self) -> str: + svg = f"{self.favicon}" + urlEscape = str.maketrans({"#": "%23", "<": "%3C", ">": "%3E"}) + svgEscaped = svg.translate(urlEscape) + return f"data:image/svg+xml,{svgEscaped}" + + def renderHeader(self) -> str: + return f'

{self.header or self.title}

' + + def renderAll(self, out: str): + styleFile = os.path.join(SITE_DIR, "style.css") + if not os.path.exists(styleFile): + styleFile = DEFAULT_STYLE_PATH + + style = readFile(styleFile) + + md = markdown.Markdown(extensions=["meta"]) + files = shell.find(SITE_DIR) + for file in files: + if file.endswith(".json"): + continue + + relDir = file.replace(SITE_DIR + "/", "") + print(f"Processing {relDir}") + output = os.path.join(out, relDir) + if not file.endswith(".md"): + shell.mkdir(os.path.dirname(output)) + shell.cp(file, out) + continue + + output = output.replace(".md", ".html") + + print(f"Rendering {file} -> {output}") + + shell.mkdir(os.path.dirname(output)) + + mdContent = readFile(path=file) + htmlContent = md.convert(mdContent) + + title = md.Meta.get("title", [""])[0] + if title: + title = f"{title} - {self.title}" + else: + title = self.title + + htmlContent = f""" + + + + + + {title} + + + + +
+ {self.renderHeader()} + +
+
+ {htmlContent} +
+ + + +""" + + writeFile(output, fixupLinks(htmlContent, relDir)) + + +# MARK: Public interface ------------------------------------------------------- + + +@cli.command(None, "cat", "Tiny site generator") +def _(): + pass + + +@cli.command("b", "cat/build", "Build the site") +def _() -> None: + shell.rmrf(SITE_BUILD_DIR) + shell.mkdir(SITE_BUILD_DIR) + site = Site.load() + site.renderAll(SITE_BUILD_DIR) + + print(f"{CAT} Site built at {SITE_BUILD_DIR}") + + +@cli.command("c", "cat/clean", "Clean the site") +def _(): + shell.rmrf(SITE_BUILD_DIR) + + print(f"{CAT} Site cleaned") + + +@cli.command("s", "cat/serve", "Serve the site") +def _(): + shell.rmrf(SITE_BUILD_DIR) + shell.mkdir(SITE_BUILD_DIR) + site = Site.load() + site.renderAll(SITE_BUILD_DIR) + + os.chdir(SITE_BUILD_DIR) + + print(f"{CAT} Serving site") + shell.exec("python3", "-m", "http.server") + + +@cli.command("e", "cat/init", "Initialize the site") +def _(): + shell.mkdir(SITE_DIR) + writeFile( + os.path.join(SITE_DIR, "site.json"), + """ +{ + "favicon": "🐱", + "title": "Cat", + "header": "ᓚ₍ ^. .^₎", + "navbar": "[Home](/)", + "footer": "Built with [ᓚ₍ ^. .^₎](https://github.com/cute-engineering/cat)" +} + """, + ) + + writeFile( + os.path.join(SITE_DIR, "index.md"), + """ +This is the home page of the site. You can edit this file to change the content of the home page. +""", + ) + + print(f"{CAT} Site initialized at {SITE_DIR}") diff --git a/meta/plugins/default.css b/meta/plugins/default.css new file mode 100644 index 0000000..ec6a786 --- /dev/null +++ b/meta/plugins/default.css @@ -0,0 +1,159 @@ +:root { + --width: 720px; + --font-main: Verdana, sans-serif; + --font-secondary: Verdana, sans-serif; + --font-scale: 1em; + --background-color: #fff; + --heading-color: #222; + --text-color: #444; + --link-color: #3273dc; + --visited-color: #8b6fcb; + --code-background-color: #f2f2f2; + --code-color: #222; + --blockquote-color: #222; +} + +@media (prefers-color-scheme: dark) { + :root { + --background-color: #01242e; + --heading-color: #eee; + --text-color: #ddd; + --link-color: #8cc2dd; + --visited-color: #8b6fcb; + --code-background-color: #000; + --code-color: #ddd; + --blockquote-color: #ccc; + } +} + +body { + font-family: var(--font-secondary); + font-size: var(--font-scale); + margin: auto; + padding: 20px; + max-width: var(--width); + text-align: left; + background-color: var(--background-color); + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: var(--text-color); +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-main); + color: var(--heading-color); +} + +a { + color: var(--link-color); + cursor: pointer; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +nav a { + margin-right: 8px; +} + +strong, +b { + color: var(--heading-color); +} + +button { + margin: 0; + cursor: pointer; +} + +time { + font-family: monospace; + font-style: normal; + font-size: 15px; +} + +main { + line-height: 1.6; +} + +table { + width: 100%; +} + +hr { + border: 0; + border-top: 1px dashed; +} + +img { + max-width: 100%; +} + +code { + font-family: monospace; + padding: 2px; + background-color: var(--code-background-color); + color: var(--code-color); + border-radius: 3px; +} + +blockquote { + border-left: 1px solid #999; + color: var(--code-color); + padding-left: 20px; + font-style: italic; +} + +footer { + padding: 25px 0; + text-align: center; +} + +.title:hover { + text-decoration: none; +} + +.title h1 { + font-size: 1.5em; +} + +.inline { + width: auto !important; +} + +.highlight, +.code { + padding: 1px 15px; + background-color: var(--code-background-color); + color: var(--code-color); + border-radius: 3px; + margin-block-start: 1em; + margin-block-end: 1em; + overflow-x: auto; +} + +/* blog post list */ +ul.blog-posts { + list-style-type: none; + padding: unset; +} + +ul.blog-posts li { + display: flex; +} + +ul.blog-posts li span { + flex: 0 0 130px; +} + +ul.blog-posts li a:visited { + color: var(--visited-color); +} diff --git a/meta/plugins/requirements.txt b/meta/plugins/requirements.txt new file mode 100644 index 0000000..9b2aa88 --- /dev/null +++ b/meta/plugins/requirements.txt @@ -0,0 +1 @@ +Markdown~=3.7 diff --git a/meta/site/blog/index.md b/meta/site/blog/index.md new file mode 100644 index 0000000..67b31bc --- /dev/null +++ b/meta/site/blog/index.md @@ -0,0 +1 @@ +- [Initial Release](initial-release.md) diff --git a/meta/site/blog/initial-release.md b/meta/site/blog/initial-release.md new file mode 100644 index 0000000..08ca33e --- /dev/null +++ b/meta/site/blog/initial-release.md @@ -0,0 +1 @@ +It's cat first release 🎉 diff --git a/meta/site/cat.jpg b/meta/site/cat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d97f66c24a7124cc59fa96cc8b51c453dd414a9 GIT binary patch literal 30364 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 a@r4l`6@<@?K>gz}1bv`D$g@cCKmXZV&<6ql literal 0 HcmV?d00001 diff --git a/meta/site/index.md b/meta/site/index.md new file mode 100644 index 0000000..ca5a532 --- /dev/null +++ b/meta/site/index.md @@ -0,0 +1,3 @@ +**Cat** is a tiny static site generator for CuteKit. + +![Cat writting the blog](cat.jpg) diff --git a/meta/site/site.json b/meta/site/site.json new file mode 100644 index 0000000..10bd41b --- /dev/null +++ b/meta/site/site.json @@ -0,0 +1,7 @@ +{ + "favicon": "🐱", + "title": "Cat", + "header": "ᓚ₍ ^. .^₎", + "navbar": "[Home](/) [Blog](/blog) [GitHub](https://github.com/cute-engineering/cat)", + "footer": "© 2024 Cute Engineering" +} diff --git a/project.json b/project.json new file mode 100644 index 0000000..7566423 --- /dev/null +++ b/project.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.project.v1", + "id": "cute-engineeering/cat", + "type": "project", + "description": "A tiny static site generator for CuteKit projects." +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..28604de --- /dev/null +++ b/readme.md @@ -0,0 +1,26 @@ +# 🐱 Cat + +A tiny static site generator for CuteKit projects. + +## Features + + - Nothing fancy + - purrs like a kitten + - Easy to use with CuteKit + +## Installation + +Just add the following piece of json to your `project.json` file: + +```json +{ + "extern": { + "cute-engineering/cat": { + "git": "https://github.com/cute-engineering/cat.git", + "tag": "v0.7.0" + }, + } +} +``` + +Then run `cutekit model init` to install the package and `cutekit cat init` to initialize the site.