Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 5 additions & 35 deletions frontend/src/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -664,46 +664,18 @@
background-color: var(--color-canvas-subtle);
}

/* Chat markdown tables (ResponsiveTable): horizontal rules, Maple tokens, full width + wrap */
/* Chat markdown tables (ResponsiveTable): Maple tokens with intrinsic column sizing */
.markdown-body table.markdown-table-maple {
display: table;
table-layout: fixed;
width: 100%;
max-width: 100%;
min-width: 0;
table-layout: auto;
width: max-content;
max-width: none;
background-color: transparent;
box-shadow: none;
border: none;
border-radius: 0;
}

.markdown-body table.markdown-table-maple thead th,
.markdown-body table.markdown-table-maple tbody td,
.markdown-body table.markdown-table-maple tbody th {
min-width: 0;
overflow-wrap: break-word;
word-break: break-word;
}

/* Slightly wider label column on small screens */
@media (max-width: 767px) {
.markdown-body table.markdown-table-maple th:first-child,
.markdown-body table.markdown-table-maple td:first-child {
padding-left: 0;
width: 34%;
max-width: 11rem;
}
}

@media (min-width: 768px) {
.markdown-body table.markdown-table-maple th:first-child,
.markdown-body table.markdown-table-maple td:first-child {
padding-left: 0;
width: 22%;
max-width: 10.5rem;
}
}

.markdown-body table.markdown-table-maple thead th {
font-weight: 600;
color: hsl(var(--foreground));
Expand All @@ -713,7 +685,6 @@
border: none;
border-bottom: 1px solid hsl(var(--maple-secondary) / 0.2);
background-color: transparent;
max-width: none;
}

.markdown-body table.markdown-table-maple tbody td,
Expand All @@ -726,10 +697,9 @@
border: none;
border-bottom: 1px solid hsl(var(--maple-secondary-container));
background-color: transparent;
max-width: none;
}

/* First column flush left (base); width caps only on md+ above */
/* First column flush left */
.markdown-body table.markdown-table-maple th:first-child,
.markdown-body table.markdown-table-maple td:first-child {
padding-left: 0;
Expand Down
58 changes: 54 additions & 4 deletions frontend/src/components/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,18 +274,68 @@ function ResponsiveTable({ children, className, ...rest }: JSX.IntrinsicElements
// Strip off props added by react-markdown that the DOM doesn't understand
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { node, inline, ...safeRest } = rest as Record<string, unknown>;
const tableProps = safeRest as JSX.IntrinsicElements["table"];
const tableStyle = {
...(tableProps.style ?? {}),
minWidth: "max-content"
};

const scrollRef = useRef<HTMLDivElement>(null);
const [canScrollLeft, setCanScrollLeft] = useState(false);
const [canScrollRight, setCanScrollRight] = useState(false);

useEffect(() => {
const el = scrollRef.current;
if (!el) return;

const checkScroll = () => {
const { scrollLeft, scrollWidth, clientWidth } = el;
setCanScrollLeft(scrollLeft > 0);
setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);
};

const frameId = window.requestAnimationFrame(checkScroll);

el.addEventListener("scroll", checkScroll, { passive: true });
window.addEventListener("resize", checkScroll);

let resizeObserver: ResizeObserver | undefined;
if (typeof ResizeObserver !== "undefined") {
resizeObserver = new ResizeObserver(checkScroll);
resizeObserver.observe(el);
const tableEl = el.querySelector("table");
if (tableEl) {
resizeObserver.observe(tableEl);
}
}

return () => {
window.cancelAnimationFrame(frameId);
el.removeEventListener("scroll", checkScroll);
window.removeEventListener("resize", checkScroll);
resizeObserver?.disconnect();
};
}, [children]);

return (
<div className="my-4 w-full min-w-0 max-w-none self-stretch">
<div className="relative my-4 -mx-4 px-4">
{canScrollLeft && (
<div className="pointer-events-none absolute bottom-0 left-[15px] top-0 z-10 w-8 bg-gradient-to-r from-background via-background/85 to-transparent" />
)}
{canScrollRight && (
<div className="pointer-events-none absolute bottom-0 right-[15px] top-0 z-10 w-8 bg-gradient-to-l from-background via-background/85 to-transparent" />
)}
<div
ref={scrollRef}
className={cn(
"block w-full min-w-0 overflow-x-auto overflow-y-visible overscroll-x-contain",
"overflow-x-auto overflow-y-visible overscroll-x-contain",
"[-webkit-overflow-scrolling:touch]"
)}
>
<table
className={cn("markdown-table-maple w-full min-w-0", className || "")}
{...(safeRest as object)}
{...tableProps}
className={cn("markdown-table-maple", className || "")}
style={tableStyle}
>
{children}
</table>
Expand Down
Loading