diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 75c7b973f..7ca7c4251 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -26,10 +26,12 @@ from rich.style import Style from . import errors from ._cells import cell_len from ._loop import loop_last -from ._types import Lines +from .strip import Strip +from ._types import Strips from ._typing import TypeAlias from .geometry import NULL_OFFSET, Offset, Region, Size + if TYPE_CHECKING: from .widget import Widget @@ -66,8 +68,8 @@ CompositorMap: TypeAlias = "dict[Widget, MapGeometry]" class LayoutUpdate: """A renderable containing the result of a render for a given region.""" - def __init__(self, lines: Lines, region: Region) -> None: - self.lines = lines + def __init__(self, strips: Strips, region: Region) -> None: + self.strips = strips self.region = region def __rich_console__( @@ -76,7 +78,7 @@ class LayoutUpdate: x = self.region.x new_line = Segment.line() move_to = Control.move_to - for last, (y, line) in loop_last(enumerate(self.lines, self.region.y)): + for last, (y, line) in loop_last(enumerate(self.strips, self.region.y)): yield move_to(x, y) yield from line if not last: @@ -92,7 +94,7 @@ class ChopsUpdate: def __init__( self, - chops: list[dict[int, list[Segment] | None]], + chops: list[dict[int, Strip | None]], spans: list[tuple[int, int, int]], chop_ends: list[list[int]], ) -> None: @@ -121,9 +123,9 @@ class ChopsUpdate: for y, x1, x2 in self.spans: line = chops[y] ends = chop_ends[y] - for end, (x, segments) in zip(ends, line.items()): + for end, (x, strip) in zip(ends, line.items()): # TODO: crop to x extents - if segments is None: + if strip is None: continue if x > x2 or end <= x1: @@ -131,10 +133,10 @@ class ChopsUpdate: if x2 > x >= x1 and end <= x2: yield move_to(x, y) - yield from segments + yield from strip continue - iter_segments = iter(segments) + iter_segments = iter(strip) if x < x1: for segment in iter_segments: next_x = x + _cell_len(segment.text) @@ -635,7 +637,7 @@ class Compositor: def _get_renders( self, crop: Region | None = None - ) -> Iterable[tuple[Region, Region, Lines]]: + ) -> Iterable[tuple[Region, Region, Strips]]: """Get rendered widgets (lists of segments) in the composition. Returns: @@ -685,19 +687,21 @@ class Compositor: _Region(delta_x, delta_y, new_width, new_height) ) - @classmethod - def _assemble_chops( - cls, chops: list[dict[int, list[Segment] | None]] - ) -> list[list[Segment]]: - """Combine chops in to lines.""" - from_iterable = chain.from_iterable - segment_lines: list[list[Segment]] = [ - list(from_iterable(line for line in bucket.values() if line is not None)) - for bucket in chops - ] - return segment_lines + # @classmethod + # def _assemble_chops(cls, chops: list[dict[int, Strip | None]]) -> list[Strip]: + # """Combine chops in to lines.""" - def render(self, full: bool = False) -> RenderableType | None: + # [Strip.join(strips) for strips in chops] + + # from_iterable = chain.from_iterable + + # segment_lines: list[list[Segment]] = [ + # list(from_iterable(strip for strip in bucket.values() if strip is not None)) + # for bucket in chops + # ] + # return segment_lines + + def render(self, full: bool = False) -> RenderableType: """Render a layout. Returns: @@ -728,8 +732,6 @@ class Compositor: else: return None - divide = Segment.divide - # Maps each cut on to a list of segments cuts = self.cuts @@ -738,19 +740,19 @@ class Compositor: "Callable[[list[int]], dict[int, list[Segment] | None]]", dict.fromkeys ) # A mapping of cut index to a list of segments for each line - chops: list[dict[int, list[Segment] | None]] + chops: list[dict[int, Strip | None]] chops = [fromkeys(cut_set[:-1]) for cut_set in cuts] - cut_segments: Iterable[list[Segment]] + cut_strips: Iterable[Strip] # Go through all the renders in reverse order and fill buckets with no render renders = self._get_renders(crop) intersection = Region.intersection - for region, clip, lines in renders: + for region, clip, strips in renders: render_region = intersection(region, clip) - for y, line in zip(render_region.line_range, lines): + for y, strip in zip(render_region.line_range, strips): if not is_rendered_line(y): continue @@ -763,20 +765,20 @@ class Compositor: ] if len(final_cuts) <= 2: # Two cuts, which means the entire line - cut_segments = [line] + cut_strips = [strip] else: render_x = render_region.x relative_cuts = [cut - render_x for cut in final_cuts[1:]] - cut_segments = divide(line, relative_cuts) + cut_strips = list(strip.divide(relative_cuts)) # Since we are painting front to back, the first segments for a cut "wins" - for cut, segments in zip(final_cuts, cut_segments): + for cut, segments in zip(final_cuts, cut_strips): if chops_line[cut] is None: chops_line[cut] = segments if full: - render_lines = self._assemble_chops(chops) - return LayoutUpdate(render_lines, screen_region) + render_strips = [Strip.join(chop.values()) for chop in chops] + return LayoutUpdate(render_strips, screen_region) else: chop_ends = [cut_set[1:] for cut_set in cuts] return ChopsUpdate(chops, spans, chop_ends) diff --git a/src/textual/_segment_tools.py b/src/textual/_segment_tools.py index b2e4a13f7..abb783496 100644 --- a/src/textual/_segment_tools.py +++ b/src/textual/_segment_tools.py @@ -10,7 +10,7 @@ from rich.segment import Segment from rich.style import Style from ._cells import cell_len -from ._types import Lines +from ._types import Strips from .css.types import AlignHorizontal, AlignVertical from .geometry import Size @@ -22,8 +22,8 @@ def line_crop( Args: segments (list[Segment]): A list of Segments for a line. - start (int): Start offset - end (int): End offset (exclusive) + start (int): Start offset (cells) + end (int): End offset (cells, exclusive) total (int): Total cell length of segments. Returns: list[Segment]: A new shorter list of segments @@ -130,7 +130,7 @@ def line_pad( def align_lines( - lines: Lines, + lines: Strips, style: Style, size: Size, horizontal: AlignHorizontal, @@ -153,7 +153,7 @@ def align_lines( width, height = size shape_width, shape_height = Segment.get_shape(lines) - def blank_lines(count: int) -> Lines: + def blank_lines(count: int) -> Strips: return [[Segment(" " * width, style)]] * count top_blank_lines = bottom_blank_lines = 0 diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index 8b4e62996..e99c289fd 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -11,12 +11,13 @@ from ._border import get_box, render_row from ._filter import LineFilter from ._opacity import _apply_opacity from ._segment_tools import line_crop, line_pad, line_trim -from ._types import Lines +from ._types import Strips from ._typing import TypeAlias from .color import Color from .geometry import Region, Size, Spacing from .renderables.text_opacity import TextOpacity from .renderables.tint import Tint +from .strip import Strip if TYPE_CHECKING: from .css.styles import StylesBase @@ -25,35 +26,6 @@ if TYPE_CHECKING: RenderLineCallback: TypeAlias = Callable[[int], List[Segment]] -def style_links( - segments: Iterable[Segment], link_id: str, link_style: Style -) -> list[Segment]: - """Apply a style to the given link id. - - Args: - segments (Iterable[Segment]): Segments. - link_id (str): A link id. - link_style (Style): Style to apply. - - Returns: - list[Segment]: A list of new segments. - """ - - _Segment = Segment - - segments = [ - _Segment( - text, - (style + link_style if style is not None else None) - if (style and not style._null and style._link_id == link_id) - else style, - control, - ) - for text, style, control in segments - ] - return segments - - @lru_cache(1024 * 8) def make_blank(width, style: Style) -> Segment: """Make a blank segment. @@ -95,7 +67,7 @@ class StylesCache: """ def __init__(self) -> None: - self._cache: dict[int, list[Segment]] = {} + self._cache: dict[int, Strip] = {} self._dirty_lines: set[int] = set() self._width = 1 @@ -123,7 +95,7 @@ class StylesCache: self._cache.clear() self._dirty_lines.clear() - def render_widget(self, widget: Widget, crop: Region) -> Lines: + def render_widget(self, widget: Widget, crop: Region) -> list[Strip]: """Render the content for a widget. Args: @@ -135,7 +107,7 @@ class StylesCache: """ base_background, background = widget.background_colors styles = widget.styles - lines = self.render( + strips = self.render( styles, widget.region.size, base_background, @@ -147,7 +119,6 @@ class StylesCache: filter=widget.app._filter, ) if widget.auto_links: - _style_links = style_links hover_style = widget.hover_style link_hover_style = widget.link_hover_style if ( @@ -157,12 +128,12 @@ class StylesCache: and "@click" in hover_style.meta ): if link_hover_style: - lines = [ - _style_links(line, hover_style.link_id, link_hover_style) - for line in lines + strips = [ + strip.style_links(hover_style.link_id, link_hover_style) + for strip in strips ] - return lines + return strips def render( self, @@ -175,7 +146,7 @@ class StylesCache: padding: Spacing | None = None, crop: Region | None = None, filter: LineFilter | None = None, - ) -> Lines: + ) -> list[Strip]: """Render a widget content plus CSS styles. Args: @@ -202,15 +173,14 @@ class StylesCache: if width != self._width: self.clear() self._width = width - lines: Lines = [] - add_line = lines.append - simplify = Segment.simplify + strips: list[Strip] = [] + add_strip = strips.append is_dirty = self._dirty_lines.__contains__ render_line = self.render_line for y in crop.line_range: if is_dirty(y) or y not in self._cache: - line = render_line( + strip = render_line( styles, y, size, @@ -220,21 +190,19 @@ class StylesCache: background, render_content_line, ) - line = list(simplify(line)) - self._cache[y] = line + self._cache[y] = strip else: - line = self._cache[y] + strip = self._cache[y] if filter: - line = filter.filter(line) - add_line(line) + strip = strip.apply_filter(filter) + add_strip(strip) self._dirty_lines.difference_update(crop.line_range) if crop.column_span != (0, width): - _line_crop = line_crop x1, x2 = crop.column_span - lines = [_line_crop(line, x1, x2, width) for line in lines] + strips = [strip.crop(x1, x2) for strip in strips] - return lines + return strips def render_line( self, @@ -246,7 +214,7 @@ class StylesCache: base_background: Color, background: Color, render_content_line: RenderLineCallback, - ) -> list[Segment]: + ) -> Strip: """Render a styled line. Args: @@ -402,4 +370,5 @@ class StylesCache: else: line = [*line, right] - return post(line) + strip = Strip(post(line), width) + return strip diff --git a/src/textual/_types.py b/src/textual/_types.py index cfb4af035..4df812b89 100644 --- a/src/textual/_types.py +++ b/src/textual/_types.py @@ -2,10 +2,12 @@ from typing import Awaitable, Callable, List, TYPE_CHECKING, Union from rich.segment import Segment -from textual._typing import Protocol +from ._typing import Protocol + if TYPE_CHECKING: from .message import Message + from .strip import Strip class MessageTarget(Protocol): @@ -27,5 +29,5 @@ class EventTarget(Protocol): ... -Lines = List[List[Segment]] +Strips = List["Strip"] CallbackType = Union[Callable[[], Awaitable[None]], Callable[[], None]] diff --git a/src/textual/scroll_view.py b/src/textual/scroll_view.py index e6e692480..0c8abd0bf 100644 --- a/src/textual/scroll_view.py +++ b/src/textual/scroll_view.py @@ -30,6 +30,16 @@ class ScrollView(Widget): """Not transparent, i.e. renders something.""" return False + def watch_scroll_x(self, new_value: float) -> None: + if self.show_horizontal_scrollbar: + self.horizontal_scrollbar.position = int(new_value) + self.refresh() + + def watch_scroll_y(self, new_value: float) -> None: + if self.show_vertical_scrollbar: + self.vertical_scrollbar.position = int(new_value) + self.refresh() + def on_mount(self): self._refresh_scrollbars() @@ -68,6 +78,8 @@ class ScrollView(Widget): virtual_size (Size): New virtual size. container_size (Size): New container size. """ + if self._size != size or container_size != container_size: + self.refresh() if ( self._size != size or virtual_size != self.virtual_size @@ -77,9 +89,7 @@ class ScrollView(Widget): virtual_size = self.virtual_size self._container_size = size - self.styles.gutter.totals self._scroll_update(virtual_size) - self.scroll_to(self.scroll_x, self.scroll_y, animate=False) - self.refresh() def render(self) -> RenderableType: """Render the scrollable region (if `render_lines` is not implemented). diff --git a/src/textual/strip.py b/src/textual/strip.py new file mode 100644 index 000000000..77078ebcc --- /dev/null +++ b/src/textual/strip.py @@ -0,0 +1,181 @@ +from __future__ import annotations + +from itertools import chain +from typing import Iterator, Iterable, Sequence + +import rich.repr +from rich.cells import cell_len, set_cell_size +from rich.segment import Segment +from rich.style import Style + +from ._filter import LineFilter +from ._segment_tools import line_crop + +from ._profile import timer + + +@rich.repr.auto +class Strip: + __slots__ = ["_segments", "_cell_length", "_divide_cache"] + + def __init__( + self, segments: Iterable[Segment], cell_length: int | None = None + ) -> None: + self._segments = list(segments) + self._cell_length = cell_length + self._divide_cache: dict[tuple[int], list[Strip]] = {} + + def __rich_repr__(self) -> rich.repr.Result: + yield self._segments + yield self.cell_length + + @property + def cell_length(self) -> int: + """Get the number of cells required to render this object.""" + # Done on demand and cached, as this is an O(n) operation + if self._cell_length is None: + self._cell_length = Segment.get_line_length(self._segments) + return self._cell_length + + @classmethod + def join(cls, strips: Iterable[Strip | None]) -> Strip: + + segments: list[list[Segment]] = [] + add_segments = segments.append + total_cell_length = 0 + for strip in strips: + if strip is None: + continue + total_cell_length += strip.cell_length + add_segments(strip._segments) + strip = cls(chain.from_iterable(segments), total_cell_length) + return strip + + def __bool__(self) -> bool: + return bool(self._segments) + + def __iter__(self) -> Iterator[Segment]: + return iter(self._segments) + + def __len__(self) -> int: + return len(self._segments) + + def __eq__(self, strip: Strip) -> bool: + return ( + self._segments == strip._segments and self.cell_length == strip.cell_length + ) + + def adjust_line_length(self, cell_length: int, style: Style | None) -> Strip: + + new_line: list[Segment] + line = self._segments + current_cell_length = self.cell_length + + _Segment = Segment + + if current_cell_length < cell_length: + new_line = line + [ + _Segment(" " * (cell_length - current_cell_length), style) + ] + + elif current_cell_length > cell_length: + new_line = [] + append = new_line.append + line_length = 0 + for segment in line: + segment_length = segment.cell_length + if line_length + segment_length < cell_length: + append(segment) + line_length += segment_length + else: + text, segment_style, _ = segment + text = set_cell_size(text, cell_length - line_length) + append(_Segment(text, segment_style)) + break + else: + return self + + return Strip(new_line, cell_length) + + def simplify(self) -> Strip: + line = Strip( + Segment.simplify(self._segments), + self._cell_length, + ) + return line + + def apply_filter(self, filter: LineFilter) -> Strip: + return Strip(filter.filter(self._segments), self._cell_length) + + def style_links(self, link_id: str, link_style: Style) -> Strip: + _Segment = Segment + if not any( + segment.style._link_id == link_id + for segment in self._segments + if segment.style + ): + return self + segments = [ + _Segment( + text, + (style + link_style if style is not None else None) + if (style and not style._null and style._link_id == link_id) + else style, + control, + ) + for text, style, control in self._segments + ] + return Strip(segments, self._cell_length) + + def crop(self, start: int, end: int) -> Strip: + _cell_len = cell_len + pos = 0 + output_segments: list[Segment] = [] + add_segment = output_segments.append + iter_segments = iter(self._segments) + segment: Segment | None = None + for segment in iter_segments: + end_pos = pos + _cell_len(segment.text) + if end_pos > start: + segment = segment.split_cells(start - pos)[1] + break + pos = end_pos + else: + return Strip([], 0) + + if end >= self.cell_length: + # The end crop is the end of the segments, so we can collect all remaining segments + if segment: + add_segment(segment) + output_segments.extend(iter_segments) + return Strip(output_segments, self.cell_length - start) + + pos = start + while segment is not None: + end_pos = pos + _cell_len(segment.text) + if end_pos < end: + add_segment(segment) + else: + add_segment(segment.split_cells(end - pos)[0]) + break + pos = end_pos + segment = next(iter_segments, None) + return Strip(output_segments, end - start) + + def divide(self, cuts: Iterable[int]) -> list[Strip]: + + pos = 0 + cache_key = tuple(cuts) + cached = self._divide_cache.get(cache_key) + if cached is not None: + return cached + + strips: list[Strip] = [] + add_strip = strips.append + for segments, cut in zip(Segment.divide(self._segments, cuts), cuts): + add_strip(Strip(segments, cut - pos)) + pos += cut + + self._divide_cache[cache_key] = strips + + return strips diff --git a/src/textual/widget.py b/src/textual/widget.py index a74449272..69b1b2afa 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -43,7 +43,7 @@ from ._easing import DEFAULT_SCROLL_EASING from ._layout import Layout from ._segment_tools import align_lines from ._styles_cache import StylesCache -from ._types import Lines +from ._types import Strips from .actions import SkipAction from .await_remove import AwaitRemove from .binding import Binding @@ -57,6 +57,7 @@ from .message import Message from .messages import CallbackType from .reactive import Reactive from .render import measure +from .strip import Strip from .walk import walk_depth_first if TYPE_CHECKING: @@ -156,7 +157,7 @@ class RenderCache(NamedTuple): """Stores results of a previous render.""" size: Size - lines: Lines + lines: Strips class WidgetError(Exception): @@ -2118,7 +2119,7 @@ class Widget(DOMNode): line = [Segment(" " * self.size.width, self.rich_style)] return line - def render_lines(self, crop: Region) -> Lines: + def render_lines(self, crop: Region) -> list[Strip]: """Render the widget in to lines. Args: @@ -2127,8 +2128,8 @@ class Widget(DOMNode): Returns: Lines: A list of list of segments. """ - lines = self._styles_cache.render_widget(self, crop) - return lines + strips = self._styles_cache.render_widget(self, crop) + return strips def get_style_at(self, x: int, y: int) -> Style: """Get the Rich style in a widget at a given relative offset. diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py index 5d6d0a0e0..6b8eb5f38 100644 --- a/src/textual/widgets/_data_table.py +++ b/src/textual/widgets/_data_table.py @@ -14,7 +14,7 @@ from rich.text import Text, TextType from .. import events, messages from .._cache import LRUCache from .._segment_tools import line_crop -from .._types import Lines +from .._types import Strips from ..geometry import Region, Size, Spacing, clamp from ..reactive import Reactive from ..render import measure @@ -207,10 +207,10 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True): self.row_count = 0 self._y_offsets: list[tuple[int, int]] = [] self._row_render_cache: LRUCache[ - tuple[int, int, Style, int, int], tuple[Lines, Lines] + tuple[int, int, Style, int, int], tuple[Strips, Strips] ] self._row_render_cache = LRUCache(1000) - self._cell_render_cache: LRUCache[tuple[int, int, Style, bool, bool], Lines] + self._cell_render_cache: LRUCache[tuple[int, int, Style, bool, bool], Strips] self._cell_render_cache = LRUCache(10000) self._line_cache: LRUCache[ tuple[int, int, int, int, int, int, Style], list[Segment] @@ -450,7 +450,7 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True): width: int, cursor: bool = False, hover: bool = False, - ) -> Lines: + ) -> Strips: """Render the given cell. Args: @@ -488,7 +488,7 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True): base_style: Style, cursor_column: int = -1, hover_column: int = -1, - ) -> tuple[Lines, Lines]: + ) -> tuple[Strips, Strips]: """Render a row in to lines for each cell. Args: diff --git a/src/textual/widgets/_text_log.py b/src/textual/widgets/_text_log.py index 980df5f4c..1b420f95b 100644 --- a/src/textual/widgets/_text_log.py +++ b/src/textual/widgets/_text_log.py @@ -15,7 +15,7 @@ from ..geometry import Size, Region from ..scroll_view import ScrollView from .._cache import LRUCache from .._segment_tools import line_crop -from .._types import Lines +from .._types import Strips class TextLog(ScrollView, can_focus=True): @@ -143,7 +143,7 @@ class TextLog(ScrollView, can_focus=True): line = list(Segment.apply_style(line, self.rich_style)) return line - def render_lines(self, crop: Region) -> Lines: + def render_lines(self, crop: Region) -> Strips: """Render the widget in to lines. Args: diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 49f103500..a67872a63 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -21,162 +21,162 @@ font-weight: 700; } - .terminal-481343241-matrix { + .terminal-3615181303-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-481343241-title { + .terminal-3615181303-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-481343241-r1 { fill: #e1e1e1 } - .terminal-481343241-r2 { fill: #c5c8c6 } - .terminal-481343241-r3 { fill: #e1e1e1;font-weight: bold } - .terminal-481343241-r4 { fill: #454a50 } - .terminal-481343241-r5 { fill: #292b2e } - .terminal-481343241-r6 { fill: #24292f;font-weight: bold } - .terminal-481343241-r7 { fill: #555657;font-weight: bold } - .terminal-481343241-r8 { fill: #000000 } - .terminal-481343241-r9 { fill: #161617 } - .terminal-481343241-r10 { fill: #507bb3 } - .terminal-481343241-r11 { fill: #283c52 } - .terminal-481343241-r12 { fill: #dde6ed;font-weight: bold } - .terminal-481343241-r13 { fill: #4f5a62;font-weight: bold } - .terminal-481343241-r14 { fill: #001541 } - .terminal-481343241-r15 { fill: #122032 } - .terminal-481343241-r16 { fill: #7ae998 } - .terminal-481343241-r17 { fill: #3d6a4a } - .terminal-481343241-r18 { fill: #0a180e;font-weight: bold } - .terminal-481343241-r19 { fill: #1e2f23;font-weight: bold } - .terminal-481343241-r20 { fill: #008139 } - .terminal-481343241-r21 { fill: #1b4c2f } - .terminal-481343241-r22 { fill: #ffcf56 } - .terminal-481343241-r23 { fill: #775f2f } - .terminal-481343241-r24 { fill: #211505;font-weight: bold } - .terminal-481343241-r25 { fill: #392b18;font-weight: bold } - .terminal-481343241-r26 { fill: #b86b00 } - .terminal-481343241-r27 { fill: #644316 } - .terminal-481343241-r28 { fill: #e76580 } - .terminal-481343241-r29 { fill: #683540 } - .terminal-481343241-r30 { fill: #f5e5e9;font-weight: bold } - .terminal-481343241-r31 { fill: #6c595e;font-weight: bold } - .terminal-481343241-r32 { fill: #780028 } - .terminal-481343241-r33 { fill: #491928 } + .terminal-3615181303-r1 { fill: #e1e1e1 } + .terminal-3615181303-r2 { fill: #c5c8c6 } + .terminal-3615181303-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-3615181303-r4 { fill: #454a50 } + .terminal-3615181303-r5 { fill: #292b2e } + .terminal-3615181303-r6 { fill: #24292f;font-weight: bold } + .terminal-3615181303-r7 { fill: #555657;font-weight: bold } + .terminal-3615181303-r8 { fill: #000000 } + .terminal-3615181303-r9 { fill: #161617 } + .terminal-3615181303-r10 { fill: #507bb3 } + .terminal-3615181303-r11 { fill: #283c52 } + .terminal-3615181303-r12 { fill: #dde6ed;font-weight: bold } + .terminal-3615181303-r13 { fill: #4f5a62;font-weight: bold } + .terminal-3615181303-r14 { fill: #001541 } + .terminal-3615181303-r15 { fill: #122032 } + .terminal-3615181303-r16 { fill: #7ae998 } + .terminal-3615181303-r17 { fill: #3d6a4a } + .terminal-3615181303-r18 { fill: #0a180e;font-weight: bold } + .terminal-3615181303-r19 { fill: #1e2f23;font-weight: bold } + .terminal-3615181303-r20 { fill: #008139 } + .terminal-3615181303-r21 { fill: #1b4c2f } + .terminal-3615181303-r22 { fill: #ffcf56 } + .terminal-3615181303-r23 { fill: #775f2f } + .terminal-3615181303-r24 { fill: #211505;font-weight: bold } + .terminal-3615181303-r25 { fill: #392b18;font-weight: bold } + .terminal-3615181303-r26 { fill: #b86b00 } + .terminal-3615181303-r27 { fill: #644316 } + .terminal-3615181303-r28 { fill: #e76580 } + .terminal-3615181303-r29 { fill: #683540 } + .terminal-3615181303-r30 { fill: #f5e5e9;font-weight: bold } + .terminal-3615181303-r31 { fill: #6c595e;font-weight: bold } + .terminal-3615181303-r32 { fill: #780028 } + .terminal-3615181303-r33 { fill: #491928 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ButtonsApp + ButtonsApp - - - - - Standard ButtonsDisabled Buttons - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Default  Default  - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Primary!  Primary!  - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Success!  Success!  - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Warning!  Warning!  - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Error!  Error!  - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - + + + + + Standard ButtonsDisabled Buttons + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + DefaultDefault + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Primary!Primary! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Success!Success! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Warning!Warning! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Error!Error! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + @@ -207,136 +207,136 @@ font-weight: 700; } - .terminal-1548740802-matrix { + .terminal-1461952564-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1548740802-title { + .terminal-1461952564-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1548740802-r1 { fill: #e1e1e1 } - .terminal-1548740802-r2 { fill: #c5c8c6 } - .terminal-1548740802-r3 { fill: #e1e1e1;font-weight: bold } - .terminal-1548740802-r4 { fill: #1e1e1e } - .terminal-1548740802-r5 { fill: #0178d4 } - .terminal-1548740802-r6 { fill: #e2e3e3 } - .terminal-1548740802-r7 { fill: #e3e8e8 } + .terminal-1461952564-r1 { fill: #e1e1e1 } + .terminal-1461952564-r2 { fill: #c5c8c6 } + .terminal-1461952564-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-1461952564-r4 { fill: #1e1e1e } + .terminal-1461952564-r5 { fill: #0178d4 } + .terminal-1461952564-r6 { fill: #e2e3e3 } + .terminal-1461952564-r7 { fill: #e3e8e8 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CheckboxApp + CheckboxApp - - - - - - - - Example checkboxes - - - ▔▔▔▔▔▔▔▔ - off:      - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - on:       - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - focused:  - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - custom:   - ▁▁▁▁▁▁▁▁ - - - - + + + + + + + + Example checkboxes + + + ▔▔▔▔▔▔▔▔ + off:      + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + on:       + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + focused:  + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + custom:   + ▁▁▁▁▁▁▁▁ + + + + @@ -367,133 +367,133 @@ font-weight: 700; } - .terminal-2010068486-matrix { + .terminal-363813734-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2010068486-title { + .terminal-363813734-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2010068486-r1 { fill: #ff0000 } - .terminal-2010068486-r2 { fill: #c5c8c6 } - .terminal-2010068486-r3 { fill: #008000 } - .terminal-2010068486-r4 { fill: #e1e1e1 } + .terminal-363813734-r1 { fill: #ff0000 } + .terminal-363813734-r2 { fill: #c5c8c6 } + .terminal-363813734-r3 { fill: #008000 } + .terminal-363813734-r4 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - HeightApp + HeightApp - - - - ┌──────────────────────────────────────────────────────────────────────────────┐ - ┌────────────────────┐┌────────────────┐┌──────────────────────┐ - As tall as containerThis has defaultI have a static height - height - but a - few lines - └────────────────┘ - - - - - - - - - - └────────────────────┘└──────────────────────┘ - └──────────────────────────────────────────────────────────────────────────────┘ - - - - - + + + + ────────────────────────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────── + As tall as containerThis has defaultI have a static height + height + but a + few lines + ──────────────── + + + + + + + + + + ────────────────────────────────────────── + ────────────────────────────────────────────────────────────────────────────── + + + + + @@ -524,134 +524,134 @@ font-weight: 700; } - .terminal-4107518032-matrix { + .terminal-1567237307-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4107518032-title { + .terminal-1567237307-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4107518032-r1 { fill: #e1e1e1 } - .terminal-4107518032-r2 { fill: #c5c8c6 } - .terminal-4107518032-r3 { fill: #ffffff } - .terminal-4107518032-r4 { fill: #e5f2e5 } - .terminal-4107518032-r5 { fill: #e5f2e5;font-weight: bold } + .terminal-1567237307-r1 { fill: #e1e1e1 } + .terminal-1567237307-r2 { fill: #c5c8c6 } + .terminal-1567237307-r3 { fill: #ffffff } + .terminal-1567237307-r4 { fill: #e5f2e5 } + .terminal-1567237307-r5 { fill: #e5f2e5;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AlignApp + AlignApp - - - - - - - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - - Vertical alignment with Textual - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - - Take note, browsers. - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - - - - - + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + Vertical alignment with Textual + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + Take note, browsers. + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + + @@ -837,134 +837,134 @@ font-weight: 700; } - .terminal-3021441172-matrix { + .terminal-1839441138-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3021441172-title { + .terminal-1839441138-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3021441172-r1 { fill: #ffffff } - .terminal-3021441172-r2 { fill: #c5c8c6 } - .terminal-3021441172-r3 { fill: #ff0000 } - .terminal-3021441172-r4 { fill: #008000 } - .terminal-3021441172-r5 { fill: #0000ff } + .terminal-1839441138-r1 { fill: #ffffff } + .terminal-1839441138-r2 { fill: #c5c8c6 } + .terminal-1839441138-r3 { fill: #ff0000 } + .terminal-1839441138-r4 { fill: #008000 } + .terminal-1839441138-r5 { fill: #0000ff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BorderApp + BorderApp - - - - - ┌────────────────────────────────────────────────────────────────────────────┐ - - My border is solid red - - └────────────────────────────────────────────────────────────────────────────┘ - - ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ - - My border is dashed green - - ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - My border is tall blue - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - + + + + + ──────────────────────────────────────────────────────────────────────────── + + My border is solid red + + ──────────────────────────────────────────────────────────────────────────── + + ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ + + My border is dashed green + + ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + My border is tall blue + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + @@ -995,132 +995,132 @@ font-weight: 700; } - .terminal-3248705240-matrix { + .terminal-1232593861-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3248705240-title { + .terminal-1232593861-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3248705240-r1 { fill: #000000 } - .terminal-3248705240-r2 { fill: #c5c8c6 } - .terminal-3248705240-r3 { fill: #ccccff } + .terminal-1232593861-r1 { fill: #000000 } + .terminal-1232593861-r2 { fill: #c5c8c6 } + .terminal-1232593861-r3 { fill: #ccccff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BoxSizingApp + BoxSizingApp - - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - I'm using border-box! - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - I'm using content-box! - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - - - + + + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + I'm using border-box! + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + I'm using content-box! + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + + @@ -1308,133 +1308,133 @@ font-weight: 700; } - .terminal-2684005981-matrix { + .terminal-1585086532-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2684005981-title { + .terminal-1585086532-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2684005981-r1 { fill: #c5c8c6 } - .terminal-2684005981-r2 { fill: #ffffff } - .terminal-2684005981-r3 { fill: #ffffff;font-style: italic; } - .terminal-2684005981-r4 { fill: #ffffff;font-weight: bold } + .terminal-1585086532-r1 { fill: #c5c8c6 } + .terminal-1585086532-r2 { fill: #ffffff } + .terminal-1585086532-r3 { fill: #ffffff;font-style: italic; } + .terminal-1585086532-r4 { fill: #ffffff;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ContentAlignApp + ContentAlignApp - - - - - With content-align you can... - - - - - - - - - - ...Easily align content... - - - - - - - - - - - ...Horizontally and vertically! + + + + + With content-align you can... + + + + + + + + + + ...Easily align content... + + + + + + + + + + + ...Horizontally and vertically! @@ -1465,132 +1465,132 @@ font-weight: 700; } - .terminal-2110623858-matrix { + .terminal-3544266701-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2110623858-title { + .terminal-3544266701-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2110623858-r1 { fill: #0000ff } - .terminal-2110623858-r2 { fill: #c5c8c6 } - .terminal-2110623858-r3 { fill: #ddeedd } + .terminal-3544266701-r1 { fill: #0000ff } + .terminal-3544266701-r2 { fill: #c5c8c6 } + .terminal-3544266701-r3 { fill: #ddeedd } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DisplayApp + DisplayApp - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃Widget 1 - - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃Widget 3 - - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - - - - - - - - - - - - + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Widget 1 + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Widget 3 + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + + + + + + + + + @@ -1621,133 +1621,133 @@ font-weight: 700; } - .terminal-3791676016-matrix { + .terminal-2927206876-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3791676016-title { + .terminal-2927206876-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3791676016-r1 { fill: #c5c8c6 } - .terminal-3791676016-r2 { fill: #e1e1e1 } - .terminal-3791676016-r3 { fill: #731077 } - .terminal-3791676016-r4 { fill: #161c1d } + .terminal-2927206876-r1 { fill: #c5c8c6 } + .terminal-2927206876-r2 { fill: #e1e1e1 } + .terminal-2927206876-r3 { fill: #731077 } + .terminal-2927206876-r4 { fill: #161c1d } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - GridApp + GridApp - - - - - Grid cell 1Grid cell 2 - - row-span: 3; - column-span: 2; - - - Grid cell 3 - - - - - - Grid cell 4 - - - - - - Grid cell 5Grid cell 6Grid cell 7 - - - + + + + + Grid cell 1Grid cell 2 + + row-span: 3; + column-span: 2; + + + Grid cell 3 + + + + + + Grid cell 4 + + + + + + Grid cell 5Grid cell 6Grid cell 7 + + + @@ -2249,133 +2249,133 @@ font-weight: 700; } - .terminal-2799621938-matrix { + .terminal-211150573-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2799621938-title { + .terminal-211150573-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2799621938-r1 { fill: #000000 } - .terminal-2799621938-r2 { fill: #c5c8c6 } - .terminal-2799621938-r3 { fill: #0000ff } - .terminal-2799621938-r4 { fill: #ccccff } + .terminal-211150573-r1 { fill: #000000 } + .terminal-211150573-r2 { fill: #c5c8c6 } + .terminal-211150573-r3 { fill: #0000ff } + .terminal-211150573-r4 { fill: #ccccff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MarginApp + MarginApp - - - - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - I must not fear. - Fear is the mind-killer. - Fear is the little-death that brings total obliteration. - I will face my fear. - I will permit it to pass over me and through me. - And when it has gone past, I will turn the inner eye to see  - its path. - Where the fear has gone there will be nothing. Only I will  - remain. - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - - - - - - + + + + + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + I must not fear. + Fear is the mind-killer. + Fear is the little-death that brings total obliteration. + I will face my fear. + I will permit it to pass over me and through me. + And when it has gone past, I will turn the inner eye to see  + its path. + Where the fear has gone there will be nothing. Only I will  + remain. + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + + + + + @@ -2406,134 +2406,134 @@ font-weight: 700; } - .terminal-2080475776-matrix { + .terminal-4002837244-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2080475776-title { + .terminal-4002837244-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2080475776-r1 { fill: #000000 } - .terminal-2080475776-r2 { fill: #c5c8c6 } - .terminal-2080475776-r3 { fill: #ff0000 } - .terminal-2080475776-r4 { fill: #0000ff } - .terminal-2080475776-r5 { fill: #008000 } + .terminal-4002837244-r1 { fill: #000000 } + .terminal-4002837244-r2 { fill: #c5c8c6 } + .terminal-4002837244-r3 { fill: #ff0000 } + .terminal-4002837244-r4 { fill: #0000ff } + .terminal-4002837244-r5 { fill: #008000 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OffsetApp + OffsetApp - - - - - - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - - - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - Paul (offset 8 2) - - - Chani (offset 0 5)▐ - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - - - Duncan (offset ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ - 10) - - - - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ - - - + + + + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + Paul (offset 8 2) + + + Chani (offset 0 5) + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + + + Duncan (offset ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + 10) + + + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + + + @@ -2564,140 +2564,140 @@ font-weight: 700; } - .terminal-245581281-matrix { + .terminal-2191428201-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-245581281-title { + .terminal-2191428201-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-245581281-r1 { fill: #fefcf9 } - .terminal-245581281-r2 { fill: #c5c8c6 } - .terminal-245581281-r3 { fill: #c3d4e1 } - .terminal-245581281-r4 { fill: #f4edde;font-weight: bold } - .terminal-245581281-r5 { fill: #8cbdeb } - .terminal-245581281-r6 { fill: #eeefe5;font-weight: bold } - .terminal-245581281-r7 { fill: #55a6f5 } - .terminal-245581281-r8 { fill: #e8f1ec;font-weight: bold } - .terminal-245581281-r9 { fill: #1e90ff } - .terminal-245581281-r10 { fill: #e2f4f3;font-weight: bold } + .terminal-2191428201-r1 { fill: #fefcf9 } + .terminal-2191428201-r2 { fill: #c5c8c6 } + .terminal-2191428201-r3 { fill: #c3d4e1 } + .terminal-2191428201-r4 { fill: #f4edde;font-weight: bold } + .terminal-2191428201-r5 { fill: #8cbdeb } + .terminal-2191428201-r6 { fill: #eeefe5;font-weight: bold } + .terminal-2191428201-r7 { fill: #55a6f5 } + .terminal-2191428201-r8 { fill: #e8f1ec;font-weight: bold } + .terminal-2191428201-r9 { fill: #1e90ff } + .terminal-2191428201-r10 { fill: #e2f4f3;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OpacityApp + OpacityApp - - - - - - - - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - - opacity: 25% - - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - - opacity: 50% - - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - - opacity: 75% - - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ - ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜ - - opacity: 100% - - ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ + + + + + + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + + opacity: 25% + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + + opacity: 50% + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + + opacity: 75% + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + + opacity: 100% + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ @@ -2727,133 +2727,133 @@ font-weight: 700; } - .terminal-2107256950-matrix { + .terminal-3260169885-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2107256950-title { + .terminal-3260169885-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2107256950-r1 { fill: #000000 } - .terminal-2107256950-r2 { fill: #c5c8c6 } - .terminal-2107256950-r3 { fill: #008000 } - .terminal-2107256950-r4 { fill: #cce5cc } + .terminal-3260169885-r1 { fill: #000000 } + .terminal-3260169885-r2 { fill: #c5c8c6 } + .terminal-3260169885-r3 { fill: #008000 } + .terminal-3260169885-r4 { fill: #cce5cc } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OutlineApp + OutlineApp - - - - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ear is the mind-killer. - ear is the little-death that brings total obliteration. -  will face my fear. -  will permit it to pass over me and through me. - nd when it has gone past, I will turn the inner eye to see its - ath. - here the fear has gone there will be nothing. Only I will  - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - - - - - - - - + + + + + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ear is the mind-killer. + ear is the little-death that brings total obliteration. +  will face my fear. +  will permit it to pass over me and through me. + nd when it has gone past, I will turn the inner eye to see its + ath. + here the fear has gone there will be nothing. Only I will  + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + + + + + + + @@ -2884,136 +2884,136 @@ font-weight: 700; } - .terminal-1725099926-matrix { + .terminal-3616080938-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1725099926-title { + .terminal-3616080938-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1725099926-r1 { fill: #c5c8c6 } - .terminal-1725099926-r2 { fill: #000000 } - .terminal-1725099926-r3 { fill: #008000 } - .terminal-1725099926-r4 { fill: #e5f0e5 } - .terminal-1725099926-r5 { fill: #036a03 } - .terminal-1725099926-r6 { fill: #14191f } + .terminal-3616080938-r1 { fill: #c5c8c6 } + .terminal-3616080938-r2 { fill: #000000 } + .terminal-3616080938-r3 { fill: #008000 } + .terminal-3616080938-r4 { fill: #e5f0e5 } + .terminal-3616080938-r5 { fill: #036a03 } + .terminal-3616080938-r6 { fill: #14191f } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OverflowApp + OverflowApp - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - I must not fear.I must not fear. - Fear is the mind-killer.Fear is the mind-killer. - Fear is the little-death that Fear is the little-death that  - brings total obliteration.brings total obliteration. - I will face my fear.I will face my fear. - I will permit it to pass over meI will permit it to pass over me  - and through me.and through me. - And when it has gone past, I And when it has gone past, I will  - will turn the inner eye to see turn the inner eye to see its  - its path.▁▁path. - Where the fear has gone there Where the fear has gone there will - will be nothing. Only I will be nothing. Only I will remain. - remain.▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁I must not fear. - I must not fear.Fear is the mind-killer. - Fear is the mind-killer.Fear is the little-death that  - Fear is the little-death that brings total obliteration. - brings total obliteration.I will face my fear. - I will face my fear.I will permit it to pass over me  - I will permit it to pass over meand through me. + + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + I must not fear.I must not fear. + Fear is the mind-killer.Fear is the mind-killer. + Fear is the little-death that Fear is the little-death that  + brings total obliteration.brings total obliteration. + I will face my fear.I will face my fear. + I will permit it to pass over meI will permit it to pass over me  + and through me.and through me. + And when it has gone past, I And when it has gone past, I will  + will turn the inner eye to see turn the inner eye to see its  + its path.▁▁path. + Where the fear has gone there Where the fear has gone there will + will be nothing. Only I will be nothing. Only I will remain. + remain.▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁I must not fear. + I must not fear.Fear is the mind-killer. + Fear is the mind-killer.Fear is the little-death that  + Fear is the little-death that brings total obliteration. + brings total obliteration.I will face my fear. + I will face my fear.I will permit it to pass over me  + I will permit it to pass over meand through me. @@ -3043,131 +3043,131 @@ font-weight: 700; } - .terminal-1142797465-matrix { + .terminal-3291669704-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1142797465-title { + .terminal-3291669704-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1142797465-r1 { fill: #c5c8c6 } - .terminal-1142797465-r2 { fill: #0000ff } + .terminal-3291669704-r1 { fill: #c5c8c6 } + .terminal-3291669704-r2 { fill: #0000ff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - PaddingApp + PaddingApp - - - - - - - - I must not fear. - Fear is the mind-killer. - Fear is the little-death that brings total obliteration. - I will face my fear. - I will permit it to pass over me and through me. - And when it has gone past, I will turn the inner eye to see its  - path. - Where the fear has gone there will be nothing. Only I will  - remain. - - - - - - - - - - + + + + + + + + I must not fear. + Fear is the mind-killer. + Fear is the little-death that brings total obliteration. + I will face my fear. + I will permit it to pass over me and through me. + And when it has gone past, I will turn the inner eye to see its  + path. + Where the fear has gone there will be nothing. Only I will  + remain. + + + + + + + + + + @@ -3510,133 +3510,133 @@ font-weight: 700; } - .terminal-2331479198-matrix { + .terminal-3032075324-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2331479198-title { + .terminal-3032075324-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2331479198-r1 { fill: #c5c8c6 } - .terminal-2331479198-r2 { fill: #d2d2d2 } - .terminal-2331479198-r3 { fill: #bbbbbb } - .terminal-2331479198-r4 { fill: #800080 } + .terminal-3032075324-r1 { fill: #c5c8c6 } + .terminal-3032075324-r2 { fill: #d2d2d2 } + .terminal-3032075324-r3 { fill: #bbbbbb } + .terminal-3032075324-r4 { fill: #800080 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ScrollbarApp + ScrollbarApp - - - - - - I must not fear.I must not fear. - Fear is the mind-killer.Fear is the mind-killer. - Fear is the little-death that Fear is the little-death that  - brings total obliteration.brings total obliteration. - I will face my fear.I will face my fear. - I will permit it to pass over I will permit it to pass over  - me and through me.▇▇me and through me.▇▇ - And when it has gone past, I And when it has gone past, I  - will turn the inner eye to seewill turn the inner eye to see - its path.its path. - Where the fear has gone there Where the fear has gone there  - will be nothing. Only I will will be nothing. Only I will  - remain.remain. - I must not fear.I must not fear. - Fear is the mind-killer.Fear is the mind-killer. - Fear is the little-death that Fear is the little-death that  - brings total obliteration.brings total obliteration. - I will face my fear.I will face my fear. - I will permit it to pass over I will permit it to pass over  - me and through me.me and through me. - And when it has gone past, I And when it has gone past, I  + + + + + + I must not fear.I must not fear. + Fear is the mind-killer.Fear is the mind-killer. + Fear is the little-death that Fear is the little-death that  + brings total obliteration.brings total obliteration. + I will face my fear.I will face my fear. + I will permit it to pass over I will permit it to pass over  + me and through me.▇▇me and through me.▇▇ + And when it has gone past, I And when it has gone past, I  + will turn the inner eye to seewill turn the inner eye to see + its path.its path. + Where the fear has gone there Where the fear has gone there  + will be nothing. Only I will will be nothing. Only I will  + remain.remain. + I must not fear.I must not fear. + Fear is the mind-killer.Fear is the mind-killer. + Fear is the little-death that Fear is the little-death that  + brings total obliteration.brings total obliteration. + I will face my fear.I will face my fear. + I will permit it to pass over I will permit it to pass over  + me and through me.me and through me. + And when it has gone past, I And when it has gone past, I  @@ -3667,138 +3667,138 @@ font-weight: 700; } - .terminal-496646788-matrix { + .terminal-1285129494-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-496646788-title { + .terminal-1285129494-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-496646788-r1 { fill: #c5c8c6 } - .terminal-496646788-r2 { fill: #f4f9fb;font-weight: bold } - .terminal-496646788-r3 { fill: #f4f9fb } - .terminal-496646788-r4 { fill: #f8e9e9 } - .terminal-496646788-r5 { fill: #f8e9e9;font-weight: bold } - .terminal-496646788-r6 { fill: #f1fef1 } - .terminal-496646788-r7 { fill: #f1fef1;font-weight: bold } - .terminal-496646788-r8 { fill: #faecf0;font-weight: bold } - .terminal-496646788-r9 { fill: #faecf0 } + .terminal-1285129494-r1 { fill: #c5c8c6 } + .terminal-1285129494-r2 { fill: #f4f9fb;font-weight: bold } + .terminal-1285129494-r3 { fill: #f4f9fb } + .terminal-1285129494-r4 { fill: #f8e9e9 } + .terminal-1285129494-r5 { fill: #f8e9e9;font-weight: bold } + .terminal-1285129494-r6 { fill: #f1fef1 } + .terminal-1285129494-r7 { fill: #f1fef1;font-weight: bold } + .terminal-1285129494-r8 { fill: #faecf0;font-weight: bold } + .terminal-1285129494-r9 { fill: #faecf0 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TextAlign + TextAlign - - - - - Left aligned - I must not fear. Fear is the mind-killer. Fear is the little-death that brings - total obliteration. I will face my fear. I will permit it to pass over me and  - through me.                                                                    - - - Center aligned - I must not fear. Fear is the mind-killer. Fear is the little-death that brings - total obliteration. I will face my fear. I will permit it to pass over me and  -                                  through me.                                   - - - Right aligned - I must not fear. Fear is the mind-killer. Fear is the little-death that brings -  total obliteration. I will face my fear. I will permit it to pass over me and -                                                                    through me. - - - Justified - I must not fear. Fear is the mind-killer. Fear is the little-death that brings - total obliteration. I will face my fear. I will permit it to pass over me  and - through me. + + + + + Left aligned + I must not fear. Fear is the mind-killer. Fear is the little-death that brings + total obliteration. I will face my fear. I will permit it to pass over me and  + through me.                                                                    + + + Center aligned + I must not fear. Fear is the mind-killer. Fear is the little-death that brings + total obliteration. I will face my fear. I will permit it to pass over me and  +                                  through me.                                   + + + Right aligned + I must not fear. Fear is the mind-killer. Fear is the little-death that brings +  total obliteration. I will face my fear. I will permit it to pass over me and +                                                                    through me. + + + Justified + I must not fear. Fear is the mind-killer. Fear is the little-death that brings + total obliteration. I will face my fear. I will permit it to pass over me  and + through me. @@ -4309,132 +4309,132 @@ font-weight: 700; } - .terminal-3114242500-matrix { + .terminal-398211359-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3114242500-title { + .terminal-398211359-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3114242500-r1 { fill: #0000ff } - .terminal-3114242500-r2 { fill: #c5c8c6 } - .terminal-3114242500-r3 { fill: #ddeedd } + .terminal-398211359-r1 { fill: #0000ff } + .terminal-398211359-r2 { fill: #c5c8c6 } + .terminal-398211359-r3 { fill: #ddeedd } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - VisibilityApp + VisibilityApp - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃Widget 1 - - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃Widget 3 - - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - - - - - - - + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Widget 1 + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Widget 3 + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + + + + @@ -4621,134 +4621,134 @@ font-weight: 700; } - .terminal-133545376-matrix { + .terminal-1865244878-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-133545376-title { + .terminal-1865244878-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-133545376-r1 { fill: #dde6ed;font-weight: bold } - .terminal-133545376-r2 { fill: #e1e1e1 } - .terminal-133545376-r3 { fill: #c5c8c6 } - .terminal-133545376-r4 { fill: #e7e5e2 } - .terminal-133545376-r5 { fill: #211505 } + .terminal-1865244878-r1 { fill: #dde6ed;font-weight: bold } + .terminal-1865244878-r2 { fill: #e1e1e1 } + .terminal-1865244878-r3 { fill: #c5c8c6 } + .terminal-1865244878-r4 { fill: #e7e5e2 } + .terminal-1865244878-r5 { fill: #211505 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TableApp + TableApp - - - -  lane  swimmer               country        time   -  4     Joseph Schooling      Singapore      50.39  -  2     Michael Phelps        United States  51.14  -  5     Chad le Clos          South Africa   51.14  -  6     László Cseh           Hungary        51.14  -  3     Li Zhuhao             China          51.26  -  8     Mehdy Metella         France         51.58  -  7     Tom Shields           United States  51.73  -  1     Aleksandr Sadovnikov  Russia         51.84  - - - - - - - - - - - - - - + + + + laneswimmercountrytime + 4Joseph SchoolingSingapore50.39 +  2     Michael Phelps        United States  51.14  +  5     Chad le Clos          South Africa   51.14  + 6László CsehHungary51.14 + 3Li ZhuhaoChina51.26 + 8Mehdy MetellaFrance51.58 + 7Tom ShieldsUnited States51.73 + 1Aleksandr SadovnikovRussia51.84 + + + + + + + + + + + + + + @@ -4779,169 +4779,169 @@ font-weight: 700; } - .terminal-746150767-matrix { + .terminal-4040833233-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-746150767-title { + .terminal-4040833233-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-746150767-r1 { fill: #c5c8c6 } - .terminal-746150767-r2 { fill: #e3e3e3 } - .terminal-746150767-r3 { fill: #e1e1e1 } - .terminal-746150767-r4 { fill: #23568b } - .terminal-746150767-r5 { fill: #e2e2e2 } - .terminal-746150767-r6 { fill: #004578 } - .terminal-746150767-r7 { fill: #14191f } - .terminal-746150767-r8 { fill: #262626 } - .terminal-746150767-r9 { fill: #e2e2e2;font-weight: bold;text-decoration: underline; } - .terminal-746150767-r10 { fill: #e2e2e2;font-weight: bold } - .terminal-746150767-r11 { fill: #7ae998 } - .terminal-746150767-r12 { fill: #4ebf71;font-weight: bold } - .terminal-746150767-r13 { fill: #008139 } - .terminal-746150767-r14 { fill: #dde8f3;font-weight: bold } - .terminal-746150767-r15 { fill: #ddedf9 } + .terminal-4040833233-r1 { fill: #c5c8c6 } + .terminal-4040833233-r2 { fill: #e3e3e3 } + .terminal-4040833233-r3 { fill: #e1e1e1 } + .terminal-4040833233-r4 { fill: #23568b } + .terminal-4040833233-r5 { fill: #e2e2e2 } + .terminal-4040833233-r6 { fill: #004578 } + .terminal-4040833233-r7 { fill: #14191f } + .terminal-4040833233-r8 { fill: #262626 } + .terminal-4040833233-r9 { fill: #e2e2e2;font-weight: bold;text-decoration: underline; } + .terminal-4040833233-r10 { fill: #e2e2e2;font-weight: bold } + .terminal-4040833233-r11 { fill: #7ae998 } + .terminal-4040833233-r12 { fill: #4ebf71;font-weight: bold } + .terminal-4040833233-r13 { fill: #008139 } + .terminal-4040833233-r14 { fill: #dde8f3;font-weight: bold } + .terminal-4040833233-r15 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Textual Demo + Textual Demo - - - - Textual Demo - ▅▅ - - TOP - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▃ - - Widgets - Textual Demo - - Welcome! Textual is a framework for creating sophisticated - Rich contentapplications with the terminal.                            - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -  Start  - CSS▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - - - - - - - - -                           Widgets                            -  CTRL+C  Quit  CTRL+B  Sidebar  CTRL+T  Toggle Dark mode  CTRL+S  Screenshot  F1  Notes  + + + + Textual Demo + ▅▅ + + TOP + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▃ + + Widgets + Textual Demo + + Welcome! Textual is a framework for creating sophisticated + Rich contentapplications with the terminal. + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Start + CSS▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + + + + + + + +                           Widgets                            +  CTRL+C  Quit  CTRL+B  Sidebar  CTRL+T  Toggle Dark mode  CTRL+S  Screenshot  F1  Notes  @@ -5285,133 +5285,133 @@ font-weight: 700; } - .terminal-2391317464-matrix { + .terminal-230484307-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2391317464-title { + .terminal-230484307-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2391317464-r1 { fill: #ffffff } - .terminal-2391317464-r2 { fill: #c5c8c6 } - .terminal-2391317464-r3 { fill: #e2e2e2 } + .terminal-230484307-r1 { fill: #ffffff } + .terminal-230484307-r2 { fill: #c5c8c6 } + .terminal-230484307-r3 { fill: #e2e2e2 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - FRApp + FRApp - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - HEADER - - - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - ┏━━━━━━━━┓┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓┏━━━━━━┓ - foobarbaz - - - - - - - - - - - - ┗━━━━━━━━┛┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛┗━━━━━━┛ - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - FOOTER - - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + HEADER + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + foobarbaz + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + FOOTER + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -5441,133 +5441,133 @@ font-weight: 700; } - .terminal-2808014621-matrix { + .terminal-3077119198-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2808014621-title { + .terminal-3077119198-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2808014621-r1 { fill: #008000 } - .terminal-2808014621-r2 { fill: #c5c8c6 } - .terminal-2808014621-r3 { fill: #e1e1e1 } + .terminal-3077119198-r1 { fill: #008000 } + .terminal-3077119198-r2 { fill: #c5c8c6 } + .terminal-3077119198-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - GridLayoutExample + GridLayoutExample - - - - ┌────────────────────────┐┌─────────────────────────┐┌─────────────────────────┐ - OneTwoThree - - - - - - - - - - └────────────────────────┘└─────────────────────────┘└─────────────────────────┘ - ┌────────────────────────┐┌─────────────────────────┐┌─────────────────────────┐ - FourFiveSix - - - - - - - - - - └────────────────────────┘└─────────────────────────┘└─────────────────────────┘ + + + + ────────────────────────────────────────────────────────────────────────── + OneTwoThree + + + + + + + + + + ────────────────────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────────────────────── + FourFiveSix + + + + + + + + + + ────────────────────────────────────────────────────────────────────────── @@ -5597,133 +5597,133 @@ font-weight: 700; } - .terminal-947520513-matrix { + .terminal-1958232742-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-947520513-title { + .terminal-1958232742-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-947520513-r1 { fill: #008000 } - .terminal-947520513-r2 { fill: #c5c8c6 } - .terminal-947520513-r3 { fill: #e1e1e1 } + .terminal-1958232742-r1 { fill: #008000 } + .terminal-1958232742-r2 { fill: #c5c8c6 } + .terminal-1958232742-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - GridLayoutExample + GridLayoutExample - - - - ┌────────────────────────┐┌─────────────────────────┐┌─────────────────────────┐ - OneTwoThree - - - - - - └────────────────────────┘└─────────────────────────┘└─────────────────────────┘ - ┌────────────────────────┐┌─────────────────────────┐┌─────────────────────────┐ - FourFiveSix - - - - - - └────────────────────────┘└─────────────────────────┘└─────────────────────────┘ - ┌────────────────────────┐ - Seven - - - - - - └────────────────────────┘ + + + + ────────────────────────────────────────────────────────────────────────── + OneTwoThree + + + + + + ────────────────────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────────────────────── + FourFiveSix + + + + + + ────────────────────────────────────────────────────────────────────────── + ──────────────────────── + Seven + + + + + + ──────────────────────── @@ -5909,132 +5909,132 @@ font-weight: 700; } - .terminal-1066078378-matrix { + .terminal-4077214022-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1066078378-title { + .terminal-4077214022-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1066078378-r1 { fill: #c5c8c6 } - .terminal-1066078378-r2 { fill: #e3e3e3 } - .terminal-1066078378-r3 { fill: #e1e1e1 } + .terminal-4077214022-r1 { fill: #c5c8c6 } + .terminal-4077214022-r2 { fill: #e3e3e3 } + .terminal-4077214022-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - HeaderApp + HeaderApp - - - - HeaderApp - - - - - - - - - - - - - - - - - - - - - - + + + + HeaderApp + + + + + + + + + + + + + + + + + + + + + + @@ -6065,133 +6065,133 @@ font-weight: 700; } - .terminal-543913381-matrix { + .terminal-1769115774-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-543913381-title { + .terminal-1769115774-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-543913381-r1 { fill: #008000 } - .terminal-543913381-r2 { fill: #c5c8c6 } - .terminal-543913381-r3 { fill: #e1e1e1 } + .terminal-1769115774-r1 { fill: #008000 } + .terminal-1769115774-r2 { fill: #c5c8c6 } + .terminal-1769115774-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - HorizontalLayoutExample + HorizontalLayoutExample - - - - ┌────────────────────────┐┌─────────────────────────┐┌─────────────────────────┐ - OneTwoThree - - - - - - - - - - - - - - - - - - - - - - └────────────────────────┘└─────────────────────────┘└─────────────────────────┘ + + + + ────────────────────────────────────────────────────────────────────────── + OneTwoThree + + + + + + + + + + + + + + + + + + + + + + ────────────────────────────────────────────────────────────────────────── @@ -6379,135 +6379,135 @@ font-weight: 700; } - .terminal-4091889985-matrix { + .terminal-4205022328-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4091889985-title { + .terminal-4205022328-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4091889985-r1 { fill: #1e1e1e } - .terminal-4091889985-r2 { fill: #121212 } - .terminal-4091889985-r3 { fill: #c5c8c6 } - .terminal-4091889985-r4 { fill: #e2e2e2 } - .terminal-4091889985-r5 { fill: #0178d4 } - .terminal-4091889985-r6 { fill: #e1e1e1 } + .terminal-4205022328-r1 { fill: #1e1e1e } + .terminal-4205022328-r2 { fill: #121212 } + .terminal-4205022328-r3 { fill: #c5c8c6 } + .terminal-4205022328-r4 { fill: #e2e2e2 } + .terminal-4205022328-r5 { fill: #0178d4 } + .terminal-4205022328-r6 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - InputApp + InputApp - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Darren                                                                     - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Burns - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - - - - - - - - + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Darren  + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Burns + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + @@ -7166,135 +7166,135 @@ font-weight: 700; } - .terminal-2940916684-matrix { + .terminal-3700945997-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2940916684-title { + .terminal-3700945997-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2940916684-r1 { fill: #90ee90 } - .terminal-2940916684-r2 { fill: #c5c8c6 } - .terminal-2940916684-r3 { fill: #add8e6 } - .terminal-2940916684-r4 { fill: #808080 } - .terminal-2940916684-r5 { fill: #dddddd } - .terminal-2940916684-r6 { fill: #ffdddd } + .terminal-3700945997-r1 { fill: #90ee90 } + .terminal-3700945997-r2 { fill: #c5c8c6 } + .terminal-3700945997-r3 { fill: #add8e6 } + .terminal-3700945997-r4 { fill: #808080 } + .terminal-3700945997-r5 { fill: #dddddd } + .terminal-3700945997-r6 { fill: #ffdddd } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - NestedAutoApp + NestedAutoApp - - - - ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┏━━━━━━━━━━━━━━━┓ - ┏━━━━━━━━━━━━━┓ - JUST ONE LINE - ┗━━━━━━━━━━━━━┛ - ┗━━━━━━━━━━━━━━━┛ - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - - - - - - - - - - - - - - - - + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━ + JUST ONE LINE + ━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + + + + + + + + + + + + @@ -7325,133 +7325,133 @@ font-weight: 700; } - .terminal-1996000257-matrix { + .terminal-4150241775-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1996000257-title { + .terminal-4150241775-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1996000257-r1 { fill: #e1e1e1 } - .terminal-1996000257-r2 { fill: #c5c8c6 } - .terminal-1996000257-r3 { fill: #ffffff } - .terminal-1996000257-r4 { fill: #ddddef } + .terminal-4150241775-r1 { fill: #e1e1e1 } + .terminal-4150241775-r2 { fill: #c5c8c6 } + .terminal-4150241775-r3 { fill: #ffffff } + .terminal-4150241775-r4 { fill: #ddddef } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OffsetsApp + OffsetsApp - - - - - - - - - ┌──────────────┐ - FOO - BAR - BAZ - └──────────────┘ - - - - - - ┌──────────────┐ - FOO - BAR - BAZ - └──────────────┘ - - - + + + + + + + + + ────────────── + FOO + BAR + BAZ + ────────────── + + + + + + ────────────── + FOO + BAR + BAZ + ────────────── + + + @@ -7482,136 +7482,136 @@ font-weight: 700; } - .terminal-3751523503-matrix { + .terminal-1392305496-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3751523503-title { + .terminal-1392305496-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3751523503-r1 { fill: #ffff00 } - .terminal-3751523503-r2 { fill: #e3e3e3 } - .terminal-3751523503-r3 { fill: #c5c8c6 } - .terminal-3751523503-r4 { fill: #e1e1e1 } - .terminal-3751523503-r5 { fill: #dde8f3;font-weight: bold } - .terminal-3751523503-r6 { fill: #ddedf9 } + .terminal-1392305496-r1 { fill: #ffff00 } + .terminal-1392305496-r2 { fill: #e3e3e3 } + .terminal-1392305496-r3 { fill: #c5c8c6 } + .terminal-1392305496-r4 { fill: #e1e1e1 } + .terminal-1392305496-r5 { fill: #dde8f3;font-weight: bold } + .terminal-1392305496-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Layers + Layers - - - - ┌──────────────────────────────────┐Layers - It's full of stars! My God! It's full of sta - - This should float over the top - - - └──────────────────────────────────┘ - - - - - - - - - - - - - - - - -  T  Toggle Screen  + + + + ──────────────────────────────────Layers + It's full of stars! My God! It's full of sta + + This should float over the top + + + ────────────────────────────────── + + + + + + + + + + + + + + + + +  T  Toggle Screen  @@ -7641,136 +7641,136 @@ font-weight: 700; } - .terminal-3245245315-matrix { + .terminal-4137661484-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3245245315-title { + .terminal-4137661484-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3245245315-r1 { fill: #ffff00 } - .terminal-3245245315-r2 { fill: #c5c8c6 } - .terminal-3245245315-r3 { fill: #e3e3e3 } - .terminal-3245245315-r4 { fill: #ddeedd } - .terminal-3245245315-r5 { fill: #dde8f3;font-weight: bold } - .terminal-3245245315-r6 { fill: #ddedf9 } + .terminal-4137661484-r1 { fill: #ffff00 } + .terminal-4137661484-r2 { fill: #c5c8c6 } + .terminal-4137661484-r3 { fill: #e3e3e3 } + .terminal-4137661484-r4 { fill: #ddeedd } + .terminal-4137661484-r5 { fill: #dde8f3;font-weight: bold } + .terminal-4137661484-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Layers + Layers - - - - ┌──────────────────────────────────┐ - It's full of stars! My God! It's full of sta - - This should float over the top - - - └──────────────────────────────────┘ - - - - - - - - - - - - - - - - -  T  Toggle Screen  + + + + ────────────────────────────────── + It's full of stars! My God! It's full of sta + + This should float over the top + + + ────────────────────────────────── + + + + + + + + + + + + + + + + +  T  Toggle Screen  @@ -7969,131 +7969,131 @@ font-weight: 700; } - .terminal-2820474000-matrix { + .terminal-727043961-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2820474000-title { + .terminal-727043961-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2820474000-r1 { fill: #e1e1e1 } - .terminal-2820474000-r2 { fill: #c5c8c6 } + .terminal-727043961-r1 { fill: #e1e1e1 } + .terminal-727043961-r2 { fill: #c5c8c6 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TextLogLines + TextLogLines - - - - Key press #3                                                                   - Key press #4                                                                   - Key press #5                                                                   - - - - - - - - - - - - - - - - - - - - + + + + Key press #3 + Key press #4 + Key press #5 + + + + + + + + + + + + + + + + + + + + @@ -8124,132 +8124,132 @@ font-weight: 700; } - .terminal-9236131-matrix { + .terminal-2744759648-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-9236131-title { + .terminal-2744759648-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-9236131-r1 { fill: #e2e3e3 } - .terminal-9236131-r2 { fill: #c5c8c6 } - .terminal-9236131-r3 { fill: #008139 } + .terminal-2744759648-r1 { fill: #e2e3e3 } + .terminal-2744759648-r2 { fill: #c5c8c6 } + .terminal-2744759648-r3 { fill: #008139 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TreeApp + TreeApp - - - - ▼ Dune - └── ▼ Characters -     ├── Paul -     ├── Jessica -     └── Chani - - - - - - - - - - - - - - - - - - + + + + ▼ Dune + └── ▼ Characters + ├── Paul + ├── Jessica + └── Chani + + + + + + + + + + + + + + + + + + @@ -8280,133 +8280,133 @@ font-weight: 700; } - .terminal-660754755-matrix { + .terminal-452684828-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-660754755-title { + .terminal-452684828-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-660754755-r1 { fill: #008000 } - .terminal-660754755-r2 { fill: #c5c8c6 } - .terminal-660754755-r3 { fill: #e1e1e1 } + .terminal-452684828-r1 { fill: #008000 } + .terminal-452684828-r2 { fill: #c5c8c6 } + .terminal-452684828-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - VerticalLayoutExample + VerticalLayoutExample - - - - ┌──────────────────────────────────────────────────────────────────────────────┐ - One - - - - - - └──────────────────────────────────────────────────────────────────────────────┘ - ┌──────────────────────────────────────────────────────────────────────────────┐ - Two - - - - - - └──────────────────────────────────────────────────────────────────────────────┘ - ┌──────────────────────────────────────────────────────────────────────────────┐ - Three - - - - - - └──────────────────────────────────────────────────────────────────────────────┘ + + + + ────────────────────────────────────────────────────────────────────────────── + One + + + + + + ────────────────────────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────────────────────────── + Two + + + + + + ────────────────────────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────────────────────────── + Three + + + + + + ────────────────────────────────────────────────────────────────────────────── @@ -8436,134 +8436,134 @@ font-weight: 700; } - .terminal-1057512867-matrix { + .terminal-4186799416-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1057512867-title { + .terminal-4186799416-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1057512867-r1 { fill: #e1e1e1 } - .terminal-1057512867-r2 { fill: #ff0000 } - .terminal-1057512867-r3 { fill: #c5c8c6 } - .terminal-1057512867-r4 { fill: #0000ff } + .terminal-4186799416-r1 { fill: #e1e1e1 } + .terminal-4186799416-r2 { fill: #ff0000 } + .terminal-4186799416-r3 { fill: #c5c8c6 } + .terminal-4186799416-r4 { fill: #0000ff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Visibility + Visibility - - - - ┌──────────────────────────────────────┐ - bar - ┌────────────────────────────────────┐┌────────────────────────────────────┐ - floatfloat - └────────────────────────────────────┘└────────────────────────────────────┘ - - - - - - - - - - - - - - - - - - - └──────────────────────────────────────┘ + + + + ────────────────────────────────────── + bar + ──────────────────────────────────────────────────────────────────────── + floatfloat + ──────────────────────────────────────────────────────────────────────── + + + + + + + + + + + + + + + + + + + ────────────────────────────────────── diff --git a/tests/test_styles_cache.py b/tests/test_styles_cache.py index 32795dca0..6f65f003f 100644 --- a/tests/test_styles_cache.py +++ b/tests/test_styles_cache.py @@ -4,13 +4,14 @@ from rich.segment import Segment from rich.style import Style from textual._styles_cache import StylesCache -from textual._types import Lines +from textual._types import Strips from textual.color import Color from textual.css.styles import Styles from textual.geometry import Region, Size +from textual.strip import Strip -def _extract_content(lines: Lines): +def _extract_content(lines: Strips): """Extract the text content from lines.""" content = ["".join(segment.text for segment in line) for line in lines] return content @@ -44,10 +45,11 @@ def test_no_styles(): ) style = Style.from_color(bgcolor=Color.parse("green").rich_color) expected = [ - [Segment("foo", style)], - [Segment("bar", style)], - [Segment("baz", style)], + Strip([Segment("foo", style)], 3), + Strip([Segment("bar", style)], 3), + Strip([Segment("baz", style)], 3), ] + assert lines == expected