Skip to content
Open
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
35 changes: 31 additions & 4 deletions src/renderer/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -3219,14 +3219,41 @@ body,
max-width: 100%;
}

.term-md__content table {
/* Tables in rendered Markdown — the ⌘M output view, the editor preview and the ⌘M chat view (its
messages and plan/question cards all render through `.term-chat__text`). Gridlines strong enough
to read (`--border` is a 10% separator, which made cells blur together), a tinted header row,
and a horizontal scroll inside the table for one wider than the view, so the thread never
scrolls sideways. A column's `:---:` alignment arrives as an `align` attribute, which an author
`text-align` would override — so only a header WITHOUT one is set (to the start edge, matching
its cells, instead of the browser's centred default). */
.term-md__content table,
.term-chat__text table {
display: block;
width: max-content;
max-width: 100%;
overflow-x: auto;
border-collapse: collapse;
margin: 0 0 10px;
}

.term-md__content th,
.term-md__content td {
border: 1px solid var(--border);
padding: 4px 8px;
.term-md__content td,
.term-chat__text th,
.term-chat__text td {
border: 1px solid rgba(var(--tint-rgb), 0.22);
padding: 4px 10px;
vertical-align: top;
}

.term-md__content th,
.term-chat__text th {
background: rgba(var(--tint-rgb), 0.06);
font-weight: 600;
}

.term-md__content th:not([align]),
.term-chat__text th:not([align]) {
text-align: start;
}

/* Chat panel — replaces the markdown overlay on chat-capable agent nodes (Cmd+M). */
Expand Down
46 changes: 46 additions & 0 deletions src/renderer/styles.markdown-table.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest'
import { readFileSync } from 'node:fs'
import { join } from 'node:path'

/**
* Rendered-Markdown tables get gridlines in every reading view. The chat view had no table rules
* at all (cells ran together with no lines), and the output view's lines used the 10% separator
* token. One rule group now covers both containers; this pins that neither drops out of it.
*/
const CSS = readFileSync(join(__dirname, 'styles.css'), 'utf8').replace(/\r\n/g, '\n')

/** The body of the rule whose selector list is exactly `selectors` (joined by `,\n`). */
function group(selectors: string[]): string {
const head = `${selectors.join(',\n')} {`
const at = CSS.indexOf(`\n${head}`)
if (at < 0) throw new Error(`no rule for ${selectors.join(', ')}`)
return CSS.slice(at, CSS.indexOf('}', at))
}

describe('Markdown table gridlines', () => {
it('every cell of both views has a visible border', () => {
const cells = group(['.term-md__content th', '.term-md__content td', '.term-chat__text th', '.term-chat__text td'])

expect(cells).toMatch(/border:\s*1px solid rgba\(var\(--tint-rgb\), 0\.22\)/)
})

it('header cells are tinted in both views', () => {
expect(group(['.term-md__content th', '.term-chat__text th'])).toMatch(/background:/)
})

it('a wide table scrolls inside itself in both views', () => {
const table = group(['.term-md__content table', '.term-chat__text table'])

expect(table).toMatch(/border-collapse:\s*collapse/)
expect(table).toMatch(/overflow-x:\s*auto/)
expect(table).toMatch(/max-width:\s*100%/)
})

it('leaves text-align to the Markdown column alignment, start-aligning only unaligned headers', () => {
const cells = group(['.term-md__content th', '.term-md__content td', '.term-chat__text th', '.term-chat__text td'])
const unaligned = group(['.term-md__content th:not([align])', '.term-chat__text th:not([align])'])

expect(cells).not.toMatch(/text-align/)
expect(unaligned).toMatch(/text-align:\s*start/)
})
})
Loading