-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor script and add support for link icons
- Loading branch information
1 parent
d08892f
commit 8f7755a
Showing
5 changed files
with
208 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,139 +1,219 @@ | ||
import tomllib | ||
|
||
from dataclasses import dataclass, field | ||
from typing import List, Optional | ||
from tinyhtml import html, h, frag, raw | ||
|
||
|
||
with open("data.toml", "rb") as f: | ||
data = tomllib.load(f) | ||
sections = frag( | ||
h("div", klass="section")( | ||
h("hgroup")( | ||
h("h3")(section.get("title")), | ||
h("p")(section.get("description")), | ||
), | ||
@dataclass | ||
class Item: | ||
title: str | ||
description: Optional[str] = None | ||
url: Optional[str] = None | ||
icon: Optional[str] = None | ||
embed_url: Optional[str] = None | ||
embed_height: str = "315" | ||
|
||
|
||
@dataclass | ||
class Section: | ||
title: str | ||
description: Optional[str] = None | ||
icon: Optional[str] = None | ||
icon_size: str = "24px" | ||
direction: str = "column" | ||
item_style: str = "outline" | ||
items: List[Item] = field(default_factory=list) | ||
|
||
|
||
@dataclass | ||
class Data: | ||
name: str | ||
base_url: str | ||
sections: List[Section] = field(default_factory=list) | ||
description: Optional[str] = None | ||
keywords: Optional[str] = None | ||
image: Optional[str] = None | ||
theme: str = "dark" | ||
primary_color: str = "#546e7a" | ||
text_align: str = "center" | ||
gtag_id: Optional[str] = None | ||
|
||
|
||
def load_data(file_path): | ||
with open(file_path, "rb") as f: | ||
raw_data = tomllib.load(f) | ||
|
||
return Data( | ||
name=raw_data["name"], | ||
description=raw_data.get("description"), | ||
keywords=raw_data.get("keywords"), | ||
base_url=raw_data["base_url"], | ||
image=raw_data.get("image"), | ||
theme=raw_data.get("theme", "dark"), | ||
primary_color=raw_data.get("primary_color", "#546e7a"), | ||
text_align=raw_data.get("text_align", "center"), | ||
gtag_id=raw_data.get("gtag_id"), | ||
sections=[ | ||
Section( | ||
title=section.get("title"), | ||
description=section.get("description"), | ||
icon=section.get("icon"), | ||
icon_size=section.get("icon_size", "24px"), | ||
direction=section.get("direction", "column"), | ||
item_style=section.get("item_style", "outline"), | ||
items=[ | ||
Item( | ||
title=item.get("title"), | ||
description=item.get("description"), | ||
url=item.get("url"), | ||
icon=item.get("icon"), | ||
embed_url=item.get("embed_url"), | ||
embed_height=item.get("embed_height", "315"), | ||
) | ||
for item in section.get("items", []) | ||
], | ||
) | ||
for section in raw_data.get("sections", []) | ||
], | ||
) | ||
|
||
|
||
def create_section(section: Section): | ||
items = frag( | ||
h( | ||
"div", | ||
klass="item", | ||
style=f"width: {'100%' if section.direction == 'column' else 'unset'}", | ||
)( | ||
h( | ||
"div", | ||
klass="items", | ||
style=f"flex-direction: {section.get('direction', 'column')}", | ||
"a", | ||
role="button", | ||
klass=f"{'outline' if section.item_style == 'outline' else ''}", | ||
href=item.url, | ||
target="_blank", | ||
)( | ||
h( | ||
"div", | ||
klass="item", | ||
style=f"width: {'100%' if section.get('direction', 'column') == 'column' else 'unset'}", | ||
)( | ||
h( | ||
"a", | ||
role="button", | ||
klass=f"{'outline' if section.get('item_style', 'outline') == 'outline' else ''}", | ||
href=item.get("url"), | ||
target="_blank", | ||
)( | ||
h("hgroup")( | ||
h("h4")(item.get("title")), h("h5")(item.get("description")) | ||
), | ||
), | ||
"img", | ||
klass="icon", | ||
src=item.icon, | ||
alt=item.title, | ||
style=f"width: {section.icon_size};", | ||
) | ||
for item in section["items"] | ||
), | ||
if item.icon | ||
else None, | ||
h("hgroup")(h("h4")(item.title), h("h5")(item.description)), | ||
) | ||
if item.url | ||
else raw(f""" | ||
<iframe | ||
src="{item.embed_url}" | ||
height="{item.embed_height}" | ||
frameborder="0" | ||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" | ||
allowfullscreen="true" | ||
> | ||
</iframe> | ||
""") | ||
if item.embed_url | ||
else None | ||
) | ||
for section in data["sections"] | ||
for item in section.items | ||
) | ||
|
||
return h("div", klass="section")( | ||
h("hgroup")( | ||
h("h3")(section.title), | ||
h("p")(section.description), | ||
), | ||
h("div", klass="items", style=f"flex-direction: {section.direction}")(items), | ||
) | ||
|
||
meta_tags = frag( | ||
h("title")(data.get("name")), | ||
h("meta", name="description", content=data.get("description")), | ||
h("meta", name="keywords", content=data.get("keywords")), | ||
|
||
def create_meta_tags(data: Data): | ||
return frag( | ||
h("title")(data.name), | ||
h("meta", name="description", content=data.description), | ||
h("meta", name="keywords", content=data.keywords), | ||
h("meta", name="viewport", content="width=device-width, initial-scale=1"), | ||
h("meta", charset="utf-8"), | ||
# OG | ||
h("meta", property="og:title", content=data.get("name")), | ||
h("meta", property="og:description", content=data.get("description")), | ||
h( | ||
"meta", | ||
property="og:image", | ||
content=f"{data.get('base_url')}/img/{data.get('image')}", | ||
), | ||
# Twitter / X | ||
h("meta", name="twitter:title", content=data.get("name")), | ||
h("meta", name="twitter:description", content=data.get("description")), | ||
h( | ||
"meta", | ||
name="twitter:image", | ||
content=f"{data.get('base_url')}/img/{data.get('image')}", | ||
), | ||
h("meta", property="og:title", content=data.name), | ||
h("meta", property="og:description", content=data.description), | ||
h("meta", property="og:image", content=f"{data.base_url}/img/{data.image}"), | ||
h("meta", name="twitter:title", content=data.name), | ||
h("meta", name="twitter:description", content=data.description), | ||
h("meta", name="twitter:image", content=f"{data.base_url}/img/{data.image}"), | ||
h("meta", name="twitter:card", content="summary_large_image"), | ||
) | ||
|
||
head = frag( | ||
h("head")( | ||
meta_tags, | ||
h("link", rel="stylesheet", href="css/pico.min.css"), | ||
h("link", rel="stylesheet", href="css/style.css"), | ||
h("style", rel="stylesheet")( | ||
f""" | ||
[data-theme="dark"], [data-theme="light"] {{ | ||
--primary: {data.get("primary_color", "#546e7a")} !important; | ||
}} | ||
* {{ | ||
text-align: {data.get("text_align", "center")}; | ||
}} | ||
""" | ||
), | ||
raw( | ||
f""" | ||
<!-- Google tag (gtag.js) --> | ||
<script async src="https://www.googletagmanager.com/gtag/js?id={data.get("gtag_id")}"></script> | ||
<script> | ||
window.dataLayer = window.dataLayer || []; | ||
function gtag(){{dataLayer.push(arguments);}} | ||
gtag('js', new Date()); | ||
gtag('config', '{data.get("gtag_id")}'); | ||
</script> | ||
""" | ||
) | ||
if data.get("gtag_id") | ||
else None, | ||
|
||
def create_head(data: Data): | ||
return h("head")( | ||
create_meta_tags(data), | ||
h("link", rel="stylesheet", href="css/pico.min.css"), | ||
h("link", rel="stylesheet", href="css/style.css"), | ||
h("style", rel="stylesheet")( | ||
f""" | ||
[data-theme="dark"], [data-theme="light"] {{ | ||
--primary: {data.primary_color} !important; | ||
}} | ||
* {{ | ||
text-align: {data.text_align}; | ||
}} | ||
""" | ||
), | ||
raw( | ||
f""" | ||
<script async src="https://www.googletagmanager.com/gtag/js?id={data.gtag_id}"></script> | ||
<script> | ||
window.dataLayer = window.dataLayer || []; | ||
function gtag(){{dataLayer.push(arguments);}} | ||
gtag('js', new Date()); | ||
gtag('config', '{data.gtag_id}'); | ||
</script> | ||
""" | ||
) | ||
if data.gtag_id | ||
else None, | ||
) | ||
|
||
header = frag( | ||
h("header", klass="container")( | ||
h("hgroup")( | ||
h( | ||
"img", | ||
klass="avatar", | ||
src=f"img/{data.get('image')}", | ||
alt="avatar", | ||
), | ||
h("h1")(data.get("name")), | ||
h("p")(data.get("description")) if data.get("description") else None, | ||
), | ||
|
||
def create_header(data: Data): | ||
return h("header", klass="container")( | ||
h("hgroup")( | ||
h("img", klass="avatar", src=f"img/{data.image}", alt="avatar"), | ||
h("h1")(data.name), | ||
h("p")(data.description) if data.description else None, | ||
) | ||
) | ||
|
||
footer = frag( | ||
h("footer", klass="container")( | ||
h("small")("Generated with "), | ||
h( | ||
"a", | ||
klass="", | ||
href="https://github.com/thevahidal/jake/", | ||
target="_blank", | ||
)("Jake"), | ||
|
||
def create_footer(): | ||
return h("footer", klass="container")( | ||
h("small")("Generated with "), | ||
h("a", klass="", href="https://github.com/thevahidal/jake/", target="_blank")( | ||
"Jake" | ||
), | ||
) | ||
|
||
output = html(lang="en", data_theme=data.get("theme", "dark"))( | ||
head, | ||
|
||
def generate_html(data: Data): | ||
sections = frag(create_section(section) for section in data.sections) | ||
return html(lang="en", data_theme=data.theme)( | ||
create_head(data), | ||
h("body")( | ||
header, | ||
h("main", klass="container")( | ||
sections, | ||
), | ||
footer, | ||
create_header(data), | ||
h("main", klass="container")(sections), | ||
create_footer(), | ||
), | ||
).render() | ||
|
||
|
||
def main(): | ||
data = load_data("data.toml") | ||
output = generate_html(data) | ||
with open("dist/index.html", "w") as f: | ||
f.write(output) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |