diff --git a/devenv.nix b/devenv.nix index c46ffe5..85e5426 100644 --- a/devenv.nix +++ b/devenv.nix @@ -18,9 +18,15 @@ sync.allExtras = true; }; }; + typst = { + enable = true; + }; }; packages = [ + pkgs.google-fonts + pkgs.hanken-grotesk + pkgs.typstyle pkgs.uv ]; diff --git a/pyproject.toml b/pyproject.toml index 185fa2f..ec68b5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,8 +18,10 @@ dependencies = [ "cssselect==1.3.0", "cssutils==2.11.1", "discord.py==2.7.1", + "fastapi[standard]>=0.136.1", "html5lib==1.1", "idna==3.10", + "immichpy>=4.1.3", "Jinja2==3.1.6", "lxml==6.0.0", "MarkupSafe==3.0.2", @@ -27,10 +29,12 @@ dependencies = [ "premailer==3.10.0", "python-dateutil==2.9.0.post0", "python-dotenv==1.1.1", + "pytz==2026.1.post1", "requests==2.32.4", "six==1.17.0", "soupsieve==2.7", "typing_extensions==4.14.0", + "typst>=0.14.8", "urllib3==2.5.0", "webencodings==0.5.1", ] diff --git a/src/kronos-ui/__init__.py b/src/kronos-ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/kronos-ui/main.py b/src/kronos-ui/main.py new file mode 100644 index 0000000..259ae48 --- /dev/null +++ b/src/kronos-ui/main.py @@ -0,0 +1,74 @@ +from datetime import datetime +import json +import os +import shutil + +from fastapi import FastAPI, File, UploadFile, Form +from fastapi.responses import HTMLResponse, Response +from fastapi.staticfiles import StaticFiles +import typst + +from kronos.mobilizon import get_raw_events + +app = FastAPI() + +app.mount("/static", StaticFiles(directory="src/kronos-ui/static/"), name="static") + + +@app.get("/", response_class=HTMLResponse) +async def root(): + with open("src/kronos-ui/static/index.html", "rb") as f: + index = f.read() + return index + + +@app.get("/calendar", responses={200: {"content": {"image/png": {}}}}, response_class=Response) +async def calendar(): + get_raw_events() + + png_bytes = typst.compile("src/typst/calendar.typ", format="png") + + return Response(content=png_bytes, media_type="image/png") + + +@app.post("/event_card", responses={200: {"content": {"image/png": {}}}}, response_class=Response) +async def event_card( # noqa: PLR0913 + title: str = Form(""), + description: str = Form(""), + begins=Form(...), + ends=Form(...), + speaker: str = Form(""), + picture: UploadFile = File(...), +): + pic_path = os.path.join("src", "typst", "assets", "tmp", f"{datetime.now()}.jpg") + fp = open(pic_path, "wb") + if picture and picture.size > 0: + shutil.copyfileobj(picture.file, fp) + else: + with open(os.path.join("src", "typst", "assets", "photo.jpg"), "rb") as placeholder: + shutil.copyfileobj(placeholder, fp) + + # TODO: pack this in a method + events = [ + { + "title": title, + "beginsOn": begins, + "endsOn": ends, + "description": description, + "physicalAddress": None, + "picture": os.path.relpath(pic_path, start="src/typst"), + "url": None, + "txt_description": description, + "txt_date": f"{begins.split('T')[0]} {begins.split('T')[1]}-{ends.split('T')[1]}", + # "txt_date": "2026-04-29 18:00-19:00", + "speaker": speaker, + } + ] + sys_inputs = {"events": json.dumps(events)} + print(sys_inputs) + # FIXME: remove hardcoded paths + png_bytes = typst.compile("src/typst/event.typ", format="png", sys_inputs=sys_inputs) + + fp.close() + + return Response(content=png_bytes, media_type="image/png") diff --git a/src/kronos-ui/setzer.py b/src/kronos-ui/setzer.py new file mode 100644 index 0000000..6f38ff7 --- /dev/null +++ b/src/kronos-ui/setzer.py @@ -0,0 +1,3 @@ +import typst + +typst.compile("src/typst/calendar.typ", output="calendar.pdf") diff --git a/src/kronos-ui/static/index.html b/src/kronos-ui/static/index.html new file mode 100644 index 0000000..dcbe7af --- /dev/null +++ b/src/kronos-ui/static/index.html @@ -0,0 +1,164 @@ + + + + + + Kronos UI -- Generator Genialnych Grafik + + + + + + + + + + + + +
+
+
+
+

Kronos

+
+ Kalendarz + Karta +
+
+
+

Kalendarz

+
+ +
+ +
+
+ +
+
+
+

Karta

+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + diff --git a/src/kronos/main.py b/src/kronos/main.py index 25e9219..8db068b 100755 --- a/src/kronos/main.py +++ b/src/kronos/main.py @@ -4,7 +4,6 @@ import sys from zoneinfo import ZoneInfo from argparse import ArgumentParser -import requests from bs4 import BeautifulSoup from dotenv import load_dotenv from jinja2 import Environment, FileSystemLoader, select_autoescape @@ -12,13 +11,13 @@ from premailer import transform from .discordbot import KronosBot, intents +from .mobilizon import get_raw_events + -MOBILIZON_API_URL = "https://events.hs3.pl/api" -QUERY_LIMIT = 100 -TIME_WINDOW_DAYS = 365 TRUNCATE_AFTER_CHARACTERS = 300 -TEMPLATE_FILENAME = "templates/newsletter_template.html" -OUTPUT_FILENAME = "newsletter_events.html" +TEMPLATES = { + "templates/newsletter_template.html": "newsletter_events.html", +} def sanitize_html(raw_html: str) -> str: @@ -29,69 +28,8 @@ def sanitize_html(raw_html: str) -> str: return cleaned -def get_time_window(days: int = 365): - now_utc = datetime.datetime.now(datetime.timezone.utc) - ends_utc = now_utc + datetime.timedelta(days=days) - - begins_iso = now_utc.replace(microsecond=0).isoformat().replace("+00:00", "Z") - ends_iso = ends_utc.replace(microsecond=0).isoformat().replace("+00:00", "Z") - return begins_iso, ends_iso - - -def build_graphql_query(): - return """ - query SearchEventsInWindow($beginsOn: DateTime, $endsOn: DateTime, $limit: Int) { - searchEvents(beginsOn: $beginsOn, endsOn: $endsOn, limit: $limit) { - total - elements { - __typename - ... on Event { - id - title - description - beginsOn - picture { - url - } - url - physicalAddress { - description - locality - } - } - } - } - } - """ - - -def fetch_events(begins_on: str, ends_on: str, limit: int = QUERY_LIMIT): - query = build_graphql_query() - variables = {"beginsOn": begins_on, "endsOn": ends_on, "limit": limit} - payload = {"query": query, "variables": variables} - headers = {"Content-Type": "application/json"} - - resp = requests.post(MOBILIZON_API_URL, json=payload, headers=headers) - resp.raise_for_status() - data = resp.json() - if "errors" in data: - raise RuntimeError(f"GraphQL error: {data['errors']}") - - events = [] - for elem in data["data"]["searchEvents"]["elements"]: - if elem.get("__typename") == "Event": - begins_iso = elem.get("beginsOn") - if begins_iso: - dt = datetime.datetime.fromisoformat(begins_iso.replace("Z", "+00:00")) - dt_begins = datetime.datetime.fromisoformat(begins_on.replace("Z", "+00:00")) - dt_ends = datetime.datetime.fromisoformat(ends_on.replace("Z", "+00:00")) - if dt_begins <= dt < dt_ends: - events.append(elem) - return events - - def prepare_events_for_template(raw_events: list) -> list: - jours_semaine = [ + days_week = [ "poniedziałek", "wtorek", "środa", @@ -100,7 +38,7 @@ def prepare_events_for_template(raw_events: list) -> list: "sobota", "niedziela", ] - mois_annee = [ + month_year = [ "", "stycznia", "lutego", @@ -132,6 +70,7 @@ def prepare_events_for_template(raw_events: list) -> list: begins_iso = ev.get("beginsOn") picture = ev.get("picture") picture_url = picture.get("url") if picture else None + picture_filename = ev.get("picture_filename") link = ev.get("url") or "" if picture_url and "?" in picture_url: @@ -146,15 +85,15 @@ def prepare_events_for_template(raw_events: list) -> list: location = "" dt_utc = datetime.datetime.fromisoformat(begins_iso.replace("Z", "+00:00")) - dt_paris = dt_utc.astimezone(ZoneInfo("Europe/Paris")) - jour_nom = jours_semaine[dt_paris.weekday()] - jour_num = dt_paris.day - mois_nom = mois_annee[dt_paris.month] - annee = dt_paris.year - heure = dt_paris.hour - minute = dt_paris.minute + dt_warsaw = dt_utc.astimezone(ZoneInfo("Europe/Warsaw")) + day_name = days_week[dt_warsaw.weekday()] + day_num = dt_warsaw.day + month_name = month_year[dt_warsaw.month] + year = dt_warsaw.year + hour = dt_warsaw.hour + minute = dt_warsaw.minute minute_str = f"{minute:02d}" - full_date = f"{jour_nom}, {jour_num} {mois_nom} {annee} @ {heure}:{minute_str}" + full_date = f"{day_name}, {day_num} {month_name} {year} @ {hour}:{minute_str}" prepared.append( { @@ -162,6 +101,7 @@ def prepare_events_for_template(raw_events: list) -> list: "description": truncated, "full_date": full_date, "picture_url": picture_url, + "picture_filename": picture_filename, "location": location, "link": link, "start_time": dt_utc, @@ -199,45 +139,27 @@ def _main(): _args = parser.parse_args() try: - begins_on, ends_on = get_time_window(days=TIME_WINDOW_DAYS) - print( - f"Fetching events between {begins_on} and {ends_on}...", - file=sys.stderr, - ) - - raw_events = list( - filter( - lambda x: "https://events.hs3.pl/" in x.get("url", ""), - fetch_events(begins_on, ends_on), - ) - ) - if not raw_events: - print("No events found in the requested period.", file=sys.stderr) - sys.exit(0) - - for ev in raw_events: - print(f"{ev.get('title', 'Untitled')} — {ev.get('beginsOn', 'Unknown date')}") - - raw_events.sort(key=lambda ev: ev.get("beginsOn", "")) - + raw_events = get_raw_events() events = prepare_events_for_template(raw_events) - os.makedirs("dist", exist_ok=True) - output_path = os.path.join(os.getcwd(), "dist", OUTPUT_FILENAME) - html_output = render_newsletter( - events=events, template_dir=os.getcwd(), template_name=TEMPLATE_FILENAME - ) + for template_filename, output_filename in TEMPLATES.items(): + output = render_newsletter( + events=events, template_dir=os.getcwd(), template_name=template_filename + ) - with open(output_path, "w", encoding="utf-8") as f: - f.write(html_output) - print(f"File '{output_path}' generated successfully.", file=sys.stderr) + os.makedirs("dist", exist_ok=True) + output_path = os.path.join(os.getcwd(), "dist", output_filename) + with open(output_path, "w", encoding="utf-8") as f: + f.write(output) + print(f"File '{output_path}' generated successfully.", file=sys.stderr) - inlined_output_path = os.path.join(os.getcwd(), "dist", "newsletter_events_inlined.html") - inline_css(output_path, inlined_output_path) - print( - f"File '{inlined_output_path}' (inline CSS) generated.", - file=sys.stderr, - ) + if output_filename.endswith(".html"): + inlined_output_path = os.path.join(os.getcwd(), "dist", f"inlined_{output_filename}") + inline_css(output_path, inlined_output_path) + print( + f"File '{inlined_output_path}' (inline CSS) generated.", + file=sys.stderr, + ) discord_token = os.getenv("DISCORD_TOKEN") client = KronosBot(intents=intents) diff --git a/src/kronos/mobilizon.py b/src/kronos/mobilizon.py new file mode 100644 index 0000000..9881c09 --- /dev/null +++ b/src/kronos/mobilizon.py @@ -0,0 +1,143 @@ +import datetime +import json +import os +import sys +import requests + +from bs4 import BeautifulSoup +from pytz import timezone + +MOBILIZON_API_URL = "https://events.hs3.pl/api" +QUERY_LIMIT = 100 +TIME_WINDOW_DAYS = 365 + + +def get_time_window(start_utc=datetime.datetime.now(datetime.timezone.utc), days: int = 365): + now_utc = start_utc + ends_utc = now_utc + datetime.timedelta(days=days) + + begins_iso = now_utc.replace(microsecond=0).isoformat().replace("+00:00", "Z") + ends_iso = ends_utc.replace(microsecond=0).isoformat().replace("+00:00", "Z") + return begins_iso, ends_iso + + +def build_graphql_query(): + return """ + query SearchEventsInWindow($beginsOn: DateTime, $endsOn: DateTime, $limit: Int) { + searchEvents(beginsOn: $beginsOn, endsOn: $endsOn, limit: $limit) { + total + elements { + __typename + ... on Event { + id + title + description + beginsOn + endsOn + picture { + url + } + url + physicalAddress { + description + locality + } + } + } + } + } + """ + + +def fetch_events(begins_on: str, ends_on: str, limit: int = QUERY_LIMIT): + query = build_graphql_query() + variables = {"beginsOn": begins_on, "endsOn": ends_on, "limit": limit} + payload = {"query": query, "variables": variables} + headers = {"Content-Type": "application/json"} + + resp = requests.post(MOBILIZON_API_URL, json=payload, headers=headers) + resp.raise_for_status() + data = resp.json() + if "errors" in data: + raise RuntimeError(f"GraphQL error: {data['errors']}") + + events = [] + for elem in data["data"]["searchEvents"]["elements"]: + if elem.get("__typename") == "Event": + begins_iso = elem.get("beginsOn") + if begins_iso: + dt = datetime.datetime.fromisoformat(begins_iso.replace("Z", "+00:00")) + dt_begins = datetime.datetime.fromisoformat(begins_on.replace("Z", "+00:00")) + dt_ends = datetime.datetime.fromisoformat(ends_on.replace("Z", "+00:00")) + if dt_begins <= dt < dt_ends: + events.append(elem) + return events + + +def save_json_content(events): + json_dirname = "src/typst/content" + os.makedirs(json_dirname, exist_ok=True) + with open(os.path.join(json_dirname, "events.json"), "w") as f: + json.dump(sorted(events, key=lambda event: event["beginsOn"]), f) + + +def extract_picture(event): + picture = event.get("picture") + picture_url = picture.get("url") if picture else None + picture_filename = None + + if picture_url: + if "?" in picture_url: + picture_url = picture_url.split("?", 1)[0] + + picture_dirname = "src/typst/assets/tmp" + picture_filename = os.path.join(picture_dirname, picture_url.split("/")[-1]) + event["picture_filename"] = picture_filename + + response = requests.get(picture_url) + + os.makedirs(picture_dirname, exist_ok=True) + with open(picture_filename, "wb") as picture_file: + picture_file.write(response.content) + + +def get_raw_events(): + begins_on, ends_on = get_time_window(days=TIME_WINDOW_DAYS) + print( + f"Fetching events between {begins_on} and {ends_on}...", + file=sys.stderr, + ) + + raw_events = list( + filter( + lambda x: "https://events.hs3.pl/" in x.get("url", ""), + fetch_events(begins_on, ends_on), + ) + ) + if not raw_events: + print("No events found in the requested period.", file=sys.stderr) + sys.exit(0) + + for ev in raw_events: + print(f"{ev.get('title', 'Untitled')} — {ev.get('beginsOn', 'Unknown date')}") + + ev["txt_description"] = BeautifulSoup(ev["description"], "html.parser").get_text() + + local_tz = timezone("Europe/Warsaw") + begins_date = datetime.datetime.fromisoformat(ev["beginsOn"]).astimezone(local_tz) + ends_date = datetime.datetime.fromisoformat(ev["endsOn"]).astimezone(local_tz) + begins = (begins_date.strftime("%Y-%m-%d"), begins_date.strftime("%H:%M")) + ends = (ends_date.strftime("%Y-%m-%d"), ends_date.strftime("%H:%M")) + txt_date = f"{begins[0]} {begins[1]}-" + if begins[0] != ends[0]: + txt_date += f"{ends[0]}" + txt_date += f"{ends[1]}" + ev["txt_date"] = txt_date + + extract_picture(ev) + + save_json_content(raw_events) + + raw_events.sort(key=lambda ev: ev.get("beginsOn", "")) + + return raw_events diff --git a/src/typst/.gitignore b/src/typst/.gitignore new file mode 100644 index 0000000..20634ad --- /dev/null +++ b/src/typst/.gitignore @@ -0,0 +1,2 @@ +assets/tmp/* +*.pdf diff --git a/src/typst/assets/calendar.svg b/src/typst/assets/calendar.svg new file mode 100644 index 0000000..69b9967 --- /dev/null +++ b/src/typst/assets/calendar.svg @@ -0,0 +1,25941 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GSPublisherVersion 0.17.100.100 + + + + + + + + + + + + + + + + + + + + NADCHODZĄCE + WYDARZENIA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SPRAWDŹ + , + CO SIĘ + U NAS DZIEJE + + + + + + + + + + + + OTWARCI + DLA WSZYSTKICH + + + + + + + + + + + + TWORZYMY + DZIELIMY SIĘ + UCZYMY + + + + + + + + + + + + TECHNOLOGIA + PASJA + SPOŁECZNOŚĆ + + + + + + + + + + + + DOŁĄCZ DO NAS + ! + + + + + + + + + + + + hs + 3 + . + pl + + + + + + + + + + + + KODUJ + . + TWÓRZ + . + INSPIRUJ SIĘ + . + BAW SIĘ + . + + + + + + + + + + + + STATUS + : + AKTYWNY + + + + + + + + + + + + KOD + + + + + + + + + + + + TRYB + : + KREATYWNY + + + + + + + + + + + + ELEKTRONIKA + + + + + + + + + + + + MECHANIKA + + + + + + + + + + + + DESIGN + + + + + + + + + + + + EKSPERYMENTY + + + + + + + + + + + + KAWA + + + + + + + + + + + + POWER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/typst/assets/event.svg b/src/typst/assets/event.svg new file mode 100644 index 0000000..517ccb8 --- /dev/null +++ b/src/typst/assets/event.svg @@ -0,0 +1,1244 @@ + + + + + + + + + + + + + + + + + + + GSPublisherVersion 0.20.100.100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/typst/assets/hs3_logo_hires.png b/src/typst/assets/hs3_logo_hires.png new file mode 100644 index 0000000..a78beac Binary files /dev/null and b/src/typst/assets/hs3_logo_hires.png differ diff --git a/src/typst/assets/logo.png b/src/typst/assets/logo.png new file mode 100644 index 0000000..dd8e793 Binary files /dev/null and b/src/typst/assets/logo.png differ diff --git a/src/typst/assets/photo.jpg b/src/typst/assets/photo.jpg new file mode 100644 index 0000000..718b180 Binary files /dev/null and b/src/typst/assets/photo.jpg differ diff --git a/src/typst/calendar.typ b/src/typst/calendar.typ new file mode 100644 index 0000000..622fb6a --- /dev/null +++ b/src/typst/calendar.typ @@ -0,0 +1,88 @@ +#import "@preview/cades:0.3.1": qr-code + +#set page( + paper: "a4", + background: context { + place(center + horizon, { + image("assets/calendar.svg") + }) + }, + margin: (top: .5cm, bottom: .5cm, x: 0cm), +) + +#place( + top + left, + dx: 8mm, + dy: -14mm, + image("assets/hs3_logo_hires.png", height: 58mm, width: 58mm), +) + +#place( + top + left, + dx: 13mm, + dy: 145mm, + qr-code("https://hs3.pl", width: 32mm), +) + +#let add_event(number, title, description, date, address) = { + let ex = 85mm + calc.rem-euclid(number, 2) * 67mm + let ey = 46mm + calc.div-euclid(number, 2) * 76mm + + set text( + fill: white, + font: "Rajdhani", + ) + + place( + top + left, + dx: ex, + dy: ey, + block( + width: 32mm, + height: 48mm, + + [ + #block( + height: 14mm, + text( + weight: "bold", + title, + ), + ) + #move(dy: 3mm, block( + height: 8mm, + clip: true, + text( + weight: "bold", + size: 10pt, + date, + ), + )) + #move(dy: 4mm, block( + height: 12mm, + clip: true, + text(size: 10pt, address), + )) + ], + ), + ) +} + +#let events = json("content/events.json") +#let index = 0 + +#for event in events { + add_event( + index, + event.title, + event.txt_description, + event.txt_date, + "Hackerspace Trójmiasto, al. Wojska Polskiego 41, Gdańsk", + ) + + index = index + 1 + + if (index >= 6) { + break + } +} diff --git a/src/typst/content/.gitkeep b/src/typst/content/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/typst/event.typ b/src/typst/event.typ new file mode 100644 index 0000000..2e665bd --- /dev/null +++ b/src/typst/event.typ @@ -0,0 +1,86 @@ +#import "@preview/bulb:0.1.0": dither + +#set page( + width: 297mm, + height: 169mm, + background: context { + place(center + horizon, { + image("assets/event.svg") + }) + }, + margin: (top: 0cm, bottom: .5cm, x: .5cm), +) + +#let make_event_card(title, description, date, address, picture, name) = { + move( + dx: 148mm, + dy: 23mm, + image( + dither( + read(picture, encoding: none), + mode: "bw", + method: "bayer8x8", + size: 360, + ), + ), + ) + place( + top + left, + dx: 94mm, + dy: -4mm, + image("assets/hs3_logo_hires.png", height: 38mm, width: 38mm), + ) + + set text(font: "Hanken Grotesk", size: 14pt) + + place( + top + left, + dx: 12mm, + dy: 30mm, + block( + width: 118mm, + height: 130mm, + grid( + rows: (2fr, 6fr, 0.75fr, 0.5fr), + text(size: 28pt, weight: "bold", title), + text(size: 10pt, description), + text( + size: 24pt, + weight: "bold", + grid( + columns: (1fr, 1fr), + date.split(" ").at(0), align(right)[#date.split(" ").at(1)], + ), + ), + address, + ), + ), + ) + + align(right + bottom)[#text(size: 14pt, weight: "bold", name)] +} + +#let events = none +#if sys.inputs.len() < 1 { + events = json("content/events.json") +} else { + events = json(bytes(sys.inputs.events)) +} +#let index = 0 + +#for event in events { + make_event_card( + event.title, + event.txt_description, + event.txt_date, + "Gdańsk, al. Wojska Polskiego 41", + event.picture, + event.speaker, + ) + + index = index + 1 + + if index < events.len() { + pagebreak() + } +}