Public Access
Give hosts and terminals their own screen, and the rest of the vault another
Rebuilds the client's shell from an imported design: a titlebar and nav rail it draws itself, real multi-session tabs over the one WebView, a Ctrl+K host search, and a vault screen that merges keys, passwords and pinned host keys into one table. Hosts left the vault column for their own screen beside the terminal, which is what the design asks for and turned out to be the better split anyway. Two screens the design shows have nothing behind them yet — file transfer and teams — and say so plainly rather than rendering invented data; every other gap between the design and this build is recorded in docs/design-import-gaps.md.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:DodoSSH.Client.App.ViewModels"
|
||||
x:Class="DodoSSH.Client.App.Views.TerminalTabs"
|
||||
x:DataType="vm:MainWindowViewModel">
|
||||
|
||||
<!--
|
||||
The tab strip above the terminal.
|
||||
|
||||
Every tab is one pane in the one WebView, so switching is a single frame telling the page which pane to
|
||||
show — nothing is created, nothing is destroyed, and the shell behind a hidden pane goes on running and
|
||||
goes on producing output. That is what makes tabs cost almost nothing here, and it is also why closing
|
||||
one is the only thing in this application that deliberately ends a session.
|
||||
|
||||
Three of the design's header controls are absent: SPLIT, FORWARDS and SNIPPETS. Splits would need a
|
||||
second pane geometry the renderer does not have, port forwarding does not exist in the SSH layer, and
|
||||
there is no snippet item type in the vault. Three disabled buttons would teach nobody anything; see
|
||||
docs/design-import-gaps.md.
|
||||
|
||||
An ItemsControl of buttons rather than a TabStrip, because the selection lives on the shell — a tab
|
||||
outlives the vault that opened it — and a strip that owned its own selection would be a second copy of
|
||||
that state.
|
||||
-->
|
||||
|
||||
<Border Height="34" Background="{StaticResource Chrome}"
|
||||
BorderBrush="{StaticResource Border}" BorderThickness="0,0,0,1">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
|
||||
<ScrollViewer Grid.Column="0" HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Disabled">
|
||||
<ItemsControl ItemsSource="{Binding Tabs}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:TerminalTabViewModel">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
|
||||
<Button Grid.Column="0" Classes="flat tab"
|
||||
Command="{Binding $parent[ItemsControl].((vm:MainWindowViewModel)DataContext).SelectTabCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
Classes.active="{Binding IsSelected}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="7" VerticalAlignment="Center">
|
||||
<!--
|
||||
Green while the shell behind this tab is running, grey once it has ended. The pane
|
||||
keeps its scrollback either way, which is usually why somebody is still looking at a
|
||||
tab whose dot has gone out.
|
||||
-->
|
||||
<Ellipse Classes="dot" Width="5" Height="5" Classes.live="{Binding IsLive}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding Label}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Column="1" Classes="flat close" Width="20"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{Binding $parent[ItemsControl].((vm:MainWindowViewModel)DataContext).CloseTabCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
ToolTip.Tip="Closes this terminal and ends its shell.">
|
||||
<TextBlock Text="✕" FontSize="10" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<!--
|
||||
Nothing open, and this is where that is said. The strip stays rather than collapsing — a row of
|
||||
chrome that appears and disappears moves the terminal up and down by 34 pixels every time the last
|
||||
tab closes — and it is also the only place near the terminal that can carry a sentence at all: the
|
||||
rectangle below is a native child window, and anything Avalonia draws in it is drawn underneath.
|
||||
-->
|
||||
<TextBlock Grid.Column="1" Classes="mono" FontSize="9.5"
|
||||
Text="no terminals open · choose a host and press Connect, or Ctrl+K"
|
||||
Foreground="{StaticResource TextFaint}" VerticalAlignment="Center" Margin="12,0"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
IsVisible="{Binding !HasTabs}" />
|
||||
|
||||
<TextBlock Grid.Column="2" Classes="mono" Text="{Binding SelectedTab.Address}" FontSize="9.5"
|
||||
Foreground="{StaticResource TextFaint}" VerticalAlignment="Center" Margin="12,0"
|
||||
TextTrimming="CharacterEllipsis" MaxWidth="280"
|
||||
IsVisible="{Binding HasTabs}" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</UserControl>
|
||||
Reference in New Issue
Block a user