Fix icon sizing.
This commit is contained in:
@@ -379,6 +379,11 @@ in principle, but a terminal grid is small.
|
||||
its pane count once a view holds more than one
|
||||
- Tabs: create, close, switch, and reorder by dragging a sidebar row, with the
|
||||
rows shuffling live as you drag; closing the last one closes the window
|
||||
- **A resizable sidebar**: the gutter beside it is a real divider, so drag it
|
||||
to taste. Dragging it all the way in — or `Ctrl+Shift+S`, or the chevron at
|
||||
the sidebar's foot — collapses the column to just each tab's emoji or icon
|
||||
(hover a row for its name; the status bar and wash still show); the same
|
||||
toggle expands it back to the width it had
|
||||
- Multiple panes per tab in an arbitrary split tree, rearranged by keyboard
|
||||
or by dragging a pane's header, with draggable dividers between them;
|
||||
closing the last pane in a view closes its tab
|
||||
@@ -432,6 +437,7 @@ in principle, but a terminal grid is small.
|
||||
| `Ctrl+Shift+C` | copy the terminal selection | `copy` |
|
||||
| `Ctrl+Shift+R` | rename the current tab (empty name = follow the terminal) | `rename_tab` |
|
||||
| `Ctrl+Shift+Z`, `Ctrl+Shift+F` | zoom the focused pane to fill the tab, and back | `toggle_zoom` |
|
||||
| `Ctrl+Shift+S` | collapse the sidebar to its emoji column, and back | `toggle_sidebar` |
|
||||
| `Ctrl+F` | find in the focused web page (web panes only — see [Find in page](#find-in-page)) | `find` |
|
||||
| `Ctrl+,` | settings | `open_settings` |
|
||||
| `Ctrl+PageUp/PageDown`, `Alt+Shift+K/J` | previous / next tab | `prev_tab`, `next_tab` |
|
||||
|
||||
+233
-15
@@ -31,18 +31,55 @@ const shortcuts = @import("shortcuts.zig");
|
||||
|
||||
const Window = @This();
|
||||
|
||||
/// Total width of the sidebar column, margins and border included — GTK folds
|
||||
/// Default width of the sidebar column, margins and border included — GTK folds
|
||||
/// both into a widget's size request. Widened when the sidebar became an inset
|
||||
/// card: the margin, border and roomier row padding all come out of the label,
|
||||
/// and at the old 220 a tab name truncated a good deal earlier than it used to.
|
||||
///
|
||||
/// A default rather than a fixture now that the divider beside the sidebar is
|
||||
/// draggable: it is where the column starts, and where the collapse toggle
|
||||
/// returns to when nothing has been dragged.
|
||||
const sidebar_width = 236;
|
||||
|
||||
/// The sidebar folded down to its leading column: the margin, border, list and
|
||||
/// row padding, and the 16px slot the emoji (or kind icon) draws in. Nothing
|
||||
/// else fits at this width, which is the point — see `applySidebarCollapsed`.
|
||||
const sidebar_collapsed_width = 56;
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
window: *adw.ApplicationWindow,
|
||||
|
||||
/// Holds one page per tab; the visible page is the active terminal.
|
||||
stack: *gtk.Stack,
|
||||
|
||||
/// The paned holding the sidebar and the content, whose divider position *is*
|
||||
/// the sidebar's width. A paned rather than a box so the divider is draggable.
|
||||
split: *gtk.Paned,
|
||||
|
||||
/// Sidebar chrome that collapsing has to reach: the header (whose window
|
||||
/// controls go), the layouts button beside the new-tab one, the footer (which
|
||||
/// stacks its buttons when the column is narrow) and the toggle itself.
|
||||
header: *adw.HeaderBar,
|
||||
layout_button: *gtk.MenuButton,
|
||||
footer: *gtk.Box,
|
||||
collapse_button: *gtk.Button,
|
||||
|
||||
/// Whether the sidebar is folded down to its emoji column.
|
||||
sidebar_collapsed: bool = false,
|
||||
|
||||
/// The width to put back when the sidebar expands: wherever the divider last
|
||||
/// sat while the chrome was showing, so a collapse costs no arrangement.
|
||||
sidebar_expanded_width: c_int = sidebar_width,
|
||||
|
||||
/// The position a drag has to reach before a collapsed sidebar unfolds. Set to
|
||||
/// the expanded minimum measured at the moment of collapse, so folding and
|
||||
/// unfolding by drag happen at the same width.
|
||||
sidebar_expand_at: c_int = sidebar_width,
|
||||
|
||||
/// Set while we're moving the divider ourselves, so the position handler
|
||||
/// doesn't mistake it for a drag.
|
||||
applying_position: bool = false,
|
||||
|
||||
/// One row per tab, in the same order as `tabs`.
|
||||
///
|
||||
/// Kept in that order by a sort function rather than by moving rows around:
|
||||
@@ -138,6 +175,10 @@ const Tab = struct {
|
||||
/// Status dot, hidden unless the tab has something to report.
|
||||
dot: *gtk.Image,
|
||||
|
||||
/// The row's close button, hidden along with the label while the sidebar
|
||||
/// is collapsed.
|
||||
close: *gtk.Button,
|
||||
|
||||
/// A name the user typed, which wins over whatever the panes report.
|
||||
/// Null means the label tracks the content, which is the default.
|
||||
custom_name: ?[]u8 = null,
|
||||
@@ -191,9 +232,14 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
.alloc = alloc,
|
||||
.window = window,
|
||||
.stack = gtk.Stack.new(),
|
||||
.split = gtk.Paned.new(.horizontal),
|
||||
.list = gtk.ListBox.new(),
|
||||
.layouts = .init(alloc),
|
||||
.layout_popover = gtk.Popover.new(),
|
||||
.header = adw.HeaderBar.new(),
|
||||
.layout_button = gtk.MenuButton.new(),
|
||||
.footer = gtk.Box.new(.horizontal, 0),
|
||||
.collapse_button = gtk.Button.newFromIconName("go-previous-symbolic"),
|
||||
};
|
||||
self.layouts.load();
|
||||
if (self.layouts.load_error) |message| std.log.warn("{s}", .{message});
|
||||
@@ -203,13 +249,17 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
// ---- sidebar -------------------------------------------------------
|
||||
const sidebar = gtk.Box.new(.vertical, 0);
|
||||
sidebar.as(gtk.Widget).addCssClass("playpen-sidebar");
|
||||
sidebar.as(gtk.Widget).setSizeRequest(sidebar_width, -1);
|
||||
|
||||
// The request is the *floor*, not the width: the paned's divider decides
|
||||
// how wide the column actually is, and this is as far in as it may be
|
||||
// pushed once the chrome is out of the way.
|
||||
sidebar.as(gtk.Widget).setSizeRequest(sidebar_collapsed_width, -1);
|
||||
|
||||
// The header bar lives inside the sidebar rather than spanning the
|
||||
// window, which is what gives the Zen-style look. It also carries the
|
||||
// window controls, which we still need since GTK draws its own
|
||||
// decorations on Wayland.
|
||||
const header = adw.HeaderBar.new();
|
||||
const header = self.header;
|
||||
header.setShowTitle(0);
|
||||
header.as(gtk.Widget).addCssClass("flat");
|
||||
|
||||
@@ -234,7 +284,7 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
|
||||
// Layouts sit behind their own button rather than replacing the plain
|
||||
// new-tab one: opening an ordinary shell stays a single click.
|
||||
const layout_button = gtk.MenuButton.new();
|
||||
const layout_button = self.layout_button;
|
||||
layout_button.setIconName("view-grid-symbolic");
|
||||
layout_button.as(gtk.Widget).addCssClass("playpen-header-button");
|
||||
layout_button.as(gtk.Widget).setTooltipText("Open a saved layout");
|
||||
@@ -273,7 +323,7 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
// saved layout — and a preferences button is the opposite of that: opened
|
||||
// rarely, and never in a hurry. Below the tab list it stays out of the way
|
||||
// of both, and it is where every other sidebar puts it.
|
||||
const footer = gtk.Box.new(.horizontal, 0);
|
||||
const footer = self.footer;
|
||||
footer.as(gtk.Widget).addCssClass("playpen-sidebar-footer");
|
||||
|
||||
const settings_button = gtk.Button.newFromIconName("emblem-system-symbolic");
|
||||
@@ -288,6 +338,26 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
.{},
|
||||
);
|
||||
footer.append(settings_button.as(gtk.Widget));
|
||||
|
||||
// An empty stretch between the two buttons, so the collapse toggle sits at
|
||||
// the far end. It has no height of its own, so when the collapsed footer
|
||||
// turns vertical it simply does nothing rather than pushing the buttons
|
||||
// apart.
|
||||
const footer_spacer = gtk.Box.new(.horizontal, 0);
|
||||
footer_spacer.as(gtk.Widget).setHexpand(1);
|
||||
footer.append(footer_spacer.as(gtk.Widget));
|
||||
|
||||
self.collapse_button.as(gtk.Widget).addCssClass("flat");
|
||||
self.collapse_button.as(gtk.Widget).addCssClass("playpen-settings-button");
|
||||
self.collapse_button.as(gtk.Widget).setTooltipText("Collapse the sidebar (Ctrl+Shift+S)");
|
||||
_ = gtk.Button.signals.clicked.connect(
|
||||
self.collapse_button,
|
||||
*Window,
|
||||
&onCollapseClicked,
|
||||
self,
|
||||
.{},
|
||||
);
|
||||
footer.append(self.collapse_button.as(gtk.Widget));
|
||||
sidebar.append(footer.as(gtk.Widget));
|
||||
|
||||
// ---- content -------------------------------------------------------
|
||||
@@ -295,11 +365,29 @@ pub fn create(alloc: std.mem.Allocator, app: *adw.Application) !*Window {
|
||||
self.stack.as(gtk.Widget).setVexpand(1);
|
||||
self.stack.as(gtk.Widget).addCssClass("playpen-content");
|
||||
|
||||
const content = gtk.Box.new(.horizontal, 0);
|
||||
content.append(sidebar.as(gtk.Widget));
|
||||
content.append(self.stack.as(gtk.Widget));
|
||||
// The divider between the sidebar and the content is the 6px gutter that
|
||||
// was already there, now draggable. Only the content flexes with the
|
||||
// window — the sidebar keeps whatever width it was given — and neither
|
||||
// side may be squeezed below its minimum, which for the sidebar is the
|
||||
// emoji-only column.
|
||||
self.split.as(gtk.Widget).addCssClass("playpen-root-split");
|
||||
self.split.setStartChild(sidebar.as(gtk.Widget));
|
||||
self.split.setEndChild(self.stack.as(gtk.Widget));
|
||||
self.split.setResizeStartChild(0);
|
||||
self.split.setResizeEndChild(1);
|
||||
self.split.setShrinkStartChild(0);
|
||||
self.split.setShrinkEndChild(0);
|
||||
self.split.setWideHandle(1);
|
||||
self.setSidebarPosition(sidebar_width);
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
self.split,
|
||||
*Window,
|
||||
&onSidebarPosition,
|
||||
self,
|
||||
.{ .detail = "position" },
|
||||
);
|
||||
|
||||
window.setContent(content.as(gtk.Widget));
|
||||
window.setContent(self.split.as(gtk.Widget));
|
||||
|
||||
// Window-level shortcuts run in the capture phase so they are handled
|
||||
// before the focused terminal turns the key into a VT sequence.
|
||||
@@ -385,6 +473,7 @@ fn newTabEmpty(self: *Window) !*Tab {
|
||||
.icon = gtk.Image.newFromIconName("utilities-terminal-symbolic"),
|
||||
.emoji_label = gtk.Label.new(null),
|
||||
.dot = gtk.Image.newFromIconName(Pane.status_icon),
|
||||
.close = gtk.Button.newFromIconName("window-close-symbolic"),
|
||||
.menu_popover = gtk.Popover.new(),
|
||||
.rename_popover = gtk.Popover.new(),
|
||||
.rename_entry = gtk.Entry.new(),
|
||||
@@ -417,11 +506,10 @@ fn newTabEmpty(self: *Window) !*Tab {
|
||||
Pane.applyAttention(tab.row.as(gtk.Widget), tab.dot, .none);
|
||||
row_box.append(tab.dot.as(gtk.Widget));
|
||||
|
||||
const close = gtk.Button.newFromIconName("window-close-symbolic");
|
||||
close.as(gtk.Widget).addCssClass("flat");
|
||||
close.as(gtk.Widget).addCssClass("playpen-close");
|
||||
_ = gtk.Button.signals.clicked.connect(close, *Tab, &onCloseClicked, tab, .{});
|
||||
row_box.append(close.as(gtk.Widget));
|
||||
tab.close.as(gtk.Widget).addCssClass("flat");
|
||||
tab.close.as(gtk.Widget).addCssClass("playpen-close");
|
||||
_ = gtk.Button.signals.clicked.connect(tab.close, *Tab, &onCloseClicked, tab, .{});
|
||||
row_box.append(tab.close.as(gtk.Widget));
|
||||
|
||||
tab.row.setChild(row_box.as(gtk.Widget));
|
||||
self.buildRowMenu(tab, row_box);
|
||||
@@ -429,6 +517,9 @@ fn newTabEmpty(self: *Window) !*Tab {
|
||||
installRowDragSource(tab, row_box);
|
||||
self.list.append(tab.row.as(gtk.Widget));
|
||||
|
||||
// A tab opened while the sidebar is collapsed starts collapsed too.
|
||||
self.applyRowCollapsed(tab);
|
||||
|
||||
_ = self.stack.addNamed(view.widget(), tab.pageName());
|
||||
|
||||
try self.tabs.append(self.alloc, tab);
|
||||
@@ -1384,6 +1475,128 @@ fn closeTab(self: *Window, tab: *Tab) void {
|
||||
self.select(self.tabs.items[next]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Sidebar width
|
||||
//
|
||||
// The divider beside the sidebar is a real paned handle, so the column is
|
||||
// resizable by drag. Below a certain width the sidebar stops being a list of
|
||||
// names and becomes a list of emoji, and that switch is a *mode*, not a
|
||||
// squeeze: the labels, dots, close buttons, layouts button and window controls
|
||||
// all leave, because at emoji width every one of them would be clipped rather
|
||||
// than small. The mode is entered three ways — the footer toggle, the
|
||||
// `toggle_sidebar` shortcut, and dragging the divider all the way in — and all
|
||||
// three meet in `applySidebarCollapsed`.
|
||||
|
||||
fn onCollapseClicked(_: *gtk.Button, self: *Window) callconv(.c) void {
|
||||
self.toggleSidebar();
|
||||
}
|
||||
|
||||
/// Toggle between the emoji-only column and the last expanded width — which is
|
||||
/// the default width until a drag has said otherwise.
|
||||
fn toggleSidebar(self: *Window) void {
|
||||
if (self.sidebar_collapsed) {
|
||||
self.applySidebarCollapsed(false);
|
||||
self.setSidebarPosition(self.sidebar_expanded_width);
|
||||
} else {
|
||||
self.sidebar_expanded_width = self.split.getPosition();
|
||||
self.applySidebarCollapsed(true);
|
||||
self.setSidebarPosition(sidebar_collapsed_width);
|
||||
}
|
||||
}
|
||||
|
||||
/// Show or hide everything that doesn't fit an emoji-wide column. The width
|
||||
/// itself is the caller's business: the toggle sets it, and a drag is already
|
||||
/// setting it.
|
||||
fn applySidebarCollapsed(self: *Window, collapsed: bool) void {
|
||||
if (self.sidebar_collapsed == collapsed) return;
|
||||
|
||||
// Measured before anything hides: this is the narrowest the expanded
|
||||
// sidebar can be, so it is where a drag has to reach before the chrome is
|
||||
// given back — the same width folding happened at, which is what keeps a
|
||||
// slow drag from flickering between the two modes.
|
||||
if (collapsed) {
|
||||
self.sidebar_expand_at = @max(
|
||||
minPosition(self.split),
|
||||
sidebar_collapsed_width + 24,
|
||||
);
|
||||
}
|
||||
|
||||
self.sidebar_collapsed = collapsed;
|
||||
|
||||
const shown: c_int = @intFromBool(!collapsed);
|
||||
|
||||
// The window controls belong to the desktop, but at 56px they would be
|
||||
// clipped mid-button, which is worse than absent. Closing the window is
|
||||
// still one expand away, or a keyboard shortcut that never left.
|
||||
self.header.setShowStartTitleButtons(shown);
|
||||
self.header.setShowEndTitleButtons(shown);
|
||||
self.layout_button.as(gtk.Widget).setVisible(shown);
|
||||
|
||||
// Two buttons side by side don't fit the collapsed column, so the footer
|
||||
// stacks them instead of losing one.
|
||||
self.footer.as(gtk.Orientable).setOrientation(if (collapsed) .vertical else .horizontal);
|
||||
|
||||
self.collapse_button.setIconName(if (collapsed)
|
||||
"go-next-symbolic"
|
||||
else
|
||||
"go-previous-symbolic");
|
||||
self.collapse_button.as(gtk.Widget).setTooltipText(if (collapsed)
|
||||
"Expand the sidebar (Ctrl+Shift+S)"
|
||||
else
|
||||
"Collapse the sidebar (Ctrl+Shift+S)");
|
||||
|
||||
for (self.tabs.items) |tab| self.applyRowCollapsed(tab);
|
||||
}
|
||||
|
||||
/// One row's share of the collapse: everything but the emoji (or kind icon)
|
||||
/// goes. The status dot goes too — the bar down the row's leading edge and the
|
||||
/// wash behind it carry the state at this width, and they were designed to be
|
||||
/// the glanceable half of the pair anyway.
|
||||
fn applyRowCollapsed(self: *Window, tab: *Tab) void {
|
||||
const shown: c_int = @intFromBool(!self.sidebar_collapsed);
|
||||
tab.label.as(gtk.Widget).setVisible(shown);
|
||||
tab.dot.as(gtk.Widget).setVisible(shown);
|
||||
tab.close.as(gtk.Widget).setVisible(shown);
|
||||
}
|
||||
|
||||
/// Move the divider ourselves, without the position handler reading it as a
|
||||
/// drag.
|
||||
fn setSidebarPosition(self: *Window, position: c_int) void {
|
||||
self.applying_position = true;
|
||||
defer self.applying_position = false;
|
||||
self.split.setPosition(position);
|
||||
}
|
||||
|
||||
/// The divider moved by hand. Expanded, the paned won't let a drag go below
|
||||
/// the chrome's own minimum — so a position *at* that minimum means the drag is
|
||||
/// pinned against it and wants less, and the answer is to fold. Hiding the
|
||||
/// chrome lowers the paned's minimum, which is what lets the same drag carry on
|
||||
/// down to the emoji column. Dragging back out past where the fold happened
|
||||
/// unfolds again.
|
||||
fn onSidebarPosition(paned: *gtk.Paned, _: *gobject.ParamSpec, self: *Window) callconv(.c) void {
|
||||
if (self.applying_position) return;
|
||||
const position = paned.getPosition();
|
||||
|
||||
if (self.sidebar_collapsed) {
|
||||
if (position >= self.sidebar_expand_at) self.applySidebarCollapsed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (position <= minPosition(paned)) {
|
||||
self.applySidebarCollapsed(true);
|
||||
return;
|
||||
}
|
||||
|
||||
self.sidebar_expanded_width = position;
|
||||
}
|
||||
|
||||
fn minPosition(paned: *gtk.Paned) c_int {
|
||||
var value = gobject.ext.Value.new(c_int);
|
||||
defer value.unset();
|
||||
paned.as(gobject.Object).getProperty("min-position", &value);
|
||||
return gobject.ext.Value.get(&value, c_int);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Settings
|
||||
|
||||
@@ -1472,7 +1685,11 @@ fn refreshLabel(self: *Window, tab: *Tab) void {
|
||||
buf[text.len] = 0;
|
||||
|
||||
tab.label.setText(buf[0..text.len :0]);
|
||||
tab.label.as(gtk.Widget).setTooltipText(buf[0..text.len :0]);
|
||||
|
||||
// On the row rather than the label, so a collapsed sidebar — where the
|
||||
// label is hidden and the emoji is all a row shows — still says which tab
|
||||
// an emoji is when you hover it.
|
||||
tab.row.as(gtk.Widget).setTooltipText(buf[0..text.len :0]);
|
||||
|
||||
// An emoji replaces the icon rather than joining it. The row has one slot
|
||||
// for "what is this tab", and filling it twice would spend twice the width
|
||||
@@ -1672,6 +1889,7 @@ fn perform(self: *Window, action: shortcuts.Action) bool {
|
||||
.new_web => self.addPane(.web),
|
||||
.rename_tab => if (self.activeTab()) |tab| self.beginRename(tab),
|
||||
.toggle_zoom => if (self.activeTab()) |tab| tab.view.toggleZoomFocused(),
|
||||
.toggle_sidebar => self.toggleSidebar(),
|
||||
.open_settings => self.openSettings(),
|
||||
|
||||
// Only a terminal needs us to encode a paste for it. A web pane has its
|
||||
|
||||
@@ -110,6 +110,7 @@ pub const Action = enum {
|
||||
new_web,
|
||||
rename_tab,
|
||||
toggle_zoom,
|
||||
toggle_sidebar,
|
||||
paste,
|
||||
copy,
|
||||
find,
|
||||
@@ -158,6 +159,7 @@ pub const defaults: []const Binding = &.{
|
||||
.{ .chord = chord("ctrl+shift+r"), .action = .rename_tab },
|
||||
.{ .chord = chord("ctrl+shift+z"), .action = .toggle_zoom },
|
||||
.{ .chord = chord("ctrl+shift+f"), .action = .toggle_zoom },
|
||||
.{ .chord = chord("ctrl+shift+s"), .action = .toggle_sidebar },
|
||||
.{ .chord = chord("ctrl+shift+v"), .action = .paste },
|
||||
.{ .chord = chord("ctrl+shift+c"), .action = .copy },
|
||||
.{ .chord = chord("ctrl+f"), .action = .find },
|
||||
@@ -193,6 +195,10 @@ pub const defaults: []const Binding = &.{
|
||||
/// default is a build failure rather than a shortcut that quietly isn't there.
|
||||
fn chord(comptime text: []const u8) Chord {
|
||||
comptime {
|
||||
// The whole defaults table parses in one comptime evaluation, and the
|
||||
// key-name lookup walks a large enum per entry; the default quota is
|
||||
// a few chords too small for the table's current size.
|
||||
@setEvalBranchQuota(100_000);
|
||||
const parsed = parse(text) orelse @compileError("not a chord: " ++ text);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
+17
-5
@@ -225,12 +225,12 @@ dnd.playpen-tab-drag {
|
||||
background-color: @pp_bg;
|
||||
}
|
||||
|
||||
/* A view is the container for one tab's terminals. Even padding now that the
|
||||
sidebar is inset too — the left edge used to be flush against the sidebar's
|
||||
border, so the gutter around the content was open on three sides and closed
|
||||
on the fourth. */
|
||||
/* A view is the container for one tab's terminals. The left side has no
|
||||
padding of its own: the root split's separator is the 6px gutter there, so
|
||||
the content stays evenly inset while that gap doubles as the drag handle
|
||||
that resizes the sidebar. */
|
||||
.playpen-view {
|
||||
padding: 6px;
|
||||
padding: 6px 6px 6px 0;
|
||||
}
|
||||
|
||||
/* Paned itself draws nothing; the panes inside it carry the styling. */
|
||||
@@ -724,6 +724,18 @@ dnd.playpen-tab-drag {
|
||||
box-shadow: inset 0 0 0 1px @pp_accent;
|
||||
}
|
||||
|
||||
/* The divider between the sidebar and the content: the gutter that was always
|
||||
there, made draggable. It paints as the backdrop so nothing looks different
|
||||
until it is hovered, the same way the pane dividers behave. */
|
||||
.playpen-root-split > separator {
|
||||
background-color: @pp_bg;
|
||||
min-width: 6px;
|
||||
}
|
||||
|
||||
.playpen-root-split > separator:hover {
|
||||
background-color: @pp_accent_muted;
|
||||
}
|
||||
|
||||
/* Divider between panes. Wide enough to grab without hunting for it. */
|
||||
.playpen-view paned > separator {
|
||||
background-color: @pp_bg;
|
||||
|
||||
Reference in New Issue
Block a user