Enhance UI components for map editing and school creation. Update styles for improved layout and responsiveness, including adjustments to dialog positioning and flex properties. Introduce new localization strings for better user guidance in both English and Russian. Refactor code structure for clarity and maintainability, ensuring a more intuitive user experience.
ci / server (push) Failing after 3m32s
ci / client (push) Successful in 14s

This commit is contained in:
Leonid Pershin
2026-08-18 16:34:35 +03:00
parent 3068d10409
commit 7658443cd5
9 changed files with 378 additions and 119 deletions
+181 -55
View File
@@ -3,6 +3,7 @@
--surface: #10141c;
--surface-raised: #171d28;
--surface-sunken: #0c1017;
--border: #2a3242;
--text: #d7e0ef;
--text-muted: #8b98ad;
@@ -19,14 +20,39 @@
body {
margin: 0;
min-height: 100vh;
min-height: 100dvh;
background: var(--surface);
}
/*
* The shell fills the window. A management screen that stops halfway down a very wide page reads
* as a half-loaded document rather than a game, so every screen is a full-height flex column and
* decides its own comfortable width.
*/
#app {
max-width: 1080px;
display: flex;
min-height: 100dvh;
padding: 24px 24px 52px;
}
.screen {
display: flex;
flex: 1;
flex-direction: column;
min-width: 0;
min-height: 0;
width: 100%;
margin: 0 auto;
padding: 32px 20px 72px;
}
/* A short list of saves sits in the middle of the window instead of clinging to the top edge. */
.screen.menu {
max-width: 900px;
justify-content: center;
}
.screen.game {
max-width: 1500px;
}
#status {
@@ -73,7 +99,7 @@ body {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
margin-bottom: 16px;
}
.screen__title {
@@ -100,15 +126,16 @@ body {
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
align-content: start;
gap: 16px;
}
.card {
display: flex;
flex-direction: column;
gap: 8px;
padding: 16px;
gap: 6px;
padding: 18px;
border: 1px solid var(--border);
border-radius: 12px;
background: var(--surface-raised);
@@ -151,75 +178,109 @@ body {
}
.card__actions {
margin-top: 8px;
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
/* Clock */
.clock {
padding: 28px;
/*
* Inside a school the calendar is a toolbar, not a hero banner: the panels below are the screen,
* and a 56px centred clock pushed them down for no information gained.
*/
.clockbar {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
padding: 12px 18px;
border: 1px solid var(--border);
border-radius: 16px;
border-radius: 14px;
background: var(--surface-raised);
text-align: center;
}
.clockbar__now {
display: flex;
align-items: center;
gap: 16px;
min-width: 0;
}
.clock__time {
margin: 0;
font-size: 56px;
font-size: 34px;
font-weight: 600;
font-variant-numeric: tabular-nums;
letter-spacing: 0.02em;
line-height: 1.1;
}
.clockbar__labels {
display: flex;
flex-direction: column;
min-width: 0;
}
.clock__date {
margin: 4px 0 0;
font-size: 18px;
margin: 0;
font-size: 15px;
}
.clock__weekday {
margin: 2px 0 0;
margin: 0;
color: var(--text-muted);
font-size: 13px;
text-transform: capitalize;
}
.clock__controls {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 20px;
}
.screen.game .clock {
padding: 20px;
}
.screen.game .clock__time {
font-size: 40px;
margin-left: auto;
}
/* Manager */
.manager {
display: grid;
grid-template-columns: minmax(180px, 1fr) minmax(200px, 1fr) minmax(240px, 1.35fr);
grid-template-columns: minmax(210px, 0.85fr) minmax(240px, 1fr) minmax(280px, 1.25fr);
gap: 16px;
margin-top: 20px;
flex: 1;
min-height: 0;
margin-top: 16px;
}
.panel {
display: flex;
flex-direction: column;
min-width: 0;
padding: 16px;
min-height: 0;
border: 1px solid var(--border);
border-radius: 12px;
background: var(--surface-raised);
}
.panel__title {
margin: 0 0 12px;
font-size: 15px;
flex: 0 0 auto;
margin: 0;
padding: 11px 16px;
border-bottom: 1px solid var(--border);
color: var(--text-muted);
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
}
/* The body scrolls, the title stays: a long tree must not push the panel out of the window. */
.panel__body {
flex: 1;
min-height: 0;
overflow: auto;
padding: 12px 12px 16px;
}
.panel__name {
@@ -229,7 +290,11 @@ body {
}
.panel__section {
margin-top: 12px;
margin-top: 14px;
}
.panel__section:first-child {
margin-top: 0;
}
.panel__section-title {
@@ -286,9 +351,20 @@ body {
color: var(--accent);
}
@media (max-width: 800px) {
/* Below three columns the panels stop competing for height and the page scrolls instead. */
@media (max-width: 900px) {
#app {
min-height: 0;
}
.manager {
grid-template-columns: 1fr;
display: flex;
flex-direction: column;
flex: 0 0 auto;
}
.panel__body {
overflow: visible;
}
}
@@ -302,6 +378,7 @@ body {
color: var(--text);
font: inherit;
font-size: 14px;
white-space: nowrap;
cursor: pointer;
transition: border-color 120ms ease, background 120ms ease;
}
@@ -342,11 +419,11 @@ body {
}
.input {
flex: 1;
min-width: 0;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--surface);
background: var(--surface-sunken);
color: var(--text);
font: inherit;
font-size: 14px;
@@ -361,7 +438,7 @@ body {
.dialog {
min-width: 340px;
max-width: 440px;
max-width: 460px;
padding: 24px;
border: 1px solid var(--border);
border-radius: 14px;
@@ -369,13 +446,20 @@ body {
color: var(--text);
}
/*
* The editor grows with its map instead of always claiming 800px: a two-room school framed by a
* half-empty window was the loudest thing on screen.
*/
.dialog--screen[open] {
display: flex;
flex-direction: column;
min-width: unset;
max-width: none;
width: min(1080px, calc(100vw - 24px));
height: min(800px, calc(100vh - 24px));
width: min(1080px, calc(100vw - 32px));
/* A modal dialog is absolutely positioned with `inset: 0`, so `height: auto` stretches it to the
max instead of shrink-wrapping. `fit-content` is what actually lets it size to its map. */
height: fit-content;
max-height: calc(100dvh - 48px);
padding: 16px 20px 20px;
}
@@ -389,21 +473,12 @@ body {
}
.dialog--screen .map-editor {
flex: 1;
min-height: 0;
grid-template-columns: minmax(220px, 0.9fr) minmax(280px, 1.3fr);
flex: 1 1 auto;
min-height: min(400px, 55dvh);
grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.3fr);
gap: 16px;
}
.dialog--screen .map-editor__pane,
.dialog--screen .map-editor__details {
min-height: 0;
overflow: auto;
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px;
}
.dialog--screen .dialog__actions {
flex: 0 0 auto;
margin-top: 12px;
@@ -453,6 +528,20 @@ body {
color: var(--text-muted);
}
/*
* Without this the rows fell back to inline-block flow, `.input { flex: 1 }` never applied and
* every field in the create form ended up a different width.
*/
.field__row {
display: flex;
align-items: center;
gap: 8px;
}
.field__row > .input {
flex: 1;
}
.field .hint {
margin: 0;
font-size: 13px;
@@ -460,8 +549,8 @@ body {
.mod-list {
display: flex;
flex-direction: column;
gap: 6px;
flex-wrap: wrap;
gap: 8px 16px;
}
.mod-list__item {
@@ -471,16 +560,53 @@ body {
font-size: 14px;
}
/* Map editor */
.map-editor {
display: grid;
grid-template-columns: minmax(180px, 1fr) minmax(240px, 1.4fr);
grid-template-columns: minmax(200px, 0.9fr) minmax(280px, 1.3fr);
gap: 12px;
}
.map-editor__pane,
.map-editor__details {
display: flex;
flex-direction: column;
gap: 10px;
min-width: 0;
min-height: 0;
gap: 12px;
overflow: auto;
}
.editor-section {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--surface-sunken);
}
.editor-section--grow {
flex: 1;
min-height: 0;
overflow: auto;
}
.editor-section__title {
margin: 0;
color: var(--text-muted);
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.editor-section__hint {
margin: 0;
color: var(--text-muted);
font-size: 13px;
}
.map-editor__links {