mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Eager tasks are now enabled On Python3.12 and above https://github.com/Textualize/textual/pull/6102
|
||||
- `Widget._arrange` is now public (as `Widget.arrange`) https://github.com/Textualize/textual/pull/6108
|
||||
- Reduced number of layout operations required to update the screen https://github.com/Textualize/textual/pull/6108
|
||||
- The :hover pseudo-class no applies to the first widget under the mouse with a hover style set https://github.com/Textualize/textual/pull/6132
|
||||
- The footer key hover background is more visible https://github.com/Textualize/textual/pull/6132
|
||||
|
||||
### Added
|
||||
|
||||
@@ -19,6 +21,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Added `Widget.process_layout` https://github.com/Textualize/textual/pull/6105
|
||||
- Added `App.viewport_size` https://github.com/Textualize/textual/pull/6105
|
||||
- Added `Screen.size` https://github.com/Textualize/textual/pull/6105
|
||||
- Added `compact` to Binding.Group https://github.com/Textualize/textual/pull/6132
|
||||
- Added `Screen.get_hover_widgets_at` https://github.com/Textualize/textual/pull/6132
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -848,9 +848,10 @@ class Compositor:
|
||||
Sequence of (WIDGET, REGION) tuples.
|
||||
"""
|
||||
contains = Region.contains
|
||||
for widget, cropped_region, region in self.layers_visible[y]:
|
||||
if contains(cropped_region, x, y) and widget.visible:
|
||||
yield widget, region
|
||||
if len(self.layers_visible) > y >= 0:
|
||||
for widget, cropped_region, region in self.layers_visible[y]:
|
||||
if contains(cropped_region, x, y) and widget.visible:
|
||||
yield widget, region
|
||||
|
||||
def get_style_at(self, x: int, y: int) -> Style:
|
||||
"""Get the Style at the given cell or Style.null()
|
||||
|
||||
@@ -617,6 +617,9 @@ class App(Generic[ReturnType], DOMNode):
|
||||
self._sync_available = False
|
||||
|
||||
self.mouse_over: Widget | None = None
|
||||
"""The widget directly under the mouse."""
|
||||
self.hover_over: Widget | None = None
|
||||
"""The first widget with a hover style under the mouse."""
|
||||
self.mouse_captured: Widget | None = None
|
||||
self._driver: Driver | None = None
|
||||
self._exit_renderables: list[RenderableType] = []
|
||||
@@ -3010,7 +3013,9 @@ class App(Generic[ReturnType], DOMNode):
|
||||
"""
|
||||
self.screen.set_focus(widget, scroll_visible)
|
||||
|
||||
def _set_mouse_over(self, widget: Widget | None) -> None:
|
||||
def _set_mouse_over(
|
||||
self, widget: Widget | None, hover_widget: Widget | None
|
||||
) -> None:
|
||||
"""Called when the mouse is over another widget.
|
||||
|
||||
Args:
|
||||
@@ -3031,6 +3036,12 @@ class App(Generic[ReturnType], DOMNode):
|
||||
widget.post_message(events.Enter(widget))
|
||||
finally:
|
||||
self.mouse_over = widget
|
||||
if self.hover_over is not None:
|
||||
self.hover_over.mouse_hover = False
|
||||
if hover_widget is not None:
|
||||
hover_widget.mouse_hover = True
|
||||
|
||||
self.hover_over = hover_widget
|
||||
|
||||
def _update_mouse_over(self, screen: Screen) -> None:
|
||||
"""Updates the mouse over after the next refresh.
|
||||
@@ -3046,12 +3057,16 @@ class App(Generic[ReturnType], DOMNode):
|
||||
async def check_mouse() -> None:
|
||||
"""Check if the mouse over widget has changed."""
|
||||
try:
|
||||
widget, _ = screen.get_widget_at(*self.mouse_position)
|
||||
hover_widgets = screen.get_hover_widgets_at(*self.mouse_position)
|
||||
except NoWidget:
|
||||
pass
|
||||
else:
|
||||
if widget is not self.mouse_over:
|
||||
self._set_mouse_over(widget)
|
||||
mouse_over, hover_over = hover_widgets.widgets
|
||||
if (
|
||||
mouse_over is not self.mouse_over
|
||||
or hover_over is not self.hover_over
|
||||
):
|
||||
self._set_mouse_over(mouse_over, hover_over)
|
||||
|
||||
self.call_after_refresh(check_mouse)
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ class Binding:
|
||||
description: str = ""
|
||||
"""Description of the group."""
|
||||
|
||||
compact: bool = False
|
||||
"""Show keys in compact form (no spaces)."""
|
||||
|
||||
group: Group | None = None
|
||||
"""Optional binding group (used to group related bindings in the footer)."""
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ class ColorSystem:
|
||||
"block-cursor-blurred-text-style", "none"
|
||||
)
|
||||
colors["block-hover-background"] = get(
|
||||
"block-hover-background", boost.with_alpha(0.05).hex
|
||||
"block-hover-background", boost.with_alpha(0.1).hex
|
||||
)
|
||||
|
||||
# The border color for focused widgets which have a border.
|
||||
|
||||
@@ -83,7 +83,6 @@ class HorizontalLayout(Layout):
|
||||
children, box_models, margins
|
||||
):
|
||||
styles = widget.styles
|
||||
|
||||
overlay = styles.overlay == "screen"
|
||||
offset = (
|
||||
styles.offset.resolve(
|
||||
|
||||
@@ -65,6 +65,12 @@ class StreamLayout(Layout):
|
||||
if height < (max_height_value := int(max_height.value))
|
||||
else max_height_value
|
||||
)
|
||||
if (min_height := styles.min_height) is not None and min_height.is_cells:
|
||||
height = (
|
||||
height
|
||||
if height > (min_height_value := int(min_height.value))
|
||||
else min_height_value
|
||||
)
|
||||
placements.append(
|
||||
_WidgetPlacement(
|
||||
_Region(left, y, width - (left + right), height),
|
||||
|
||||
@@ -105,7 +105,6 @@ class VerticalLayout(Layout):
|
||||
content_width.__floor__(),
|
||||
next_y.__floor__() - y.__floor__(),
|
||||
)
|
||||
|
||||
absolute = styles.has_rule("position") and styles.position == "absolute"
|
||||
add_placement(
|
||||
_WidgetPlacement(
|
||||
|
||||
@@ -20,6 +20,7 @@ from typing import (
|
||||
Generic,
|
||||
Iterable,
|
||||
Iterator,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
TypeVar,
|
||||
Union,
|
||||
@@ -83,6 +84,23 @@ ScreenResultCallbackType = Union[
|
||||
"""Type of a screen result callback function."""
|
||||
|
||||
|
||||
class HoverWidgets(NamedTuple):
|
||||
"""Result of [get_hover_widget_at][textual.screen.Screen.get_hover_widget_at]"""
|
||||
|
||||
mouse_over: tuple[Widget, Region]
|
||||
"""Widget and region directly under the mouse."""
|
||||
hover_over: tuple[Widget, Region] | None
|
||||
"""Widget with a hover style under the mouse, or `None` for no hover style widget."""
|
||||
|
||||
@property
|
||||
def widgets(self) -> tuple[Widget, Widget | None]:
|
||||
"""Just the widgets."""
|
||||
return (
|
||||
self.mouse_over[0],
|
||||
None if self.hover_over is None else self.hover_over[0],
|
||||
)
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class ResultCallback(Generic[ScreenResultType]):
|
||||
"""Holds the details of a callback."""
|
||||
@@ -584,6 +602,33 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
"""
|
||||
return self._compositor.get_widget_at(x, y)
|
||||
|
||||
def get_hover_widgets_at(self, x: int, y: int) -> HoverWidgets:
|
||||
"""Get the widget, and its region directly under the mouse, and the first
|
||||
widget, region pair with a hover style.
|
||||
|
||||
Args:
|
||||
x: X Coordinate.
|
||||
y: Y Coordinate.
|
||||
|
||||
Returns:
|
||||
A pair of (WIDGET, REGION) tuples for the top most and first hover style respectively.
|
||||
|
||||
Raises:
|
||||
NoWidget: If there is no widget under the screen coordinate.
|
||||
|
||||
"""
|
||||
widgets_under_coordinate = iter(self._compositor.get_widgets_at(x, y))
|
||||
try:
|
||||
top_widget, top_region = next(widgets_under_coordinate)
|
||||
except StopIteration:
|
||||
raise errors.NoWidget(f"No hover widget under screen coordinate ({x}, {y})")
|
||||
if not top_widget._has_hover_style:
|
||||
for widget, region in widgets_under_coordinate:
|
||||
if widget._has_hover_style:
|
||||
return HoverWidgets((top_widget, top_region), (widget, region))
|
||||
return HoverWidgets((top_widget, top_region), None)
|
||||
return HoverWidgets((top_widget, top_region), (top_widget, top_region))
|
||||
|
||||
def get_widgets_at(self, x: int, y: int) -> Iterable[tuple[Widget, Region]]:
|
||||
"""Get all widgets under a given coordinate.
|
||||
|
||||
@@ -1380,7 +1425,7 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
"""Screen has suspended."""
|
||||
if self.app.SUSPENDED_SCREEN_CLASS:
|
||||
self.add_class(self.app.SUSPENDED_SCREEN_CLASS)
|
||||
self.app._set_mouse_over(None)
|
||||
self.app._set_mouse_over(None, None)
|
||||
self._clear_tooltip()
|
||||
self.stack_updates += 1
|
||||
|
||||
@@ -1492,14 +1537,17 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
tooltip.update(tooltip_content)
|
||||
|
||||
def _handle_mouse_move(self, event: events.MouseMove) -> None:
|
||||
hover_widget: Widget | None = None
|
||||
try:
|
||||
if self.app.mouse_captured:
|
||||
widget = self.app.mouse_captured
|
||||
region = self.find_widget(widget).region
|
||||
else:
|
||||
widget, region = self.get_widget_at(event.x, event.y)
|
||||
(widget, region), hover = self.get_hover_widgets_at(event.x, event.y)
|
||||
if hover is not None:
|
||||
hover_widget = hover[0]
|
||||
except errors.NoWidget:
|
||||
self.app._set_mouse_over(None)
|
||||
self.app._set_mouse_over(None, None)
|
||||
if self._tooltip_timer is not None:
|
||||
self._tooltip_timer.stop()
|
||||
if not self.app._disable_tooltips:
|
||||
@@ -1507,9 +1555,8 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
self.get_child_by_type(Tooltip).display = False
|
||||
except NoMatches:
|
||||
pass
|
||||
|
||||
else:
|
||||
self.app._set_mouse_over(widget)
|
||||
self.app._set_mouse_over(widget, hover_widget)
|
||||
widget.hover_style = event.style
|
||||
if widget is self:
|
||||
self.post_message(event)
|
||||
|
||||
@@ -690,7 +690,8 @@ class Strip:
|
||||
Returns:
|
||||
Text with ANSI escape sequences.
|
||||
"""
|
||||
ansi = style._ansi or cls.render_ansi(style, color_system)
|
||||
if (ansi := style._ansi) is None:
|
||||
ansi = cls.render_ansi(style, color_system)
|
||||
output = f"\x1b[{ansi}m{text}\x1b[0m" if ansi else text
|
||||
if style._link:
|
||||
output = (
|
||||
|
||||
@@ -11,7 +11,7 @@ from rich.text import Text
|
||||
from textual import events
|
||||
from textual.app import ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import ScrollableContainer
|
||||
from textual.containers import HorizontalGroup, ScrollableContainer
|
||||
from textual.reactive import reactive
|
||||
from textual.widget import Widget
|
||||
from textual.widgets import Label
|
||||
@@ -20,6 +20,15 @@ if TYPE_CHECKING:
|
||||
from textual.screen import Screen
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class KeyGroup(HorizontalGroup):
|
||||
DEFAULT_CSS = """
|
||||
KeyGroup {
|
||||
width: auto;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class FooterKey(Widget):
|
||||
ALLOW_SELECT = False
|
||||
@@ -32,6 +41,7 @@ class FooterKey(Widget):
|
||||
FooterKey {
|
||||
width: auto;
|
||||
height: 1;
|
||||
text-wrap: nowrap;
|
||||
background: $footer-item-background;
|
||||
.footer-key--key {
|
||||
color: $footer-key-foreground;
|
||||
@@ -87,6 +97,7 @@ class FooterKey(Widget):
|
||||
if disabled:
|
||||
classes += " -disabled"
|
||||
super().__init__(classes=classes)
|
||||
self.shrink = False
|
||||
if tooltip:
|
||||
self.tooltip = tooltip
|
||||
|
||||
@@ -98,6 +109,7 @@ class FooterKey(Widget):
|
||||
description_padding = self.get_component_styles(
|
||||
"footer-key--description"
|
||||
).padding
|
||||
|
||||
description = self.description
|
||||
if description:
|
||||
label_text = Text.assemble(
|
||||
@@ -144,7 +156,18 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
height: 1;
|
||||
scrollbar-size: 0 0;
|
||||
&.-compact {
|
||||
grid-gutter: 1;
|
||||
FooterLabel {
|
||||
margin: 0;
|
||||
}
|
||||
FooterKey {
|
||||
margin-right: 1;
|
||||
}
|
||||
FooterKey.-grouped {
|
||||
margin: 0 1;
|
||||
}
|
||||
FooterKey.-command-palette {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
FooterKey.-command-palette {
|
||||
dock: right;
|
||||
@@ -156,6 +179,22 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
height: 1;
|
||||
layout: horizontal;
|
||||
}
|
||||
KeyGroup.-compact {
|
||||
FooterKey.-grouped {
|
||||
margin: 0;
|
||||
}
|
||||
margin: 0 1 0 0;
|
||||
padding-left: 1;
|
||||
}
|
||||
|
||||
FooterKey.-grouped {
|
||||
margin: 0 1;
|
||||
}
|
||||
FooterLabel {
|
||||
margin: 0 1 0 0;
|
||||
color: $footer-description-foreground;
|
||||
background: $footer-description-background;
|
||||
}
|
||||
|
||||
&:ansi {
|
||||
background: ansi_default;
|
||||
@@ -180,19 +219,11 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
border-left: vkey ansi_black;
|
||||
}
|
||||
}
|
||||
FooterKey.-grouped {
|
||||
margin: 0 1;
|
||||
}
|
||||
FooterLabel {
|
||||
margin: 0 1;
|
||||
background: red;
|
||||
color: $footer-description-foreground;
|
||||
background: $footer-description-background;
|
||||
}
|
||||
|
||||
}
|
||||
"""
|
||||
|
||||
compact = reactive(False)
|
||||
compact = reactive(False, toggle_class="-compact")
|
||||
"""Display in compact style."""
|
||||
_bindings_ready = reactive(False, repaint=False)
|
||||
"""True if the bindings are ready to be displayed."""
|
||||
@@ -209,6 +240,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
classes: str | None = None,
|
||||
disabled: bool = False,
|
||||
show_command_palette: bool = True,
|
||||
compact: bool = False,
|
||||
) -> None:
|
||||
"""A footer to show key bindings.
|
||||
|
||||
@@ -219,6 +251,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
classes: The CSS classes for the widget.
|
||||
disabled: Whether the widget is disabled or not.
|
||||
show_command_palette: Show key binding to invoke the command palette, on the right of the footer.
|
||||
compact: Display a compact style (less whitespace) footer.
|
||||
"""
|
||||
super().__init__(
|
||||
*children,
|
||||
@@ -228,6 +261,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
disabled=disabled,
|
||||
)
|
||||
self.set_reactive(Footer.show_command_palette, show_command_palette)
|
||||
self.compact = compact
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
if not self._bindings_ready:
|
||||
@@ -247,23 +281,25 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
|
||||
for group, multi_bindings_iterable in groupby(
|
||||
action_to_bindings.values(),
|
||||
lambda multi_bindings: multi_bindings[0][0].group,
|
||||
lambda multi_bindings_: multi_bindings_[0][0].group,
|
||||
):
|
||||
if group is not None:
|
||||
for multi_bindings in multi_bindings_iterable:
|
||||
binding, enabled, tooltip = multi_bindings[0]
|
||||
yield FooterKey(
|
||||
binding.key,
|
||||
self.app.get_key_display(binding),
|
||||
"",
|
||||
binding.action,
|
||||
disabled=not enabled,
|
||||
tooltip=tooltip or binding.description,
|
||||
classes="-grouped",
|
||||
).data_bind(Footer.compact)
|
||||
multi_bindings = list(multi_bindings_iterable)
|
||||
if group is not None and len(multi_bindings) > 1:
|
||||
with KeyGroup(classes="-compact" if group.compact else ""):
|
||||
for multi_bindings in multi_bindings:
|
||||
binding, enabled, tooltip = multi_bindings[0]
|
||||
yield FooterKey(
|
||||
binding.key,
|
||||
self.app.get_key_display(binding),
|
||||
"",
|
||||
binding.action,
|
||||
disabled=not enabled,
|
||||
tooltip=tooltip or binding.description,
|
||||
classes="-grouped",
|
||||
).data_bind(compact=Footer.compact)
|
||||
yield FooterLabel(group.description)
|
||||
else:
|
||||
for multi_bindings in multi_bindings_iterable:
|
||||
for multi_bindings in multi_bindings:
|
||||
binding, enabled, tooltip = multi_bindings[0]
|
||||
yield FooterKey(
|
||||
binding.key,
|
||||
@@ -272,7 +308,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
binding.action,
|
||||
disabled=not enabled,
|
||||
tooltip=tooltip,
|
||||
).data_bind(Footer.compact)
|
||||
).data_bind(compact=Footer.compact)
|
||||
if self.show_command_palette and self.app.ENABLE_COMMAND_PALETTE:
|
||||
try:
|
||||
_node, binding, enabled, tooltip = active_bindings[
|
||||
@@ -324,6 +360,3 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
|
||||
def on_unmount(self) -> None:
|
||||
self.screen.bindings_updated_signal.unsubscribe(self)
|
||||
|
||||
def watch_compact(self, compact: bool) -> None:
|
||||
self.set_class(compact, "-compact")
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#121212" x="0" y="1.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="25.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="50.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="74.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="99.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="123.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="147.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="172.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="196.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="221.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="245.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="402.6" y="269.9" width="170.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="573.4" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="294.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="318.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="343.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="367.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="391.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="416.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="440.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="465.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="489.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="513.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="538.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#2e3841" x="0" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#2e3841" x="24.4" y="562.7" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="292.8" y="562.7" width="536.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="829.6" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="841.8" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="866.2" y="562.7" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="963.8" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#121212" x="0" y="1.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="25.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="50.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="74.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="99.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="123.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="147.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="172.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="196.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="221.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="245.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="402.6" y="269.9" width="170.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="573.4" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="294.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="318.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="343.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="367.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="391.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="416.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="440.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="465.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="489.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="513.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="538.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#39434b" x="0" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#39434b" x="24.4" y="562.7" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="292.8" y="562.7" width="536.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="829.6" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="841.8" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="866.2" y="562.7" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="963.8" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="976" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -121,7 +121,7 @@
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#121212" x="0" y="1.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="25.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="50.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="74.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="99.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="123.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="147.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="172.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="196.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="221.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="245.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="269.9" width="390.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="390.4" y="269.9" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="573.4" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="294.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="318.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="343.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="367.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="391.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="416.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="440.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="465.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="489.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="513.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="538.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#2e3841" x="0" y="562.7" width="48.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#2e3841" x="48.8" y="562.7" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="317.2" y="562.7" width="512.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="829.6" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="841.8" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="866.2" y="562.7" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="963.8" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#121212" x="0" y="1.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="25.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="50.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="74.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="99.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="123.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="147.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="172.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="196.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="221.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="245.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="269.9" width="390.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="390.4" y="269.9" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="573.4" y="269.9" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="294.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="318.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="343.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="367.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="391.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="416.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="440.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="465.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="489.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="513.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#121212" x="0" y="538.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#39434b" x="0" y="562.7" width="48.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#39434b" x="48.8" y="562.7" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="317.2" y="562.7" width="512.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="829.6" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="841.8" y="562.7" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="866.2" y="562.7" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#242f38" x="963.8" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="976" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user