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
1 change: 1 addition & 0 deletions docs/src/plugins/worktrunk-terminal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ export function pluginWorktrunkTerminal() {
color: var(--wt-ink-muted);
}
.expressive-code .frame.is-terminal .wt-terminal-gutter {
display: inline-block;
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
66 changes: 66 additions & 0 deletions docs/tests/browser-site.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,65 @@ 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],
`${theme} merge gutter rows moved — regenerate from quickstart_merge.snap`,
);
assert.equal(
homepageTerminalStyles.joins.length,
3,
`${theme} merge gutter run is no longer three adjacent joins`,
);
assert.ok(
homepageTerminalStyles.joins.every((gap) => Math.abs(gap) < 0.5),
`${theme} merge gutter does not sit flush between rows`,
);
Comment thread
max-sixty marked this conversation as 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 +390,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 +407,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