Move the live NET readout from the panel center onto the tab sub-bar
The pending trade's credit delta now sits at the right end of the Buy/Sell + Buyback sub-bar, past a hairline divider — tabs AND the credit math on one console, one glance apart (entry state dims it to 0 cr). The center column keeps Confirm/Clear (re-centered); the buyback panel's Confirm moves up to sit just below its rows. Knobs: data/shopui.json → preview (bar sizing, zeroColor, divider). Docs: docs/ECONOMY.md §12 mockups + bullets follow the new layout. Tests: dev/shop-ui.test.mjs asserts the bar's NET readout mirrors the pending trade (+N cr while picking, 0 cr after Confirm).
This commit is contained in:
parent
05b6f573c3
commit
2b860cc899
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"_comment": "SHOP UI — the buy/sell (and buyback) screen over the shop clip (data/shopui.json). LAYOUT: the two 4×4 grids sit side by side (SELL = the player's cargo bays on the LEFT, BUY = the shop's stock on the RIGHT), a center column carries the live NET preview + Confirm/Clear, and a tab bar up top toggles Buy/Sell ↔ Buyback (Buyback is disabled until the player has SOLD something this session). The panels are semi-transparent so the shop clip shows through; items + text are full alpha. CELLS show the good's ICON only — the name + price appear in a hover TOOLTIP (→ tooltip) instead of over the icon. GEOMETRY (slot/gap/gridCols/gridRows/centerW) is primitives the code (js/ui/shop/ShopView.js) lays out against the live scene size — not pixel positions. The ECONOMY itself (prices, stock) is Economy.js + data/goods.json + data/economy.json; this file is only presentation.",
|
||||
"_comment": "SHOP UI — the buy/sell (and buyback) screen over the shop clip (data/shopui.json). LAYOUT: the two 4×4 grids sit side by side (SELL = the player's cargo bays on the LEFT, BUY = the shop's stock on the RIGHT), Confirm/Clear sit in the center column, the live NET-credits readout rides on the TAB SUB-BAR (right of the Buy/Sell + Buyback buttons, past a hairline divider), and the tab sub-bar toggles Buy/Sell ↔ Buyback (Buyback is disabled until the player has SOLD something this session). The panels are semi-transparent so the shop clip shows through; items + text are full alpha. CELLS show the good's ICON only — the name + price appear in a hover TOOLTIP (→ tooltip) instead of over the icon. GEOMETRY (slot/gap/gridCols/gridRows/centerW) is primitives the code (js/ui/shop/ShopView.js) lays out against the live scene size — not pixel positions. The ECONOMY itself (prices, stock) is Economy.js + data/goods.json + data/economy.json; this file is only presentation.",
|
||||
"enabled": true,
|
||||
|
||||
"tabs": {
|
||||
"_comment": "The tab sub-bar (two MenuButtons, the deck's cyberpunk style — js/ui/MenuButton.js). Buy/Sell opens the trade panel; Buyback opens the buyback panel (goods sold this session, session-local only). Size/palette come from data/save.json → subBar + colors (the Menu sub-bar recipe); this section just holds the labels + Buy/Sell accent. The sub-bar rests above the command deck, anchored to the deck's Shop button (SurfaceScene.shopAnchor).",
|
||||
"_comment": "The tab sub-bar (two MenuButtons, the deck's cyberpunk style — js/ui/MenuButton.js), EXTENDED at its right end by the live NET readout (→ preview) past a hairline divider. Buy/Sell opens the trade panel; Buyback opens the buyback panel (goods sold this session, session-local only). Size/palette come from data/save.json → subBar + colors (the Menu sub-bar recipe); this section just holds the labels + Buy/Sell accent. The sub-bar rests above the command deck, anchored to the deck's Shop button (SurfaceScene.shopAnchor).",
|
||||
"buySell": "Buy/Sell",
|
||||
"buyback": "Buyback",
|
||||
"w": 184, "h": 46, "gap": 14,
|
||||
|
|
@ -61,13 +61,16 @@
|
|||
},
|
||||
|
||||
"preview": {
|
||||
"_comment": "The live NET-credits readout in the center column. Positive (you're up) = green, negative (you'd spend past your credits / it's a net spend) = the value shown; the Confirm button is disabled while the trade is invalid (can't go negative, hold overflows).",
|
||||
"_comment": "The live NET-credits readout — on the TAB SUB-BAR, right of the Buy/Sell + Buyback buttons, past a hairline divider (→ divider): tabs AND the pending trade's credit delta on one console, one glance apart. Positive (you're up) = green, negative (a net spend) = the value shown in magenta, zero = dim (entry state / nothing selected). The value is right-aligned at the bar's end so longer numbers (+1,240 cr) never resize the bar. Confirm is disabled while the trade is invalid (can't go negative, hold overflows).",
|
||||
"label": "NET",
|
||||
"labelColor": "#7d92c4",
|
||||
"labelFontSize": 13,
|
||||
"valueFontSize": 34,
|
||||
"labelFontSize": 12,
|
||||
"valueFontSize": 22,
|
||||
"zeroColor": "#7d92c4",
|
||||
"posColor": "#7ce8a4",
|
||||
"negColor": "#ff2d6f"
|
||||
"negColor": "#ff2d6f",
|
||||
"gap": 12,
|
||||
"divider": { "width": 2, "height": 26, "color": "#22405f", "alpha": 0.9 }
|
||||
},
|
||||
|
||||
"buttons": {
|
||||
|
|
|
|||
|
|
@ -333,12 +333,19 @@ console.log('\n== SELL — check a bay, Confirm earns credits + empties the hold
|
|||
assert.equal(pv.net, sellA, '… net = the sale (nothing bought)');
|
||||
assert.equal(pv.valid, true, '… and it\u2019s legal');
|
||||
|
||||
// The live NET readout rides on the TAB SUB-BAR (not the center column) —
|
||||
// it mirrors the pending trade's credit delta, one glance from the tabs.
|
||||
assert.ok(view._netValue, 'the sub-bar carries the NET value readout');
|
||||
assert.ok(view._netLabel, '… with the NET label');
|
||||
assert.equal(view._netValue.text, `+${sellA} cr`, '… it shows the pending +cr');
|
||||
|
||||
const before = ship.credits;
|
||||
assert.equal(view.confirm(), true, 'Confirm goes through');
|
||||
assert.equal(ship.credits, before + sellA, 'credits rise by the sale');
|
||||
assert.deepEqual(ship.cargo.snapshot(), [B], 'A leaves the hold, B stays');
|
||||
assert.equal(view.isBuybackEnabled(), true, '… and A is now buyback-eligible');
|
||||
assert.equal(gs.refreshed, 1, 'the credits HUD was refreshed');
|
||||
assert.equal(view._netValue.text, '0 cr', '… and the bar’s NET settles back to 0 cr');
|
||||
}
|
||||
console.log('SELL: OK');
|
||||
|
||||
|
|
|
|||
|
|
@ -298,7 +298,8 @@ existing `data/actionbar.json` slot); the shop clip is already live, and the scr
|
|||
it. It's one component — `js/ui/shop/ShopView.js` — composing two `TradeGrid`s.
|
||||
|
||||
**Entry state (showcase the clip).** When you first open the shop, **only the tab sub-bar**
|
||||
is up — the cyberpunk **MenuButton** pair `[ BUY/SELL | BUYBACK ]` (Buyback grayed out), the
|
||||
is up — the cyberpunk **MenuButton** pair `[ BUY/SELL | BUYBACK ]` (Buyback grayed out),
|
||||
extended at its right end by the live **NET** readout (dim `0 cr` until you start picking), the
|
||||
same style + placement as the deck's **Menu** sub-bar (`js/ui/MenuSubBar.js`). It rests **above
|
||||
the command deck**, right-aligned to the deck's **Shop** button — so it reads as the same family
|
||||
of UI as the Menu drawer. The screen stays open on the shop video so the clip plays. Clicking
|
||||
|
|
@ -308,24 +309,23 @@ of UI as the Menu drawer. The screen stays open on the shop video so the clip pl
|
|||
# first click — shop video + the tab sub-bar (rests above the deck):
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ (clip plays) │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ BUY/SELL │ BUYBACK │ ← sub-bar │
|
||||
│ └─────────────────────────┘ │
|
||||
│ ┌──────────────────────────────────┐ │
|
||||
│ │ BUY/SELL │ BUYBACK │ NET 0 cr │ ← sub-bar │
|
||||
│ └──────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ SHOP │ BUILD │ SHIP │ QUESTS │ TAKE OFF │ MENU ← command deck│
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# after clicking Buy/Sell — the trade panel reveals (middle of the screen):
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ┌SELL 4×4┐ NET +420 cr ┌BUY 4×4┐ │
|
||||
│ │ bays │ (green ≥ 0 / │ stock │ │
|
||||
│ │(cargo) │ red < 0) │(12–16) │ │
|
||||
│ └────────┘ [ CONFIRM ] └────────┘ │
|
||||
│ [ CLEAR ] │
|
||||
│ ┌SELL 4×4┐ [ CONFIRM ] ┌BUY 4×4┐ │
|
||||
│ │ bays │ [ CLEAR ] │ stock │ │
|
||||
│ │(cargo) │ │(12–16) │ │
|
||||
│ └────────┘ └────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ BUY/SELL │ BUYBACK │ ← sub-bar │
|
||||
│ └─────────────────────────┘ │
|
||||
│ ┌──────────────────────────────────┐ │
|
||||
│ │ BUY/SELL │ BUYBACK │ NET +420 cr │ ← sub-bar │
|
||||
│ └──────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ SHOP │ BUILD │ SHIP │ QUESTS │ TAKE OFF │ MENU ← command deck│
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
|
@ -335,9 +335,11 @@ of UI as the Menu drawer. The screen stays open on the shop video so the clip pl
|
|||
cyberpunk style: cut-corner panel, neon edge, hover sweep, press punch) in a console-blue
|
||||
panel that rests above the command deck, anchored to the Shop button — the exact recipe of
|
||||
the Menu sub-bar. Buyback is **disabled** (grayed) until you've sold something this visit.
|
||||
- **Confirm / Clear** — the same `MenuButton` style; Confirm is **disabled** (grayed) while
|
||||
the trade is invalid (can't go negative, hold would overflow), and both appear once you start
|
||||
picking.
|
||||
The bar is **extended** past a hairline divider to carry the live **NET** readout —
|
||||
one glance sees the tabs *and* the pending trade's credit delta.
|
||||
- **Confirm / Clear** — the same `MenuButton` style, in the center column between the grids;
|
||||
Confirm is **disabled** (grayed) while the trade is invalid (can't go negative, hold would
|
||||
overflow), and both appear once you start picking.
|
||||
|
||||
- **SELL (left)** — your **cargo bays**. 16 cells (the fixed grid); the first `cargoHold`
|
||||
are live bays (filled with a good, or empty), the rest are **locked** (the hold's upgrade
|
||||
|
|
@ -345,8 +347,9 @@ of UI as the Menu drawer. The screen stays open on the shop video so the clip pl
|
|||
quantity is simply the number of its bays that are checked.
|
||||
- **BUY (right)** — the shop's **stock** (12–16 distinct goods from `Economy.shopFor`). Each
|
||||
cell has a **−/qty/+ stepper**; buy as many as you like (capped by credits + hold room).
|
||||
- **NET preview (center)** — the live credit delta. Green when you're up (a net sale), red when
|
||||
you'd spend. Updates as you check bays / step goods.
|
||||
- **NET readout (tab sub-bar)** — the live credit delta, right of the tabs past the divider.
|
||||
Green when you're up (a net sale), red when you'd spend, dim at zero. Updates as you check
|
||||
bays / step goods (it's the same `preview()` the Confirm button is gated on).
|
||||
- **SELL → BUY is atomic** — check bays to sell *and* step goods to buy, then one Confirm
|
||||
executes it: credits `+ sale − buy`, cargo `− sold + bought`, in that order (free room
|
||||
first). Selling to free a bay for a buy lands in the same Confirm.
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
/**
|
||||
* ShopView — the buy/sell (and buyback) screen over the shop clip video.
|
||||
*
|
||||
* ┌─────────────────────────────────────────────────────────────┐
|
||||
* │ [ Buy/Sell | Buyback ] ← tabs │
|
||||
* │ │
|
||||
* │ ┌SELL 4×4┐ ┌ NET ┐ ┌BUY 4×4┐ │
|
||||
* │ │ bays │ │ +420 │ │ stock │ │
|
||||
* │ │ (cargo)│ │ cr │ │ (12–16)│ │
|
||||
* │ └────────┘ │[Conf]│ └────────┘ │
|
||||
* │ │[Clear]│ │
|
||||
* └─────────────────────────────────────────────────────────────┘
|
||||
* ┌────────────────────────────────────────────────────────────┐
|
||||
* │ ┌SELL 4×4┐ [ Confirm ] ┌BUY 4×4┐ │
|
||||
* │ │ bays │ [ Clear ] │ stock │ │
|
||||
* │ │ (cargo)│ │ (12–16)│ │
|
||||
* │ └────────┘ └────────┘ │
|
||||
* └────────────────────────────────────────────────────────────┘
|
||||
* ┌────────────────────────────────────────────────────────────┐
|
||||
* │ BUY/SELL BUYBACK │ NET +420 cr ← tab sub-bar │
|
||||
* └────────────────────────────────────────────────────────────┘
|
||||
*
|
||||
* The two sides are TradeGrids (js/ui/shop/TradeGrid.js):
|
||||
* · SELL (left) — the player's cargo bays. Tap a filled bay to check it
|
||||
* off (a bay = 1 unit). Locked bays are the hold's upgrade room.
|
||||
* · BUY (right) — the shop's stock, each with a −/qty/+ stepper.
|
||||
* The live NET preview (green ≥ 0, red < 0) and Confirm/Clear live in the
|
||||
* center; Confirm is disabled while the trade is invalid (can't go negative,
|
||||
* The live NET preview (green ≥ 0, red < 0) sits on the TAB SUB-BAR, right
|
||||
* of the Buy/Sell + Buyback buttons past a hairline divider (tabs AND the
|
||||
* pending trade's credit math on one console); Confirm/Clear stay in the
|
||||
* center. Confirm is disabled while the trade is invalid (can't go negative,
|
||||
* hold would overflow). SELL→BUY happens atomically (sell to free room for a
|
||||
* buy).
|
||||
*
|
||||
|
|
@ -83,7 +85,8 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
this.sellGrid = null;
|
||||
this.buyGrid = null;
|
||||
this._content = null; // the active content container
|
||||
this._previewText = null;
|
||||
this._netLabel = null; // the sub-bar NET label (persistent)
|
||||
this._netValue = null; // the sub-bar NET value (live)
|
||||
this._confirmBtn = null;
|
||||
this._clearBtn = null;
|
||||
this._tabBuyback = null;
|
||||
|
|
@ -132,6 +135,12 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
// signature top rail, holding cyberpunk MenuButtons. It rests ABOVE the
|
||||
// command deck, right-aligned to the deck's "Shop" button (this.anchor),
|
||||
// so it reads as the same family of UI as the Menu drawer.
|
||||
//
|
||||
// EXTENDED (data/shopui.json → preview): the live NET credit readout —
|
||||
// the pending trade's credit delta — sits at the bar's right end past a
|
||||
// hairline divider. Tabs AND the credit math on ONE console: the readout
|
||||
// is one glance away from the tabs at every moment (entry state included,
|
||||
// where it dims to "0 cr").
|
||||
const a = this.anchor;
|
||||
const H = config.get('save.subBar.height', 58);
|
||||
const pad = config.get('save.subBar.padding', 16);
|
||||
|
|
@ -139,6 +148,7 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
const tabs = config.get('shopui.tabs', {});
|
||||
const c = config.section('save.colors', {});
|
||||
const btnCfg = config.section('save.subBar.button', {});
|
||||
const pv = config.section('shopui.preview', {});
|
||||
|
||||
const items = [
|
||||
{ id: 'trade', label: tabs.buySell ?? 'Buy/Sell', accent: tabs.activeAccent ?? c.neon ?? '#00e5ff' },
|
||||
|
|
@ -165,10 +175,31 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
|
||||
const btns = items.map(mkBtn);
|
||||
const widths = btns.map((b) => b.style?.width ?? 120);
|
||||
const W = Math.min(
|
||||
this._W() - 24,
|
||||
pad * 2 + widths.reduce((s, w) => s + w, 0) + gap * (widths.length - 1),
|
||||
);
|
||||
const tabsW = widths.reduce((s, w) => s + w, 0) + gap * (widths.length - 1);
|
||||
|
||||
// The NET readout — created BEFORE the panel body so its REAL width feeds
|
||||
// the bar width (a headless fake without text metrics falls back to an
|
||||
// estimate). The value is RIGHT-aligned at the bar's end, so longer
|
||||
// numbers ("+1,240 cr") never need the bar to grow.
|
||||
const labelStr = String(pv.label ?? 'NET');
|
||||
const valueFont = Math.max(8, Number(pv.valueFontSize) || 22);
|
||||
this._netLabel = this._makeText(0, -H / 2, labelStr, {
|
||||
fontSize: `${Math.max(8, Number(pv.labelFontSize) || 12)}px`,
|
||||
color: toCss(pv.labelColor ?? c.dim ?? '#7d92c4'),
|
||||
align: 'left',
|
||||
});
|
||||
this._netValue = this._makeText(0, -H / 2, '0 cr', {
|
||||
fontSize: `${valueFont}px`,
|
||||
color: toCss(pv.zeroColor ?? pv.labelColor ?? '#7d92c4'),
|
||||
align: 'left',
|
||||
});
|
||||
const labelW = (Number(this._netLabel?.width) > 0 ? this._netLabel.width : labelStr.length * 8) || 30;
|
||||
const valueW = (Number(this._netValue?.width) > 0 ? this._netValue.width : 4 * valueFont * 0.6) || 40;
|
||||
const divW = Math.max(1, Number(pv.divider?.width) || 2);
|
||||
const divH = Math.max(10, Number(pv.divider?.height) || Math.round(H * 0.45));
|
||||
|
||||
// Row: [ BUY/SELL ][ BUYBACK ] │ NET value
|
||||
const W = Math.min(this._W() - 24, pad * 2 + tabsW + gap + divW + gap + labelW + gap + valueW);
|
||||
|
||||
// Position: bottom edge on the deck's top rail (a.y), right edge on the
|
||||
// Shop button's right edge — the MenuSubBar recipe. The sub-bar is a
|
||||
|
|
@ -187,15 +218,18 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
this.add?.(bar);
|
||||
|
||||
// The body FIRST (v4 paints children in list order — the opaque panel
|
||||
// fill must come before the buttons or it would cover them).
|
||||
// fill must come before the buttons or it would cover them). The hairline
|
||||
// divider between the tabs and the NET block is part of the body, so it
|
||||
// paints under both.
|
||||
const divX = -W / 2 + pad + tabsW + gap + divW / 2;
|
||||
const bodyG = this.scene.add?.graphics?.();
|
||||
if (bodyG) {
|
||||
bodyG.setScrollFactor?.(0);
|
||||
bar.add?.(bodyG);
|
||||
this._drawSubBarBody(bodyG, W, H, c);
|
||||
this._drawSubBarBody(bodyG, W, H, c, divX, divH);
|
||||
}
|
||||
|
||||
// The buttons LAST (above the body), centered in the row.
|
||||
// The buttons LAST (above the body), left-anchored in the row.
|
||||
let bx = -W / 2 + pad + widths[0] / 2;
|
||||
items.forEach((it, i) => {
|
||||
const btn = btns[i];
|
||||
|
|
@ -206,12 +240,23 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
bx += widths[i] / 2 + gap + (i < items.length - 1 ? widths[i + 1] / 2 : 0);
|
||||
});
|
||||
|
||||
// The NET block: the label right after the divider, the value right-
|
||||
// aligned to the bar's end (so a growing number never shifts the label).
|
||||
this._netLabel.setPosition?.(divX + divW / 2 + gap + labelW / 2, -H / 2);
|
||||
this._netValue.setPosition?.(W / 2 - pad - valueW / 2, -H / 2);
|
||||
bar.add?.(this._netLabel);
|
||||
bar.add?.(this._netValue);
|
||||
|
||||
// Buyback starts grayed (disabled) until a sale exists this visit.
|
||||
this._refreshTabs();
|
||||
}
|
||||
|
||||
/** The sub-bar panel body (the MenuSubBar recipe at full height). */
|
||||
_drawSubBarBody(g, W, H, c) {
|
||||
/**
|
||||
* The sub-bar panel body (the MenuSubBar recipe at full height).
|
||||
* `divX`/`divH` (optional) add the hairline divider between the tabs and
|
||||
* the NET readout — drawn as body so it paints under the buttons + text.
|
||||
*/
|
||||
_drawSubBarBody(g, W, H, c, divX, divH) {
|
||||
if (!g || typeof g.clear !== 'function') return;
|
||||
const panelTop = toColor(c.panelTop ?? '#0e1930');
|
||||
const panelBottom = toColor(c.panelBottom ?? '#050912');
|
||||
|
|
@ -238,6 +283,10 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
g.fillStyle(ink, 0.8); g.fillRect(-W / 2 + cut, -H + 0.5, W - cut * 2, 0.8);
|
||||
g.fillStyle(magenta, 0.5); g.fillRect(-W / 2 + cut, -H + rail, W - cut * 2, 1);
|
||||
g.fillStyle(magenta, 0.35); g.fillRect(-W / 2, -1.5, W, 1.5); // seam
|
||||
if (typeof divX === 'number' && divH > 0) {
|
||||
g.fillStyle(toColor(c.border ?? '#22405f'), 0.9);
|
||||
g.fillRect(divX - 1, -H / 2 - divH / 2, 2, divH); // tabs │ NET
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,27 +347,17 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
content.add?.(sellGrid);
|
||||
content.add?.(buyGrid);
|
||||
|
||||
// center column: NET preview + Confirm + Clear — vertically centered with
|
||||
// the grids (the NET above, the buttons below), so the whole panel is one
|
||||
// cohesive block near the top of the screen.
|
||||
// center column: Confirm + Clear — vertically centered with the grids,
|
||||
// so the whole panel is one cohesive block near the top of the screen.
|
||||
// (The live NET preview now rides on the tab sub-bar — see _buildTabs.)
|
||||
const cx = leftX + sellGrid.width + centerW / 2;
|
||||
const cy = this.topY + gridH / 2;
|
||||
this._previewLabel = this._makeText(cx, cy - 52, config.get('shopui.preview.label', 'NET'), {
|
||||
fontSize: `${config.get('shopui.preview.labelFontSize', 13)}px`,
|
||||
color: config.get('shopui.preview.labelColor', '#7d92c4'), align: 'center',
|
||||
});
|
||||
this._previewText = this._makeText(cx, cy - 14, 'NET 0 cr', {
|
||||
fontSize: `${config.get('shopui.preview.valueFontSize', 34)}px`,
|
||||
color: config.get('shopui.preview.zeroColor', '#7d92c4'), align: 'center',
|
||||
});
|
||||
content.add?.(this._previewLabel);
|
||||
content.add?.(this._previewText);
|
||||
|
||||
// Confirm / Clear — the same cyberpunk MenuButton as the tab bar.
|
||||
const c = config.section('save.colors', {});
|
||||
const btnCfg = config.section('save.subBar.button', {});
|
||||
this._confirmBtn = new MenuButton(
|
||||
this.scene, cx, cy + 34, config.get('shopui.buttons.confirmLabel', 'Confirm'), () => this.confirm(),
|
||||
this.scene, cx, cy + 16, config.get('shopui.buttons.confirmLabel', 'Confirm'), () => this.confirm(),
|
||||
{
|
||||
screenFixed: true,
|
||||
fontSize: btnCfg.fontSize ?? 13, paddingX: 26, paddingY: 12,
|
||||
|
|
@ -331,7 +370,7 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
content.add?.(this._confirmBtn);
|
||||
|
||||
this._clearBtn = new MenuButton(
|
||||
this.scene, cx, cy + 104, config.get('shopui.buttons.clearLabel', 'Clear'), () => this.clear(),
|
||||
this.scene, cx, cy + 86, config.get('shopui.buttons.clearLabel', 'Clear'), () => this.clear(),
|
||||
{
|
||||
screenFixed: true,
|
||||
fontSize: btnCfg.fontSize ?? 13, paddingX: 26, paddingY: 12,
|
||||
|
|
@ -390,16 +429,11 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
}
|
||||
|
||||
const cy = y + 24;
|
||||
this._previewLabel = this._makeText(cx, cy - 8, config.get('shopui.preview.label', 'NET'), {
|
||||
fontSize: `${config.get('shopui.preview.labelFontSize', 13)}px`, color: config.get('shopui.preview.labelColor', '#7d92c4'), align: 'center' });
|
||||
content.add?.(this._previewLabel);
|
||||
this._previewText = this._makeText(cx, cy + 22, 'NET 0 cr', {
|
||||
fontSize: `${config.get('shopui.preview.valueFontSize', 34)}px`, color: config.get('shopui.preview.zeroColor', '#7d92c4'), align: 'center' });
|
||||
content.add?.(this._previewText);
|
||||
// (The live NET readout rides on the tab sub-bar — see _buildTabs.)
|
||||
|
||||
const bw = config.get('shopui.buttons.w', 158), bh = config.get('shopui.buttons.h', 54);
|
||||
this._confirmBtn = this._makeButton(config.get('shopui.buttons.confirmLabel', 'Confirm'), bw, bh, config.get('shopui.buttons.confirmAccent', '#7ce8a4'));
|
||||
this._confirmBtn.setPosition(cx, cy + 92);
|
||||
this._confirmBtn.setPosition(cx, cy + 40);
|
||||
this._confirmBtn.tap(() => this.confirm());
|
||||
this._confirmBtn.setAlpha(0);
|
||||
content.add?.(this._confirmBtn.container);
|
||||
|
|
@ -531,13 +565,16 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
_syncPreview() {
|
||||
const pv = this.preview();
|
||||
const anySel = this._hasAnySelection();
|
||||
if (this._previewText && typeof this._previewText.setText === 'function') {
|
||||
const sign = pv.net >= 0 ? '+' : '';
|
||||
this._previewText.setText(`NET ${sign}${Math.round(pv.net)} cr`);
|
||||
const col = pv.net === 0
|
||||
// The live NET readout lives on the tab sub-bar (this._netValue) — one
|
||||
// glance sees the tabs AND the pending trade's credit delta. Right-
|
||||
// aligned, so a growing number never shifts the "NET" label.
|
||||
if (this._netValue && typeof this._netValue.setText === 'function') {
|
||||
const n = Math.round(pv.net);
|
||||
this._netValue.setText(n === 0 ? '0 cr' : `${n > 0 ? '+' : ''}${n} cr`);
|
||||
const col = n === 0
|
||||
? config.get('shopui.preview.zeroColor', '#7d92c4')
|
||||
: (pv.net > 0 ? config.get('shopui.preview.posColor', '#7ce8a4') : config.get('shopui.preview.negColor', '#ff2d6f'));
|
||||
if (typeof this._previewText.setColor === 'function') this._previewText.setColor(col);
|
||||
: (n > 0 ? config.get('shopui.preview.posColor', '#7ce8a4') : config.get('shopui.preview.negColor', '#ff2d6f'));
|
||||
if (typeof this._netValue.setColor === 'function') this._netValue.setColor(col);
|
||||
}
|
||||
const confirmOn = anySel;
|
||||
const confirmEnabled = anySel && pv.valid;
|
||||
|
|
@ -584,8 +621,6 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
this.buyGrid?.destroy?.();
|
||||
this.sellGrid = null;
|
||||
this.buyGrid = null;
|
||||
this._previewText = null;
|
||||
this._previewLabel = null;
|
||||
this._confirmBtn = null;
|
||||
this._clearBtn = null;
|
||||
}
|
||||
|
|
@ -594,6 +629,10 @@ export class ShopView extends Phaser.GameObjects.Container {
|
|||
this._destroyContent();
|
||||
this._tabTrade?.destroy?.();
|
||||
this._tabBuyback?.destroy?.();
|
||||
this._netLabel?.destroy?.();
|
||||
this._netValue?.destroy?.();
|
||||
this._netLabel = null;
|
||||
this._netValue = null;
|
||||
if (typeof super.destroy === 'function') super.destroy();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue