feat: match preview styling to xterm.js — palette, background, font, line-height
ANSI_COLORS: replaced with xterm.js default GTK/Tango palette. Background: #000000 on tile-body, sidebar-item-body, preview-popover. Font: 'SF Mono', 'Fira Code', Consolas, monospace (same as terminal). Line-height: 1.0 across all preview surfaces (xterm.js default). Gradient overlays: fade to #000 instead of theme bg. Result: previews are visually indistinguishable from the terminal.
This commit is contained in:
@@ -269,8 +269,8 @@ function escapeHtml(str) {
|
||||
// Converts terminal color sequences to <span> tags with inline styles.
|
||||
// ---------------------------------------------------------------------------
|
||||
var ANSI_COLORS = [
|
||||
'#000','#c23621','#25bc26','#adad27','#492ee1','#d338d3','#33bbc8','#cbcccd',
|
||||
'#818383','#fc391f','#31e722','#eaec23','#5833ff','#f935f8','#14f0f0','#e9ebeb'
|
||||
'#2e3436','#cc0000','#4e9a06','#c4a000','#3465a4','#75507b','#06989a','#d3d7cf',
|
||||
'#555753','#ef2929','#8ae234','#fce94f','#729fcf','#ad7fa8','#34e2e2','#eeeeec'
|
||||
];
|
||||
|
||||
function ansiToHtml(raw) {
|
||||
|
||||
+13
-10
@@ -221,6 +221,7 @@ body {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.tile-body pre {
|
||||
@@ -229,8 +230,9 @@ body {
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 6px 8px;
|
||||
font-family: var(--font-mono);
|
||||
font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
|
||||
font-size: 11px;
|
||||
line-height: 1.0;
|
||||
color: #c9d1d9; /* match xterm.js foreground */
|
||||
white-space: pre;
|
||||
overflow: hidden;
|
||||
@@ -257,7 +259,7 @@ body {
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 40px;
|
||||
background: linear-gradient(to bottom, transparent, var(--bg-tile));
|
||||
background: linear-gradient(to bottom, transparent, #000000);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -518,6 +520,7 @@ body {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.sidebar-item-body::before {
|
||||
@@ -527,13 +530,13 @@ body {
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 32px;
|
||||
background: linear-gradient(to bottom, transparent, var(--bg-secondary));
|
||||
background: linear-gradient(to bottom, transparent, #000000);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.sidebar-item--active .sidebar-item-body::before {
|
||||
background: linear-gradient(to bottom, transparent, var(--bg-surface));
|
||||
background: linear-gradient(to bottom, transparent, #000000);
|
||||
}
|
||||
|
||||
.sidebar-item-body pre {
|
||||
@@ -541,9 +544,9 @@ body {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-family: var(--font-mono);
|
||||
font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
|
||||
font-size: 10px;
|
||||
line-height: 1.4;
|
||||
line-height: 1.0;
|
||||
color: #c9d1d9; /* match xterm.js foreground */
|
||||
white-space: pre;
|
||||
padding: 0 8px 6px;
|
||||
@@ -966,7 +969,7 @@ body {
|
||||
.preview-popover {
|
||||
position: fixed;
|
||||
z-index: 500;
|
||||
background: var(--bg-secondary);
|
||||
background: #000000;
|
||||
border: 2px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
padding: 16px 20px;
|
||||
@@ -982,9 +985,9 @@ body {
|
||||
|
||||
.preview-popover pre {
|
||||
margin: 0;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.0;
|
||||
color: #c9d1d9; /* match xterm.js foreground exactly */
|
||||
white-space: pre-wrap; /* WRAP text instead of horizontal overflow */
|
||||
word-break: break-all; /* break long lines at viewport edge */
|
||||
|
||||
@@ -2114,4 +2114,17 @@ test('ansiToHtml converts SGR codes to styled spans', () => {
|
||||
assert.ok(source.includes('ansiToHtml(session.snapshot)'), 'overlay must use ansiToHtml');
|
||||
});
|
||||
|
||||
test('ANSI_COLORS uses xterm.js default GTK/Tango palette', () => {
|
||||
// xterm.js default palette (GTK/Tango-derived) — must match exactly
|
||||
// so previews render colors identically to the interactive terminal
|
||||
assert.strictEqual(app.ansi256Color(0), '#2e3436', 'color 0 must be xterm.js default: #2e3436');
|
||||
assert.strictEqual(app.ansi256Color(1), '#cc0000', 'color 1 must be xterm.js default: #cc0000');
|
||||
assert.strictEqual(app.ansi256Color(2), '#4e9a06', 'color 2 must be xterm.js default: #4e9a06');
|
||||
assert.strictEqual(app.ansi256Color(3), '#c4a000', 'color 3 must be xterm.js default: #c4a000');
|
||||
assert.strictEqual(app.ansi256Color(7), '#d3d7cf', 'color 7 must be xterm.js default: #d3d7cf');
|
||||
assert.strictEqual(app.ansi256Color(8), '#555753', 'color 8 must be xterm.js default: #555753');
|
||||
assert.strictEqual(app.ansi256Color(10), '#8ae234', 'color 10 must be xterm.js default: #8ae234');
|
||||
assert.strictEqual(app.ansi256Color(14), '#34e2e2', 'color 14 must be xterm.js default: #34e2e2');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@ def test_css_sidebar_item_body():
|
||||
|
||||
|
||||
def test_css_sidebar_item_body_pre():
|
||||
""".sidebar-item-body pre must be anchored to bottom with 10px monospace font using --font-mono token."""
|
||||
""".sidebar-item-body pre must be anchored to bottom with 10px monospace font matching xterm.js."""
|
||||
css = read_css()
|
||||
assert ".sidebar-item-body pre" in css
|
||||
block = _extract_rule_block(css, ".sidebar-item-body pre {")
|
||||
@@ -412,12 +412,12 @@ def test_css_sidebar_item_body_pre():
|
||||
assert "left: 0" in block
|
||||
assert "right: 0" in block
|
||||
assert "font-size: 10px" in block
|
||||
assert "line-height: 1.4" in block
|
||||
assert "line-height: 1.0" in block, "sidebar-item-body pre must use line-height: 1.0 (xterm.js default)"
|
||||
assert "#c9d1d9" in block, "sidebar-item-body pre must match xterm.js foreground"
|
||||
assert "white-space: pre" in block
|
||||
assert "padding: 0 8px 6px" in block
|
||||
# Monospace font family via design token
|
||||
assert "font-family: var(--font-mono)" in block
|
||||
# Explicit xterm.js font family (not design token variable)
|
||||
assert "'SF Mono'" in block or "SF Mono" in block, "sidebar-item-body pre must use explicit xterm.js font family"
|
||||
|
||||
|
||||
def test_css_sidebar_empty():
|
||||
@@ -640,3 +640,93 @@ def test_preview_popover_has_accent_border():
|
||||
end = css.index("}", start)
|
||||
block = css[start:end]
|
||||
assert "var(--accent)" in block, ".preview-popover must use var(--accent) border"
|
||||
|
||||
|
||||
def test_preview_popover_has_black_background():
|
||||
""".preview-popover must use #000000 background to match xterm.js terminal."""
|
||||
css = read_css()
|
||||
start = css.index(".preview-popover {")
|
||||
end = css.index("}", start)
|
||||
block = css[start:end]
|
||||
assert "#000000" in block or "background: #000" in block, (
|
||||
".preview-popover must use #000000 background (not var(--bg-secondary))"
|
||||
)
|
||||
|
||||
|
||||
def test_preview_popover_pre_matches_xterm_typography():
|
||||
""".preview-popover pre must match xterm.js terminal: 14px, line-height 1.0, explicit font stack."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".preview-popover pre {")
|
||||
assert "font-size: 14px" in block, ".preview-popover pre must use 14px (xterm.js default)"
|
||||
assert "line-height: 1.0" in block, ".preview-popover pre must use line-height: 1.0 (xterm.js default)"
|
||||
assert "'SF Mono'" in block or "SF Mono" in block, (
|
||||
".preview-popover pre must use explicit xterm.js font family"
|
||||
)
|
||||
|
||||
|
||||
def test_tile_body_has_black_background():
|
||||
""".tile-body must use #000000 background to match xterm.js terminal."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".tile-body {")
|
||||
assert "#000000" in block or "background: #000" in block, (
|
||||
".tile-body must use #000000 background to match xterm.js"
|
||||
)
|
||||
|
||||
|
||||
def test_tile_body_pre_has_xterm_line_height():
|
||||
""".tile-body pre must use line-height: 1.0 to match xterm.js terminal."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".tile-body pre {")
|
||||
assert "line-height: 1.0" in block, ".tile-body pre must use line-height: 1.0 (xterm.js default)"
|
||||
|
||||
|
||||
def test_tile_body_pre_has_explicit_font_family():
|
||||
""".tile-body pre must use explicit xterm.js font family, not CSS variable."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".tile-body pre {")
|
||||
assert "'SF Mono'" in block or "SF Mono" in block, (
|
||||
".tile-body pre must use explicit xterm.js font family"
|
||||
)
|
||||
|
||||
|
||||
def test_sidebar_item_body_has_black_background():
|
||||
""".sidebar-item-body must use #000000 background to match xterm.js terminal."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".sidebar-item-body {")
|
||||
assert "#000000" in block or "background: #000" in block, (
|
||||
".sidebar-item-body must use #000000 background to match xterm.js"
|
||||
)
|
||||
|
||||
|
||||
def test_sidebar_item_body_pre_has_xterm_line_height():
|
||||
""".sidebar-item-body pre must use line-height: 1.0 to match xterm.js terminal."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".sidebar-item-body pre {")
|
||||
assert "line-height: 1.0" in block, ".sidebar-item-body pre must use line-height: 1.0 (xterm.js default)"
|
||||
|
||||
|
||||
def test_sidebar_item_body_pre_has_explicit_font_family():
|
||||
""".sidebar-item-body pre must use explicit xterm.js font family, not CSS variable."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".sidebar-item-body pre {")
|
||||
assert "'SF Mono'" in block or "SF Mono" in block, (
|
||||
".sidebar-item-body pre must use explicit xterm.js font family"
|
||||
)
|
||||
|
||||
|
||||
def test_sidebar_item_body_gradient_fades_to_black():
|
||||
""".sidebar-item-body::before gradient must fade to #000000 (not theme background)."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".sidebar-item-body::before {")
|
||||
assert "#000000" in block or "transparent, #000" in block, (
|
||||
".sidebar-item-body::before gradient must fade to #000000 to match black terminal bg"
|
||||
)
|
||||
|
||||
|
||||
def test_tile_body_gradient_fades_to_black():
|
||||
""".tile-body::before gradient must fade to #000000 (not theme background)."""
|
||||
css = read_css()
|
||||
block = _extract_rule_block(css, ".tile-body::before {")
|
||||
assert "#000000" in block or "transparent, #000" in block, (
|
||||
".tile-body::before gradient must fade to #000000 to match black terminal bg"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user