Compare commits
2 Commits
40c3131b90
...
afcd230c3a
| Author | SHA1 | Date | |
|---|---|---|---|
|
afcd230c3a
|
|||
|
4593f9e8fb
|
+5
-1
@@ -3,7 +3,11 @@ myice.ini
|
||||
schedule.json
|
||||
.envrc
|
||||
cookies.txt
|
||||
# Byte-compiled / optimized / DLL files
|
||||
# Tailwind CSS generated artifacts
|
||||
style.css
|
||||
tailwindcss
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
@@ -48,6 +48,21 @@ pre-commit run ruff-format --files myice/webapi.py
|
||||
pre-commit run mypy --files myice/myice.py
|
||||
```
|
||||
|
||||
### CSS/Frontend Build
|
||||
|
||||
When modifying `index.html` or the Tailwind CSS setup:
|
||||
|
||||
```bash
|
||||
# One-off build of style.css
|
||||
./build-css.sh
|
||||
|
||||
# Watch mode for development
|
||||
./build-css.sh --watch
|
||||
|
||||
# Or manually with the standalone CLI (if already downloaded)
|
||||
./tailwindcss -i ./style-input.css -o ./style.css --minify
|
||||
```
|
||||
|
||||
### Running the Web API
|
||||
|
||||
```bash
|
||||
|
||||
+14
-2
@@ -4,7 +4,12 @@ FROM python:3.13-slim AS builder
|
||||
# Create working directory
|
||||
WORKDIR /app
|
||||
|
||||
# poetry export -f requirements.txt --output requirements.txt --without-hashes
|
||||
# Install tools needed for Tailwind CSS build
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy dependency files
|
||||
COPY requirements.txt ./
|
||||
|
||||
@@ -12,6 +17,12 @@ COPY requirements.txt ./
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install --no-deps --disable-pip-version-check -r requirements.txt
|
||||
|
||||
# Build Tailwind CSS
|
||||
COPY index.html style-input.css tailwind.config.js ./
|
||||
RUN curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.17/tailwindcss-linux-x64 -o tailwindcss \
|
||||
&& chmod +x tailwindcss \
|
||||
&& ./tailwindcss -i ./style-input.css -o ./style.css --minify
|
||||
|
||||
# Runtime stage
|
||||
FROM python:3.13-slim AS runtime
|
||||
|
||||
@@ -29,8 +40,9 @@ RUN useradd --home-dir /app --no-create-home --uid 1000 myice
|
||||
# Copy installed packages from builder stage
|
||||
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
|
||||
|
||||
# Copy application code
|
||||
# Copy application code and compiled assets
|
||||
COPY index.html favicon.ico ./
|
||||
COPY --from=builder /app/style.css ./style.css
|
||||
COPY myice ./myice
|
||||
|
||||
# Change ownership of copied files
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Build CSS using Tailwind CSS standalone CLI
|
||||
# For local development, run:
|
||||
# ./build-css.sh # one-off build
|
||||
# ./build-css.sh --watch # watch mode
|
||||
|
||||
version="v3.4.17"
|
||||
os="$(uname -s)"
|
||||
arch="$(uname -m)"
|
||||
|
||||
case "$os" in
|
||||
Linux*) platform="linux";;
|
||||
Darwin*) platform="macos";;
|
||||
*) echo "Unsupported OS: $os"; exit 1;;
|
||||
esac
|
||||
|
||||
case "$arch" in
|
||||
x86_64) arch="x64";;
|
||||
arm64) arch="arm64";;
|
||||
aarch64) arch="arm64";;
|
||||
*) echo "Unsupported architecture: $arch"; exit 1;;
|
||||
esac
|
||||
|
||||
binary="tailwindcss-${platform}-${arch}"
|
||||
url="https://github.com/tailwindlabs/tailwindcss/releases/download/${version}/${binary}"
|
||||
|
||||
if [ ! -f "tailwindcss" ]; then
|
||||
echo "Downloading Tailwind CSS standalone CLI (${version} ${platform}/${arch})..."
|
||||
curl -sL "$url" -o tailwindcss
|
||||
chmod +x tailwindcss
|
||||
fi
|
||||
|
||||
if [ "${1:-}" == "--watch" ]; then
|
||||
echo "Building CSS in watch mode..."
|
||||
./tailwindcss -i ./style-input.css -o ./style.css --watch
|
||||
else
|
||||
echo "Building CSS..."
|
||||
./tailwindcss -i ./style-input.css -o ./style.css --minify
|
||||
fi
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MyIce - Games</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
</head>
|
||||
|
||||
|
||||
+22
-3
@@ -140,6 +140,11 @@ def get_health() -> HealthCheck:
|
||||
return HealthCheck(status="OK")
|
||||
|
||||
|
||||
@app.get("/style.css")
|
||||
async def style_css():
|
||||
return FileResponse("style.css")
|
||||
|
||||
|
||||
@app.get("/favicon.ico")
|
||||
async def favico():
|
||||
return FileResponse("favicon.ico")
|
||||
@@ -177,9 +182,20 @@ async def login(request: Request):
|
||||
|
||||
response = RedirectResponse(auth_url)
|
||||
# Store state and nonce in secure http-only cookies for validation on callback
|
||||
response.set_cookie("oidc_state", state, httponly=True, max_age=300)
|
||||
response.set_cookie("oidc_nonce", nonce, httponly=True, max_age=300)
|
||||
response.set_cookie("oidc_verifier", code_verifier, httponly=True, max_age=300)
|
||||
response.set_cookie(
|
||||
"oidc_state", state, httponly=True, secure=True, samesite="Lax", max_age=300
|
||||
)
|
||||
response.set_cookie(
|
||||
"oidc_nonce", nonce, httponly=True, secure=True, samesite="Lax", max_age=300
|
||||
)
|
||||
response.set_cookie(
|
||||
"oidc_verifier",
|
||||
code_verifier,
|
||||
httponly=True,
|
||||
secure=True,
|
||||
samesite="Lax",
|
||||
max_age=300,
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
@@ -252,6 +268,7 @@ async def callback(request: Request, code: str, state: str):
|
||||
|
||||
@app.get("/exchange-token")
|
||||
async def exchange_token(
|
||||
request: Request,
|
||||
code: str,
|
||||
headers: Annotated[AuthHeaders, Header()],
|
||||
):
|
||||
@@ -259,6 +276,7 @@ async def exchange_token(
|
||||
if not headers.authorized():
|
||||
raise HTTPException(401, detail="get out")
|
||||
|
||||
code_verifier = request.cookies.get("oidc_verifier")
|
||||
# Exchange authorization code for access token
|
||||
token_data = {
|
||||
"grant_type": "authorization_code",
|
||||
@@ -266,6 +284,7 @@ async def exchange_token(
|
||||
"client_secret": CLIENT_SECRET,
|
||||
"code": code,
|
||||
"redirect_uri": REDIRECT_URI,
|
||||
"code_verifier": code_verifier,
|
||||
}
|
||||
|
||||
response = requests.post(TOKEN_ENDPOINT, data=token_data)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
Reference in New Issue
Block a user