From 0f7ff2c3e9ef7c59c82769f7270764a0f9d6d4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mekina?= Date: Fri, 2 May 2025 22:05:45 +0200 Subject: [PATCH] add presentation base --- .gitignore | 4 ++++ Makefile | 27 +++++++++++++++++++++++++++ README.md | 28 +++++++++++++++++++--------- client/.gitignore | 1 + client/bun.lockb | Bin 0 -> 17998 bytes client/index.html | 12 ++++++++++++ client/make.mk | 33 +++++++++++++++++++++++++++++++++ client/package.json | 14 ++++++++++++++ client/script.ts | 0 client/style.scss | 0 client/tsconfig.json | 27 +++++++++++++++++++++++++++ main.py | 16 +++++++++++++++- 12 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 client/.gitignore create mode 100755 client/bun.lockb create mode 100644 client/index.html create mode 100644 client/make.mk create mode 100644 client/package.json create mode 100644 client/script.ts create mode 100644 client/style.scss create mode 100644 client/tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d485eb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/__pycache__/ +/static/ +/venv/ +/pythagoras.tar.xz diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c97fea2 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +.PHONY: default +default: run + +include client/make.mk + +.PHONY: run +run: $(CLIENT_TARGETS) venv + source venv/bin/activate && python main.py + +.PHONY: build +build: $(CLIENT_TARGETS) + +.PHONY: pack +pack: pythagoras.tar.xz + +.PHONY: clean +clean: client_clean + rm -rf __pycache__ + rm -rf venv + rm -f pythagoras.tar.xz + +venv: + python -m venv venv + source venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt + +pythagoras.tar.xz: main.py $(CLIENT_TARGETS) + tar --transform='s|^|pythagoras/|' -Jcvf $@ $^ diff --git a/README.md b/README.md index c10968d..164f168 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,29 @@ Clone the repository: Install the dependencies: -`cd pythagoras` - -`python -m venv venv` - -`source venv/bin/activate` - -`pip install -r requirements.txt` +`sudo pacman -S python-virtualenv` ## Running the app -Simply run the main Python file to start the server: +Simply execute the **run** recipe in the Makefile to start the server: - `python main.py` +`make run` + +Note that run is also the default recipe. So `make` works too. + +The run recipe should take care of everything for you... enjoy! + +## Cleaning up the mess + +If you wish to go back to a clean slate just run: + +`make clean` + +## Packing for production + +To make an archive `pythagoras.tar.xz` in project root simply run: + +`make pack` ## Usage diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..2ccbe46 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1 @@ +/node_modules/ diff --git a/client/bun.lockb b/client/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..f9c0643ecb2c545b8ba6c3c40009ed3b005c43e8 GIT binary patch literal 17998 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%0ACw}uc3WNj0=gm0FDvU7@bX` zT}bo=)jo#EA@MIH9s@YotAIlyVn~DrB}26-iH#w#8dN(HX$O9uH_Fo`u9$ z00*^(9zr5tNF)X&V}vp!HipD%i0d&2A+l>H(Hy`rWEvqFiMJu~A7U9qBM~_yLIgN4 zdYFS~G!nBzVn~2vEbgQvYKKITP-s*=B#wu~l>i4kfc20F9uiR^FBf6JG)3Khj7Fk- zNYsfGjl}zq_!D_KG}I94ArU|%B1K-VKaMI$BqoT&sDK8hOd~^3VTNSJORAswWFL`2 zE`JtRz#JAT;tB%T{^LXfUVx9ao}qM7G^?K!MM4f$*O^Zme+kybYT#K4-c!B1)v}^< zaHdEoyd`2Gw&FM#LG;|hF5q9CCKizVRt@Pr~k7&9Pc zz9|XSNn{w*e1{c!aYbB?h~dxk7#n?0NX%$JhQ~HG`nD#2UO-4FqCsFBsQzO%KSb#NeJ)jFL*n8B z4FWVG&iI}%JHSg2$n#=+*J5v22YL#<(6R>l&bJ21NXfLZ%w1`FHv#o4MP+cmy8lba z;?@HPP!5uT{+iKDY^rB`7o6fW4;^|QHtzS}C9G!S|4@I@>zh#nj-2o6PZ-U_{=V+@ z4bH7zo_I7h{K`j|o zr4#&5VSfFz0GzLHFb3fg1fMkxcu@N60eNYLfeSS=lnvr>#LuP%Kf|&RRgIc?y41}foGX(4aA8rHnN(%vkG$S=!6v%)T05`Nzq^}DC+SfN2)G8SD zg8fiH2;Z~8r+_HmfHFB)Il(5Q5o^9$Jc0aIc|bs|8t$F-t1>i)FIk~MV>I5c z$<7%B$xo>-8?cz{SwN2b1Ub~TVNJhUeS+{;d8%fr?Kx~d*Pn|0=lFBk0St~%2*ZmH zPj;>VR+nr(#S?Jx&>%$MFMj_COHW)-lb4|lXkT9*G^qa#gUZmn(Z;H;ld@b=KZDv6 zHDbC{ZxEGcq@At-g(aIH5S09)W(~^O{(-Z(0?Hi?$V&?Wgfs)4%MeaB8fh{v$oO)p zj@a11tZyU`ss9bS8Z|x&>KhtGNuxuLz@ryXP&z0YFjHCxK%^OH9@9q0khII80`>im znrbPtLxO@DceJz+phz>6qZ^wCqm%)(0>tU;-K_9vC43UOW!3QB`D%p&w+V7~)MeWfZmh74LW(&`7$81t@6-rZ+RO MQsTYv|GmHe1LA#oi~s-t literal 0 HcmV?d00001 diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..554c142 --- /dev/null +++ b/client/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/client/make.mk b/client/make.mk new file mode 100644 index 0000000..d40bcaa --- /dev/null +++ b/client/make.mk @@ -0,0 +1,33 @@ +CLIENT_PAGES := index.html +CLIENT_STYLES := style.css +CLIENT_SCRIPTS := script.js +CLIENT_TARGETS := $(CLIENT_PAGES:%=static/%) \ + $(CLIENT_STYLES:%=static/%) \ + $(CLIENT_SCRIPTS:%=static/%) + +.PHONY: client_clean +client_clean: + rm -rf static + rm -rf client/node_modules + +client/node_modules: + cd client && bun install + +static/%.html: client/%.html client/node_modules + @mkdir -p $(@D) + cat $< | \ + bun run --cwd client html-minifier \ + --collapse-inline-tag-whitespace \ + --collapse-boolean-attributes \ + --collapse-whitespace \ + --remove-attribute-quotes \ + --remove-comments \ + --remove-redundant-attributes > $@ + +static/%.css: client/%.scss client/node_modules + @mkdir -p $(@D) + bun run --cwd client sass $(notdir $<) --style compressed > $@ + +static/%.js: client/%.ts client/node_modules + @mkdir -p $(@D) + bun build $< --minify --outfile $@ diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..1ef9211 --- /dev/null +++ b/client/package.json @@ -0,0 +1,14 @@ +{ + "name": "client", + "type": "module", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "html-minifier": "^4.0.0", + "sass": "^1.87.0" + } +} diff --git a/client/script.ts b/client/script.ts new file mode 100644 index 0000000..e69de29 diff --git a/client/style.scss b/client/style.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/main.py b/main.py index eb86375..191e344 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,9 @@ from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect, BackgroundTasks -from fastapi.responses import JSONResponse +from fastapi.responses import HTMLResponse, JSONResponse import logging import uvicorn from typing import Dict, List, Any +from dataclasses import dataclass import json import httpx import asyncio @@ -43,6 +44,19 @@ class ConnectionManager: manager = ConnectionManager() +# Static files +def read_file(filepath: str) -> str: + with open(filepath, "r", encoding="utf-8") as f: + return f.read() + +@dataclass +class StaticFiles: + index_html: str = read_file("static/index.html") + +@app.get("/presentation/") +async def presentation_index(_: Request): + return HTMLResponse(status_code=200, content=StaticFiles.index_html) + # Endpoints @app.post("/control") async def control_endpoint(request: Request):