A compact element like a Jauge (name label + thin bar, no padding) got
an outline pulled 1px INSIDE its box (outline-offset:-1px), which hugged
the content so tightly it looked like it was slicing through the bar
instead of framing it. Push the outline outward instead (+3px) with a
soft glow, so the selection frame reads clearly regardless of how
tightly the underlying element is sized.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A top-level element already got a selection border via its
.canvasElement wrapper, but a child posed inside a container/répéteur/
groupe de champs has no such separate frame, so selecting it from the
tree gave no visual feedback on the canvas at all.
applySelectionHighlight() now targets the element's own tag directly via
data-element-id (present on every rendered element, nested or not) and
outlines it, re-run after every canvas refresh path (initial load, full
pjax navigation, partial panel refresh, and the autosave-only canvas
refresh).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "Éléments de cet écran" tree now sits above "Ajouter un élément sur
l'écran" / "Mes éléments de jeu" so it's the first thing visible in the
left panel.
Each container row gets a disclosure triangle that collapses/expands its
children, independent from the row's link (which still selects the
element and shows its properties whether collapsed or expanded). The
collapsed state is remembered per element in localStorage.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "Éléments de cet écran" tree now renders every level of nesting
(previously stopped after one level of children) as a compact single-line
list, and right-clicking a row opens a context menu to duplicate the
element (and its full subtree) in place, in its current container.
Also: all property panels start collapsed instead of some being open by
default, the redundant nested element list inside "Ajouter DANS ce
conteneur" is removed (it only needs the widget picker), and the
now-unneeded "a container is selected" warning banner is gone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Center the name+bar block vertically within the Jauge's own box
(justify-content:center) so it no longer looks pinned to the top once a
name label adds extra content height.
Add appearance settings for the name: position (above the bar, or beside
it on the left), alignment when above (centered or left-aligned), font
family, font size, bold, and italic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A Jauge posée dans un conteneur a une hauteur "auto" (voir
_style_string) — "flex:1 1 auto" seul n'avait alors rien à répartir
(le conteneur flex lui-même n'a pas de hauteur définie), donc le
wrapper de la barre s'effondrait à 0px : seul le nom restait visible,
la jauge elle-même disparaissait. Ajout d'un "min-height" plancher
sur ce wrapper, qui laisse toujours la barre visible dans ce cas tout
en la laissant grandir avec flex:1 si l'élément a une vraie hauteur.
A Jauge could only target a whole object, not a specific record —
three gauges pointing at the same "value" field (e.g. Réputation/
Trésorerie/Confiance in one "jauge" object) all silently showed the
most recent row's value, with no way to tell them apart.
Add "Enregistrement (ligne) à suivre" (row_id) so a Jauge targets one
specific row, and "Champ contenant le nom" (champ_nom) to show a
label above the bar — both as dropdowns populated from the object's
actual fields/rows (previously "Champ numérique à afficher" was free
text the user had to type correctly by hand). No regression: without
row_id the widget still falls back to the latest row, exactly as
before.
Extract data_definition_options() (rows+fields for a definition) out
of routes/screens/screen_edit.py so controls_with_values.py can reuse
it server-side for the initial render; a small client-side handler
(bindJaugeDefinitionSelect) repopulates the same selects live when
the tracked object is changed without leaving the panel.
Verified live with Playwright: picking "jauge" then "Confiance" then
"value"/"name" in the panel renders an 80%-filled, green-leaning bar
labelled "Confiance" on /play — not the 20%/50% of the other rows.
Add "survol"/"fin_survol" trigger events (mouseenter/mouseleave,
same anti-doublon pattern as bindClicks()) so hovering an element can
run flow nodes, instead of the old static hover-text-only control
removed from the properties panel. Also add "Contenu" as a settable
"Modifier un élément" property so an action can display a defined
text on another element on hover — the concrete use case that
motivated this.
Verified live with Playwright: a "Au survol" trigger on one element
correctly updates another element's text via the action, and text
stays put with no "Fin du survol" wired (explicit, no implicit
revert, consistent with "Au clic").
- Merge "Taille dans le conteneur" into "Position & taille": a child
element (posé dans un conteneur/répéteur/groupe de champs) now shows
greyed-out X/Y (not applicable, it follows its parent's layout) and
a single Largeur/Hauteur field per axis with a unit selector (%/px)
instead of the old fixed-px-only sliders capped at 1000 — which was
the root cause of a landscape-mode bug where a child couldn't be
made wider than 1000px even though the actual screen was wider.
New c_size control type (one style key per axis, not two competing
sliders — an earlier px+% two-slider attempt let the untouched
slider silently clobber the other's value on every autosave).
- Merge the two "Disposition" groups (visibility + scale, previously
split apart in UNIVERSAL_CONTROLS by unrelated groups) into one.
- Remove the "Survol" panel: hovering is conceptually a flow trigger,
not a static element property — to be reintroduced there. The
underlying data-hover-text/bindHoverTexts runtime is untouched.
main.content (.content-builder) inherited "margin:0 auto" from the
base .content class. On this page body is a column flex container, so
that auto margin disabled cross-axis stretch and made the element
shrink-to-fit instead — sized via an algorithm that runs back down
through the flex/%/aspect-ratio chain to the canvas, and shifts
slightly whenever sibling panel content changes (e.g. selecting an
element). Give it an explicit width:100% so max-width/auto-margin
centering still work but sizing is stable and fills the available
space. Also add min-width:0 to .builderPanelRight, matching its
siblings, as defense against the same class of bug.
Verified with Playwright: canvas box was previously not filling
available width (918px expected vs 379px actual at a 1920px viewport)
and shifted between steps; both are fixed.
su forge -s /bin/sh -c 'exec "$@"' -- "$@" didn't forward gunicorn's
argv correctly with this image's su, so the container never actually
started gunicorn — Caddy then had nothing to proxy to (502). Flatten
the command into a single string via "$*" instead.
The named Docker volume mounted at /app/projects is created by Docker
as root before the container starts, so the image's build-time chown
never applies to it. A root-owned volume made the app (running as the
non-root forge user) unable to write new game folders in production.
Add an entrypoint that chowns /app/projects to forge at each startup,
then drops privileges before exec'ing gunicorn.