Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions docs/src/plugins/worktrunk-terminal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ export function pluginWorktrunkTerminal() {
color: var(--wt-ink-muted);
}
.expressive-code .frame.is-terminal .wt-terminal-gutter {
display: inline-block;
margin-block: -0.25em;
padding-block: 0.25em;
Comment thread
max-sixty marked this conversation as resolved.
Resolved
background: var(--wt-terminal-gutter);
}
.expressive-code .frame.is-terminal .wt-terminal-bold {
Expand Down
11 changes: 9 additions & 2 deletions docs/src/themes/worktrunk-code.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const baseTokenColors = (palette) => [
scope: ['string', 'constant.other.symbol', 'entity.other.inherited-class'],
settings: { foreground: palette.string },
},
{
name: 'Quoted shell strings',
scope: ['string.quoted.single.shell', 'string.quoted.double.shell'],
settings: { foreground: palette.quotedShellString },
},
{
name: 'Variables',
scope: ['variable', 'support.class', 'entity.name.class', 'entity.name.type.class'],
Expand Down Expand Up @@ -78,15 +83,16 @@ function theme(name, type, palette) {
};
}

// These are the syntax roles from the pre-Astro Worktrunk themes, adjusted only
// where the old foregrounds did not meet contrast on the current code surface.
// These roles follow the pre-Astro Worktrunk themes. Low-contrast colors and
// the shell-only quoted-string role use the current site's accessible palette.
export const worktrunkLightCodeTheme = theme('worktrunk-light', 'light', {
background: '#f8f7f6',
foreground: '#3d3632',
comment: '#6d6258',
keyword: '#9f4f2a',
function: '#9b6500',
string: '#527a16',
quotedShellString: '#1d4ed8',
variable: '#7e6247',
constant: '#a03c15',
support: '#9f4f2a',
Expand All @@ -101,6 +107,7 @@ export const worktrunkDarkCodeTheme = theme('worktrunk-dark', 'dark', {
keyword: '#d8b4fe',
function: '#e5b567',
string: '#a3be8c',
quotedShellString: '#93c5fd',
variable: '#d9a0a5',
constant: '#e09a82',
support: '#67d4d4',
Expand Down
58 changes: 58 additions & 0 deletions docs/tests/browser-site.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,57 @@ test('code artifacts keep their visual hierarchy in both themes', async () => {
await page.evaluate((selectedTheme) => {
document.documentElement.dataset.theme = selectedTheme;
}, theme);
const homepageTerminalStyles = await page.evaluate(() => {
const frames = [...document.querySelectorAll('.expressive-code .frame')];
const agentFrame = frames.find((candidate) => candidate.textContent.includes(
"wt switch -x claude -c feature-a -- 'Add user authentication'",
));
const mergeFrame = frames.find((candidate) => candidate.textContent.includes(
'Merging 1 commit to main',
));
const token = (text) => [...agentFrame.querySelectorAll('.code span')]
.find((candidate) => candidate.textContent === text);
const outputLines = [...mergeFrame.querySelectorAll('.ec-line.wt-output')];
const gutters = outputLines.map((line, index) => ({
index,
gutter: line.querySelector('.wt-terminal-gutter'),
})).filter(({ gutter }) => gutter);
const joins = gutters.slice(1).flatMap((current, index) => (
current.index === gutters[index].index + 1
? [current.gutter.getBoundingClientRect().top
- gutters[index].gutter.getBoundingClientRect().bottom]
: []
));
const pre = agentFrame.querySelector('pre');
return {
argument: getComputedStyle(token('feature-a')).color,
background: getComputedStyle(pre).backgroundColor,
gutterIndexes: gutters.map(({ index }) => index),
joins,
lineHeights: outputLines.map((line) => line.getBoundingClientRect().height),
quoted: getComputedStyle(token("'Add user authentication'")).color,
};
});
assert.notEqual(
homepageTerminalStyles.argument,
homepageTerminalStyles.quoted,
`${theme} quoted shell string uses the argument color`,
);
assert.ok(
contrastRatio(homepageTerminalStyles.quoted, homepageTerminalStyles.background) >= 4.5,
`${theme} quoted shell string falls below 4.5:1 contrast`,
);
assert.deepEqual(homepageTerminalStyles.gutterIndexes, [1, 4, 5, 6, 7]);
assert.equal(homepageTerminalStyles.joins.length, 3);
Comment thread
max-sixty marked this conversation as resolved.
Resolved
assert.ok(
homepageTerminalStyles.joins.every((gap) => gap <= 0),
`${theme} merge gutter has a visible gap between rows`,
);
Comment thread
max-sixty marked this conversation as resolved.
Resolved
assert.equal(
new Set(homepageTerminalStyles.lineHeights).size,
1,
`${theme} gutter padding changes terminal line height`,
);
const comparisonStyles = await page.evaluate(() => {
const table = document.querySelector('.cmd-compare');
return {
Expand Down Expand Up @@ -331,6 +382,8 @@ test('code artifacts keep their visual hierarchy in both themes', async () => {
titleBackground: getComputedStyle(title).backgroundColor,
codeBackground: getComputedStyle(pre).backgroundColor,
accentWidth: getComputedStyle(pre).borderInlineStartWidth,
stringColor: getComputedStyle([...frame.querySelectorAll('.code span')]
.find((span) => span.textContent === '".worktrees/{{ branch | sanitize }}"')).color,
};
});
assert.equal(fileFrame.title, '~/.config/worktrunk/config.toml');
Expand All @@ -346,6 +399,11 @@ test('code artifacts keep their visual hierarchy in both themes', async () => {
);
const titleContrast = contrastRatio(fileFrame.titleColor, fileFrame.titleBackground);
assert.ok(titleContrast >= 4.5, `${theme} file-label contrast is ${titleContrast.toFixed(2)}:1`);
assert.notEqual(
fileFrame.stringColor,
homepageTerminalStyles.quoted,
`${theme} shell quote color leaks into TOML strings`,
);
assert.equal(fileFrame.accentWidth, '3px');
await page.close();
}
Expand Down
Loading