Archived
fix(chat): scroll wide markdown tables horizontally
Wrap chat markdown tables in a focusable scroll region and let the table keep its natural width so narrow screens can scroll instead of squeezing columns into the chat width.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@jmfederico/pi-web": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Let chat markdown tables keep their natural width and scroll horizontally instead of being squeezed into the chat column, making them readable on mobile.
|
||||||
@@ -465,8 +465,8 @@ export const chatStyles = css`
|
|||||||
export const formattedTextStyles = css`
|
export const formattedTextStyles = css`
|
||||||
:host { display: block; }
|
:host { display: block; }
|
||||||
.formatted { white-space: normal; overflow-wrap: anywhere; line-height: 1.45; text-align: start; unicode-bidi: plaintext; }
|
.formatted { white-space: normal; overflow-wrap: anywhere; line-height: 1.45; text-align: start; unicode-bidi: plaintext; }
|
||||||
p, ul, ol, pre, blockquote, table, .code-block-wrapper { margin: 0 0 10px; }
|
p, ul, ol, pre, blockquote, .table-scroll, .code-block-wrapper { margin: 0 0 10px; }
|
||||||
:is(p, ul, ol, pre, blockquote, table, .code-block-wrapper):last-child { margin-bottom: 0; }
|
:is(p, ul, ol, pre, blockquote, .table-scroll, .code-block-wrapper):last-child { margin-bottom: 0; }
|
||||||
ul, ol { padding-left: 22px; }
|
ul, ol { padding-left: 22px; }
|
||||||
li + li { margin-top: 3px; }
|
li + li { margin-top: 3px; }
|
||||||
code { border: 1px solid var(--pi-border); border-radius: 4px; background: var(--pi-bg); padding: 1px 4px; font: 13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; direction: ltr; text-align: left; unicode-bidi: isolate; }
|
code { border: 1px solid var(--pi-border); border-radius: 4px; background: var(--pi-bg); padding: 1px 4px; font: 13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; direction: ltr; text-align: left; unicode-bidi: isolate; }
|
||||||
@@ -484,8 +484,10 @@ export const formattedTextStyles = css`
|
|||||||
h2 { font-size: 17px; }
|
h2 { font-size: 17px; }
|
||||||
h3 { font-size: 15px; }
|
h3 { font-size: 15px; }
|
||||||
h4 { font-size: 14px; }
|
h4 { font-size: 14px; }
|
||||||
table { border-collapse: collapse; display: block; overflow-x: auto; overflow-y: hidden; }
|
.table-scroll { max-width: 100%; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }
|
||||||
th, td { border: 1px solid var(--pi-border); padding: 4px 8px; }
|
.table-scroll:focus-visible { outline: 1px solid var(--pi-accent); outline-offset: 2px; }
|
||||||
|
table { border-collapse: collapse; width: max-content; min-width: 100%; max-width: none; }
|
||||||
|
th, td { border: 1px solid var(--pi-border); padding: 4px 8px; max-width: 48ch; overflow-wrap: anywhere; }
|
||||||
th { background: var(--pi-surface); }
|
th { background: var(--pi-surface); }
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ function escapeHtml(text: string): string {
|
|||||||
.replaceAll(">", ">");
|
.replaceAll(">", ">");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TABLE_SCROLL_CLASS = "table-scroll";
|
||||||
|
|
||||||
function sanitizeHtml(html: string): string {
|
function sanitizeHtml(html: string): string {
|
||||||
const template = document.createElement("template");
|
const template = document.createElement("template");
|
||||||
template.innerHTML = html;
|
template.innerHTML = html;
|
||||||
@@ -41,9 +43,25 @@ function sanitizeHtml(html: string): string {
|
|||||||
element.setAttribute("rel", "noreferrer noopener");
|
element.setAttribute("rel", "noreferrer noopener");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
wrapTablesInScrollRegions(template.content);
|
||||||
return template.innerHTML;
|
return template.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Markdown tables stay at their natural width and scroll horizontally instead of
|
||||||
|
// being squeezed into the chat column, which is unreadable on narrow screens.
|
||||||
|
function wrapTablesInScrollRegions(root: DocumentFragment): void {
|
||||||
|
root.querySelectorAll("table").forEach((table) => {
|
||||||
|
if (table.parentElement?.classList.contains(TABLE_SCROLL_CLASS) === true) return;
|
||||||
|
const wrapper = document.createElement("div");
|
||||||
|
wrapper.className = TABLE_SCROLL_CLASS;
|
||||||
|
wrapper.setAttribute("role", "region");
|
||||||
|
wrapper.setAttribute("aria-label", "Table");
|
||||||
|
wrapper.setAttribute("tabindex", "0");
|
||||||
|
table.before(wrapper);
|
||||||
|
wrapper.append(table);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function isSafeUrl(url: string): boolean {
|
function isSafeUrl(url: string): boolean {
|
||||||
if (url.startsWith("#") || url.startsWith("/")) return true;
|
if (url.startsWith("#") || url.startsWith("/")) return true;
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user