fix(market): inset bid board to timeline gutter

Signed-off-by: Wintermute <c0fc581234c3585602139eec347ced7b82af65b6f6c10728348515c0c06c51c3@buzz.block.builderlab.xyz>
This commit is contained in:
Wintermute
2026-09-07 11:23:08 -04:00
parent c5e47b650e
commit 6dcaf58ee0
2 changed files with 25 additions and 15 deletions

View File

@@ -4,7 +4,7 @@ import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { MARKET_SCENARIOS } from "@/features/market/lib/marketPrototypeData";
import { MarketBidTable } from "./MarketChannelIntro.tsx";
import { MarketBidTable, MarketBoardLayout } from "./MarketChannelIntro.tsx";
import { MarketContractCard } from "./MarketContractCard.tsx";
const bidderOne = "a".repeat(64);
@@ -47,14 +47,23 @@ test("the bid table renders exactly one body row per bid", () => {
assert.equal(body.match(/<tr/g)?.length ?? 0, bids.length);
assert.match(html, />Bidder</);
assert.match(html, />Bid</);
assert.match(html, />Message</);
assert.doesNotMatch(html, />Message</);
assert.match(html, />Fizz</);
assert.match(html, />Honey</);
assert.match(html, />First bid</);
assert.match(html, />Second bid</);
assert.doesNotMatch(html, />First bid</);
assert.doesNotMatch(html, />Second bid</);
});
test("the contract card has no independent horizontal margin", () => {
test("the market board follows the header and avatar gutter", () => {
const html = renderToStaticMarkup(
React.createElement(MarketBoardLayout, null, "Board"),
);
const className = html.match(/<div class="([^"]+)"/)?.[1] ?? "";
assert.match(className, /(?:^|\s)mx-5(?:\s|$)/);
});
test("the contract card leaves horizontal alignment to the board", () => {
const html = renderToStaticMarkup(
React.createElement(MarketContractCard, {
scenario: MARKET_SCENARIOS.finite,

View File

@@ -16,6 +16,13 @@ import type { UserProfileLookup } from "@/features/profile/lib/identity";
import { Button } from "@/shared/ui/button";
import { UserAvatar } from "@/shared/ui/UserAvatar";
const MARKET_BOARD_GUTTER_CLASS = "mx-5";
/** Aligns the market board with the channel header and timeline avatars. */
export function MarketBoardLayout({ children }: { children: React.ReactNode }) {
return <div className={`${MARKET_BOARD_GUTTER_CLASS} mt-2`}>{children}</div>;
}
export function MarketBidTable({
bids,
onOpenBid,
@@ -27,17 +34,14 @@ export function MarketBidTable({
}) {
return (
<div className="overflow-x-auto rounded-xl border border-border/70">
<table className="w-full min-w-[44rem] table-fixed border-collapse text-left text-sm">
<table className="w-full min-w-[28rem] table-fixed border-collapse text-left text-sm">
<thead className="bg-muted/35 text-xs text-muted-foreground">
<tr>
<th className="w-[12rem] px-3 py-2 font-medium" scope="col">
Bidder
</th>
<th className="w-[10rem] px-3 py-2 font-medium" scope="col">
Bid
</th>
<th className="px-3 py-2 font-medium" scope="col">
Message
Bid
</th>
<th className="w-[6.5rem] px-3 py-2 font-medium" scope="col">
<span className="sr-only">Action</span>
@@ -70,9 +74,6 @@ export function MarketBidTable({
: "Terms in thread"}
{` · ${bid.quantity} ${bid.quantity === 1 ? "unit" : "units"}`}
</td>
<td className="truncate px-3 py-2 text-muted-foreground">
<span title={bid.message}>{bid.message}</span>
</td>
<td className="px-2 py-1 text-right">
<Button
aria-label={`Open negotiation with ${displayName}`}
@@ -140,13 +141,13 @@ export function MarketChannelIntro({
if (!projection || isMarketProtocolMessage(anchorMessage)) return undefined;
const visibleBids = marketBidsAfterAnchor(bids, anchorMessage);
return (
<div className="mt-2">
<MarketBoardLayout>
<MarketContractCard scenario={projection.scenario} />
<BidList
bids={visibleBids}
channelId={projection.channelId}
profiles={profiles}
/>
</div>
</MarketBoardLayout>
);
}