frontend tweaks
This commit is contained in:
parent
9866af07d3
commit
751a0e2525
3 changed files with 119 additions and 14 deletions
23
Dockerfile
Normal file
23
Dockerfile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
FROM python:3.13-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install uv
|
||||
RUN pip install --no-cache-dir uv
|
||||
|
||||
# Copy project files
|
||||
COPY pyproject.toml uv.lock ./
|
||||
|
||||
# Install dependencies with uv
|
||||
RUN uv sync --no-editable
|
||||
|
||||
# Copy source code
|
||||
COPY solve.py web_solve.py ./
|
||||
COPY templates/ templates/
|
||||
|
||||
# Set environment variables
|
||||
ENV FLASK_APP=web_solve.py
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Run Flask app
|
||||
CMD ["uv", "run", "python", "web_solve.py"]
|
||||
14
docker-compose.yml
Normal file
14
docker-compose.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "5555:5000"
|
||||
environment:
|
||||
- FLASK_ENV=development
|
||||
- FLASK_DEBUG=1
|
||||
volumes:
|
||||
- .:/app
|
||||
command: uv run python web_solve.py
|
||||
restart: unless-stopped
|
||||
96
index.html
96
index.html
|
|
@ -129,10 +129,21 @@
|
|||
padding: .55rem .7rem;
|
||||
display: grid;
|
||||
gap: .45rem .8rem;
|
||||
align-items: end;
|
||||
align-items: start;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
}
|
||||
|
||||
/* Top-align cells but keep every field's input on a common baseline by
|
||||
reserving a uniform (two-line) label height — so a wrapping label no
|
||||
longer drops its input below the others, and a stacked cell (Type +
|
||||
"Can renovate") can hang its extra control underneath while its primary
|
||||
input still lines up with the rest. */
|
||||
.card .field:not(.check):not(.vat-row)>span {
|
||||
min-height: 2.8em;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.card input,
|
||||
.card select,
|
||||
.card textarea {
|
||||
|
|
@ -149,17 +160,70 @@
|
|||
gap: .35rem;
|
||||
}
|
||||
|
||||
/* Stack two controls vertically inside a single grid cell (e.g. the city
|
||||
Type field with its "Can renovate" checkbox tucked underneath). Top-align
|
||||
so the Type input stays on the same row as the card's other inputs while
|
||||
the checkbox hangs below. */
|
||||
.card .stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .45rem;
|
||||
min-width: 0;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
/* Vat amounts: stacked rows, each with its label to the left of the input. */
|
||||
.card .vat-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .3rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.card .vat-head {
|
||||
font-size: .8rem;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.card .vat-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: .4rem;
|
||||
}
|
||||
|
||||
.card .vat-row>span {
|
||||
flex: 0 0 4rem;
|
||||
}
|
||||
|
||||
.card .vat-row input {
|
||||
width: auto;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
align-self: start;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
/* Keep the "Log" checkbox and its JS-function field together in one cell
|
||||
and reserve the space up front, so enabling the field only fills the
|
||||
already-allotted room instead of reflowing the whole card. */
|
||||
.card .log-group {
|
||||
grid-column: span 2;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
gap: .5rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.log-cell {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.log-on .log-cell {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Output tables: a CSS grid kept inside a scroll container so it never
|
||||
|
|
@ -466,15 +530,18 @@
|
|||
}
|
||||
}
|
||||
// Vat amounts only matter for Foundries; hide them otherwise and keep
|
||||
// them as the card's last fields (before the actions).
|
||||
const vatFields = [
|
||||
field("Vat steel", vs),
|
||||
field("Vat brass", vb),
|
||||
field("Vat electrum", ve),
|
||||
];
|
||||
// them as the card's last field (before the actions). They stack in a
|
||||
// single cell, each input labeled on its left.
|
||||
const vatRow = (label, input) =>
|
||||
el("label", {class: "field vat-row"}, [el("span", {}, label), input]);
|
||||
const vatGroup = el("div", {class: "vat-group"}, [
|
||||
el("span", {class: "vat-head"}, "Vat amounts"),
|
||||
vatRow("steel", vs),
|
||||
vatRow("brass", vb),
|
||||
vatRow("electrum", ve),
|
||||
]);
|
||||
function renderVats() {
|
||||
const show = type.value === "foundry";
|
||||
for (const f of vatFields) f.style.display = show ? "" : "none";
|
||||
vatGroup.style.display = type.value === "foundry" ? "" : "none";
|
||||
}
|
||||
type.onchange = () => {renderUpgrades(); renderVats();};
|
||||
renderUpgrades();
|
||||
|
|
@ -499,14 +566,16 @@
|
|||
};
|
||||
card.append(
|
||||
field("Name", name),
|
||||
field("Type", type),
|
||||
el("div", {class: "stack"}, [
|
||||
field("Type", type),
|
||||
checkField("Can renovate", reno),
|
||||
]),
|
||||
field("Renown", renown),
|
||||
field("Upgrades (already installed)", upWrap),
|
||||
checkField("Can renovate", reno),
|
||||
field("Adjacent cities (csv of names)", adjacent),
|
||||
field("Forced actions (turn:action, csv)", forced),
|
||||
field("Avail turns (csv, blank=all)", avail),
|
||||
...vatFields,
|
||||
vatGroup,
|
||||
el("div", {class: "card-actions"}, removeBtn(card)));
|
||||
document.getElementById("cities").append(card);
|
||||
}
|
||||
|
|
@ -584,8 +653,7 @@
|
|||
resF,
|
||||
field("Scalar", scalar),
|
||||
turnF,
|
||||
checkField("Log?", isLog),
|
||||
exprF,
|
||||
el("div", {class: "log-group"}, [field("Log", isLog), exprF]),
|
||||
el("div", {class: "card-actions"}, removeBtn(card)));
|
||||
document.getElementById("terms").append(card);
|
||||
toggle();
|
||||
|
|
|
|||
Loading…
Reference in a new issue