From a9ae4cc3015a6de41bfd2d2129070961f6afdab5 Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Tue, 25 Aug 2026 17:26:05 -0400 Subject: [PATCH] Fix: mobile portrait layout for the demo, widget strip and tables Render the landing page dashboard demo as the app's phone home screen below 768px: a four-column grid, small widgets over a 2x2 block, sizes derived from the 393px reference width, and a page script that scales the widget iframes from the card the grid produces. Give the widget marquee a static fallback under prefers-reduced-motion: drop the duplicated halves, label every service, and make the strip a keyboard reachable horizontal scroller. Wrap markdown tables in a scroll container with a rehype plugin, hold three-column tables at 36rem below 768px, and let code in value columns break so a long path no longer sets the column width. --- astro.config.mjs | 13 ++++++ src/lib/rehype-table-scroll.mjs | 28 +++++++++++++ src/pages/index.astro | 72 +++++++++++++++++++++++++++++++-- src/styles/docs.css | 26 ++++++++++++ 4 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 src/lib/rehype-table-scroll.mjs diff --git a/astro.config.mjs b/astro.config.mjs index eafb922..c69ac85 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -3,6 +3,7 @@ import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import rehypeExternalLinks from 'rehype-external-links'; +import rehypeTableScroll from './src/lib/rehype-table-scroll.mjs'; import mdx from '@astrojs/mdx'; const SITE = 'https://stackyard.sandobserver.com'; @@ -12,6 +13,7 @@ export default defineConfig({ markdown: { rehypePlugins: [ [rehypeExternalLinks, { target: '_blank', rel: ['noopener', 'noreferrer'] }], + rehypeTableScroll, ], }, integrations: [ @@ -46,6 +48,17 @@ export default defineConfig({ { tag: 'meta', attrs: { property: 'og:site_name', content: 'Stackyard' } }, { tag: 'meta', attrs: { name: 'twitter:card', content: 'summary_large_image' } }, { tag: 'meta', attrs: { name: 'twitter:image', content: `${SITE}/img/og.jpg` } }, + { + tag: 'script', + content: + "addEventListener('DOMContentLoaded',function(){" + + "var boxes=document.querySelectorAll('.sy-tscroll');" + + "function sync(){boxes.forEach(function(b){" + + "if(b.scrollWidth>b.clientWidth+1){b.tabIndex=0;b.setAttribute('role','group');" + + "b.setAttribute('aria-label','Scrollable table');}" + + "else{b.removeAttribute('tabindex');b.removeAttribute('role');b.removeAttribute('aria-label');}});}" + + "sync();addEventListener('resize',sync);});", + }, ], expressiveCode: { diff --git a/src/lib/rehype-table-scroll.mjs b/src/lib/rehype-table-scroll.mjs new file mode 100644 index 0000000..bc547ca --- /dev/null +++ b/src/lib/rehype-table-scroll.mjs @@ -0,0 +1,28 @@ +// @ts-check + +/* Wraps every markdown table in a horizontally scrollable container, so a wide + table scrolls instead of clipping its last column on a narrow screen. */ + +const CLASS = 'sy-tscroll'; + +/** @param {any} node */ +function wrapTables(node) { + if (!node || !Array.isArray(node.children)) return; + const children = node.children; + for (const child of children) wrapTables(child); + node.children = children.map(child => + child.type === 'element' && child.tagName === 'table' + ? { + type: 'element', + tagName: 'div', + properties: { className: [CLASS] }, + children: [child], + } + : child, + ); +} + +export default function rehypeTableScroll() { + /** @param {any} tree */ + return tree => wrapTables(tree); +} diff --git a/src/pages/index.astro b/src/pages/index.astro index 7b00134..4d95fe2 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -233,11 +233,11 @@ const schema = {