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
|
||||||
94
index.html
94
index.html
|
|
@ -129,10 +129,21 @@
|
||||||
padding: .55rem .7rem;
|
padding: .55rem .7rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: .45rem .8rem;
|
gap: .45rem .8rem;
|
||||||
align-items: end;
|
align-items: start;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
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 input,
|
||||||
.card select,
|
.card select,
|
||||||
.card textarea {
|
.card textarea {
|
||||||
|
|
@ -149,17 +160,70 @@
|
||||||
gap: .35rem;
|
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 {
|
.card-actions {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
justify-self: end;
|
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 {
|
.log-cell {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.log-on .log-cell {
|
.card.log-on .log-cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output tables: a CSS grid kept inside a scroll container so it never
|
/* 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
|
// Vat amounts only matter for Foundries; hide them otherwise and keep
|
||||||
// them as the card's last fields (before the actions).
|
// them as the card's last field (before the actions). They stack in a
|
||||||
const vatFields = [
|
// single cell, each input labeled on its left.
|
||||||
field("Vat steel", vs),
|
const vatRow = (label, input) =>
|
||||||
field("Vat brass", vb),
|
el("label", {class: "field vat-row"}, [el("span", {}, label), input]);
|
||||||
field("Vat electrum", ve),
|
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() {
|
function renderVats() {
|
||||||
const show = type.value === "foundry";
|
vatGroup.style.display = type.value === "foundry" ? "" : "none";
|
||||||
for (const f of vatFields) f.style.display = show ? "" : "none";
|
|
||||||
}
|
}
|
||||||
type.onchange = () => {renderUpgrades(); renderVats();};
|
type.onchange = () => {renderUpgrades(); renderVats();};
|
||||||
renderUpgrades();
|
renderUpgrades();
|
||||||
|
|
@ -499,14 +566,16 @@
|
||||||
};
|
};
|
||||||
card.append(
|
card.append(
|
||||||
field("Name", name),
|
field("Name", name),
|
||||||
|
el("div", {class: "stack"}, [
|
||||||
field("Type", type),
|
field("Type", type),
|
||||||
|
checkField("Can renovate", reno),
|
||||||
|
]),
|
||||||
field("Renown", renown),
|
field("Renown", renown),
|
||||||
field("Upgrades (already installed)", upWrap),
|
field("Upgrades (already installed)", upWrap),
|
||||||
checkField("Can renovate", reno),
|
|
||||||
field("Adjacent cities (csv of names)", adjacent),
|
field("Adjacent cities (csv of names)", adjacent),
|
||||||
field("Forced actions (turn:action, csv)", forced),
|
field("Forced actions (turn:action, csv)", forced),
|
||||||
field("Avail turns (csv, blank=all)", avail),
|
field("Avail turns (csv, blank=all)", avail),
|
||||||
...vatFields,
|
vatGroup,
|
||||||
el("div", {class: "card-actions"}, removeBtn(card)));
|
el("div", {class: "card-actions"}, removeBtn(card)));
|
||||||
document.getElementById("cities").append(card);
|
document.getElementById("cities").append(card);
|
||||||
}
|
}
|
||||||
|
|
@ -584,8 +653,7 @@
|
||||||
resF,
|
resF,
|
||||||
field("Scalar", scalar),
|
field("Scalar", scalar),
|
||||||
turnF,
|
turnF,
|
||||||
checkField("Log?", isLog),
|
el("div", {class: "log-group"}, [field("Log", isLog), exprF]),
|
||||||
exprF,
|
|
||||||
el("div", {class: "card-actions"}, removeBtn(card)));
|
el("div", {class: "card-actions"}, removeBtn(card)));
|
||||||
document.getElementById("terms").append(card);
|
document.getElementById("terms").append(card);
|
||||||
toggle();
|
toggle();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue