{{! Root template }}
{{~#*inline "root"}}
<!-- Created with {{{creator.name}}} v{{{creator.version}}} ({{{creator.repo}}}) -->
<svg viewBox="0 {{#if window}}-{{const.WINDOW_FRAME_HEIGHT}}{{else}}0{{/if}} {{width}} {{height}}" width="{{width}}" height="{{height}}" xmlns="http://www.w3.org/2000/svg">
<switch>
<g requiredExtensions="http://www.w3.org/1999/xhtml">
{{>styles}}
{{>background}}
{{~>content}}
{{~#if scroll_animation}}
{{>scrollbar}}
{{>scroll_animation}}
{{/if}}
</g>
{{>unsupported_error}}
</switch>
</svg>
{{/inline~}}
{{! NB. The warning text should fit in one 80-char line to not potentially overflow the viewbox. }}
{{~#*inline "unsupported_error"}}
<text x="10" y="{{line_height}}" style="font: {{const.FONT_SIZE}}px monospace; fill: {{ palette.colors.red }};">
HTML embedding not supported.
Consult <tspan style="text-decoration: underline; text-decoration-thickness: 1px;"><a href="https://github.com/slowli/term-transcript/blob/HEAD/FAQ.md">term-transcript docs</a></tspan> for details.
</text>
{{/inline~}}
{{! CSS definitions }}
{{~#*inline "styles"}}
<style>
{{>common_styles_header}}
.container {
padding: 0 {{const.WINDOW_PADDING}}px;
color: {{ palette.colors.white }};
line-height: {{line_height}}px;
}
.container pre {
padding: 0;
margin: 0;
font: {{const.FONT_SIZE}}px {{#if embedded_font}}"{{embedded_font.family_name}}", monospace{{else}}{{font_family}}{{/if}};
line-height: inherit;
}
.input {
{{#if line_numbers~}}
{{~#if (eq line_numbers.scope "continuous")}}
display: flex;
{{/if~}}
{{~/if}}
margin: 0 -{{const.WINDOW_PADDING}}px {{const.BLOCK_MARGIN}}px;
color: {{ palette.colors.white }};
background: rgba(255, 255, 255, 0.1);
padding: 2px {{const.WINDOW_PADDING}}px;
}
.input-hidden { display: none; }
{{#if line_numbers}}{{#if (eq line_numbers.scope "continuous")~}}
.input > pre { flex-grow: 1; }
{{/if}}{{/if~}}
.output { {{#if line_numbers}}display: flex; {{/if}}margin-bottom: {{const.BLOCK_MARGIN}}px; }
{{#if line_numbers}}
.output > pre { flex-grow: 1; }
pre.line-numbers {
flex-grow: 0;
width: {{const.LN_WIDTH}}px;
text-align: right;
padding-right: {{const.LN_PADDING}}px;
color: color-mix(in hsl, currentColor 35%, {{ palette.colors.black }});
user-select: none;
}
{{/if}}
.output-sep {
margin: -{{div const.BLOCK_MARGIN 2}}px -{{const.WINDOW_PADDING}}px {{sub (div const.BLOCK_MARGIN 2) 1}}px;
border-top: 1px solid color-mix(in hsl, {{ palette.colors.white }} 35%, {{ palette.colors.black }});
}
{{#if has_failures~}}
.input-failure {
border-left: 2px solid {{ palette.colors.red }};
border-right: 2px solid {{ palette.colors.red }};
background: rgba(255, 0, 65, 0.15);
}
{{/if}}
{{~#if scroll_animation}}
.scrollbar { fill: #fff; fill-opacity: 0.35; }
{{/if}}
{{>common_font_styles}}
{{!
For opacity-related styling (.dimmed, .blink), text decoration must be applied to the child <span>,
so that it has the correct opacity.
}}
.underline:not(.dimmed, .blink), .underline:is(.dimmed, .blink) > span { text-decoration-line: underline; }
.strike:not(.dimmed, .blink), .strike:is(.dimmed, .blink) > span { text-decoration-line: line-through; }
.underline.strike:not(.dimmed, .blink), .underline.strike:is(.dimmed, .blink) > span { text-decoration-line: underline line-through; }
{{!
The dimmed-related complexity is motivated by Safari quirks; it doesn't render HTML-in-SVG with any filters
(incl. opacity) correctly.
}}
{{#scope opacity=(round (mul 100 dim_opacity) digits=1)}}
.dimmed > span { color: color-mix(in hsl, currentColor {{@opacity}}%, transparent); }
{{! Overlay the default background color with the complementary opacity }}
.dimmed-bg > span { background: rgb(from {{ palette.colors.black }} r g b / {{round (sub 100 @opacity) digits=1}}%); }
{{/scope}}
{{! Only text is concealed, background is not }}
.concealed { color: rgba(0, 0, 0, 0) !important; }
{{#if (lt blink.opacity 1)}}
@keyframes blink {
0% { color: currentColor; background: transparent; }
100% {
color: color-mix(in hsl, currentColor {{round (mul 100 blink.opacity) digits=1}}%, transparent);
background: rgb(from {{ palette.colors.black }} r g b / {{round (mul 100 (sub 1 blink.opacity)) digits=1}}%);
}
}
.blink > span { animation: {{mul 2 blink.interval}}s steps(2, jump-none) 0s infinite blink; }
{{/if}}
{{#if wrap}}
.hard-br { margin-left: 8px; }
{{#with wrap.hard_break_at.mark as |mark|}}
.hard-br:before {
content: '{{mark}}';
color: color-mix(in hsl, currentColor 60%, {{ ../palette.colors.black }});
}
{{else}}{{/with~}}
{{~#with line_numbers.continued.mark as |mark|}}
.line-numbers .cont { margin-right: -3px; }
.line-numbers .cont:before { content: '{{mark}}'; }
{{else}}{{/with~}}
{{~/if~}}
.line { display: block; }
.line span { display: inline-block; text-decoration-thickness: 1px; }
.fg0,.inv.fg-none { color: {{ palette.colors.black }}; } .bg0 { background: {{ palette.colors.black }}; }
.fg1 { color: {{ palette.colors.red }}; } .bg1 { background: {{ palette.colors.red }}; }
.fg2 { color: {{ palette.colors.green }}; } .bg2 { background: {{ palette.colors.green }}; }
.fg3 { color: {{ palette.colors.yellow }}; } .bg3 { background: {{ palette.colors.yellow }}; }
.fg4 { color: {{ palette.colors.blue }}; } .bg4 { background: {{ palette.colors.blue }}; }
.fg5 { color: {{ palette.colors.magenta }}; } .bg5 { background: {{ palette.colors.magenta }}; }
.fg6 { color: {{ palette.colors.cyan }}; } .bg6 { background: {{ palette.colors.cyan }}; }
.fg7 { color: {{ palette.colors.white }}; } .bg7,.inv.bg-none { background: {{ palette.colors.white }}; }
.fg8 { color: {{ palette.intense_colors.black }}; } .bg8 { background: {{ palette.intense_colors.black }}; }
.fg9 { color: {{ palette.intense_colors.red }}; } .bg9 { background: {{ palette.intense_colors.red }}; }
.fg10 { color: {{ palette.intense_colors.green }}; } .bg10 { background: {{ palette.intense_colors.green }}; }
.fg11 { color: {{ palette.intense_colors.yellow }}; } .bg11 { background: {{ palette.intense_colors.yellow }}; }
.fg12 { color: {{ palette.intense_colors.blue }}; } .bg12 { background: {{ palette.intense_colors.blue }}; }
.fg13 { color: {{ palette.intense_colors.magenta }}; } .bg13 { background: {{ palette.intense_colors.magenta }}; }
.fg14 { color: {{ palette.intense_colors.cyan }}; } .bg14 { background: {{ palette.intense_colors.cyan }}; }
.fg15 { color: {{ palette.intense_colors.white }}; } .bg15 { background: {{ palette.intense_colors.white }}; }
</style>
{{/inline~}}
{{~#*inline "content"}}
{{~#scope line_number=1}}
<svg{{#if scroll_animation}} id="scroll-container"{{/if}} x="0" y="{{const.WINDOW_PADDING}}" width="{{width}}" height="{{screen_height}}" viewBox="0 0 {{width}} {{screen_height}}" overflow="hidden">
<foreignObject width="{{width}}" height="{{content_height}}">
<div xmlns="http://www.w3.org/1999/xhtml" class="container">
{{~#each interactions}}
<div class="input{{#if failure}} input-failure{{/if}}{{#if input.hidden}} input-hidden{{/if}}"
{{~#if (ne exit_status null)}} data-exit-status="{{exit_status}}"{{/if~}}
{{~#if failure}} title="This command exited with non-zero code"{{/if}}>
{{~#if ../line_numbers~}}
{{~#if (and (eq ../line_numbers.scope "continuous") (not input.hidden))~}}
<pre class="line-numbers">
{{~#each (range 0 (count_lines input.text))~}}
{{add this @../../line_number}}{{#if (not @last)}}<br/>{{/if}}
{{~/each~}}
</pre>
{{~set @../line_number (add @../line_number (count_lines input.text))~}}
{{~/if~}}
{{~/if~}}
<pre><span class="prompt">{{ input.prompt }}</span> {{ input.text }}</pre></div>
{{#if (and (not @first) input.hidden)~}}
<div class="output-sep"></div>
{{~/if}}
<div class="output">
{{~#if ../line_numbers~}}
{{~#if (eq ../line_numbers.scope "each_output")~}}
{{~set @../line_number 1 ~}}
{{~/if~}}
<pre class="line-numbers">
{{~#scope skip_line_number=false ~}}
{{~#each output as |line|~}}
{{~#if (not @../skip_line_number)~}}
{{@../../line_number}}
{{~set @../../line_number (add 1 @../../line_number)~}}
{{~else~}}
{{~#if ../../line_numbers.continued.mark}}<b class="cont"></b>{{/if~}}
{{~/if~}}
{{~#if @last}}{{else}}<br/>{{/if~}}
{{~set @../skip_line_number (and line.br (ne ../../line_numbers.continued "inherit"))~}}
{{~/each~}}
{{~/scope~}}
</pre>
{{~/if~}}
<pre>
{{~#each output as |line|~}}
<span class="line">
{{~#each line.spans as |span|~}}
{{~>html_span span~}}
{{~else~}}{{! The line may be empty }}
{{~/each~}}
{{~#if line.br}}<b class="hard-br"></b>{{/if~}}
{{! Add a newline in order to make the text correctly copyable }}
{{~#if (not @last)}}
{{/if~}}
</span>
{{~else~}}{{! The output may be empty }}
{{~/each~}}
</pre></div>
{{~/each}}
</div>
</foreignObject>
</svg>
{{/scope}}
{{/inline~}}
{{~#*inline "main"~}}
{{#scope
content_height=0
scroll_animation=null
screen_height=0
height=0
width=width
line_height=0
}}
{{~#set @line_height}}{{>compute_line_height}}{{/set~}}
{{~#debug line_height=@line_height}}computed line height{{/debug~}}
{{~#set @content_height~}}
{{~>compute_content_height this line_height=@line_height ~}}
{{~/set~}}
{{~set @content_height (round @content_height digits=1)~}}
{{~#debug content_height=@content_height}}computed content height{{/debug~}}
{{~#if line_numbers~}}
{{! Adjust width to take line numbers into account }}
{{~set @width (add width const.LN_WIDTH const.LN_PADDING)~}}
{{~/if~}}
{{~#if scroll~}}
{{~#set @scroll_animation~}}
{{~>compute_scroll_animation this width=@width content_height=@content_height~}}
{{~/set~}}
{{~/if~}}
{{~#if @scroll_animation~}}
{{set @screen_height scroll.max_height}}
{{~else~}}
{{set @screen_height @content_height}}
{{~/if~}}
{{~set @height (add @screen_height (mul const.WINDOW_PADDING 2))~}}
{{~#if window~}}
{{set @height (add @height const.WINDOW_FRAME_HEIGHT)}}
{{~/if~}}
{{>root (splat_vars this)~}} {{! <-- All rendering happens here }}
{{/scope}}
{{~/inline~}}
{{~>_common~}}