mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-10-03 00:01:55 +00:00
style(sidebar): mark pinned groups with ◆ instead of a pin icon, drop the divider (#972)
The pin icon read as a smudge at header size. Kept groups now carry a small ◆ beside their name — every kept group, label groups too, since with the divider gone it is the one thing that tells kept from derived. On a folder group the mark is still the click that unpins it, and the hover button that pins an auto group shows the same character. The divider is no longer drawn at rest. It keeps its (smaller) place in the layout and its recorded bounds, so pinning a header by dragging it up and handing a tab back by dropping it below behave exactly as before, and it still shows as a line while it is the drop target.
This commit is contained in:
+18
-18
@@ -88,24 +88,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
command once, the same as after a restart.
|
||||
|
||||
- **The sidebar groups tabs by repo automatically; pin what you want to keep**
|
||||
(#955). Groups now come in two halves, split by a divider. Below it, every
|
||||
tab you have not pinned is filed under its git repository, and an SSH tab
|
||||
under the host it is on rather than its remote path — `/home/ubuntu` on two
|
||||
machines used to share a header. Above it sit the groups you keep, in the
|
||||
order you drag them into, until you delete them. A pinned group can keep a
|
||||
folder: a tab whose working directory enters it joins it (the deepest folder
|
||||
wins when they nest, and a worktree of a pinned repo counts), while a tab you
|
||||
drag out stays out until it leaves the folder and comes back. Pin an auto
|
||||
group with the pin on its header or by dragging the header above the
|
||||
divider; pin a folder by dropping it from Finder, with **Pin as Group** in the
|
||||
Files panel, or with **Open Folder as Group…** in the palette. **New Group**
|
||||
in the palette or on a tab's right-click makes a label group. Deleting a
|
||||
group closes nothing — its tabs go back to auto grouping — and dragging a tab
|
||||
below the divider does the same for one tab. Groups, their order and which
|
||||
are folded are stored with the workspace, so every window onto it agrees.
|
||||
**Settings → Window & Tabs → Auto grouping** replaces the three-way *Sidebar
|
||||
grouping* choice; off, unpinned tabs sit in one flat list under the pinned
|
||||
groups. Scratch is now **Ungrouped**.
|
||||
(#955). Groups now come in two halves. Below, every tab you have not pinned is
|
||||
filed under its git repository, and an SSH tab under the host it is on rather
|
||||
than its remote path — `/home/ubuntu` on two machines used to share a header.
|
||||
Above sit the groups you keep, each marked ◆ beside its name, in the order you
|
||||
drag them into, until you delete them. A pinned group can keep a folder: a tab
|
||||
whose working directory enters it joins it (the deepest folder wins when they
|
||||
nest, and a worktree of a pinned repo counts), while a tab you drag out stays
|
||||
out until it leaves the folder and comes back. Pin an auto group with the ◆ on
|
||||
its header or by dragging the header up among the pinned ones; pin a folder by
|
||||
dropping it from Finder, with **Pin as Group** in the Files panel, or with
|
||||
**Open Folder as Group…** in the palette. **New Group** in the palette or on a
|
||||
tab's right-click makes a label group. Deleting a group closes nothing — its
|
||||
tabs go back to auto grouping — and dragging a tab below the pinned groups
|
||||
does the same for one tab. Groups, their order and which are folded are stored
|
||||
with the workspace, so every window onto it agrees. **Settings → Window & Tabs
|
||||
→ Auto grouping** replaces the three-way *Sidebar grouping* choice; off,
|
||||
unpinned tabs sit in one flat list under the pinned groups. Scratch is now
|
||||
**Ungrouped**.
|
||||
|
||||
- **The New Tab menu names three shells, not every one the machine has.** A
|
||||
stock macOS box reports nine, so the `+` menu opened on a column of `csh`,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 17v5"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"/></svg>
|
||||
|
Before Width: | Height: | Size: 424 B |
+12
-10
@@ -18,17 +18,19 @@ is doing.
|
||||
|
||||
The sidebar groups tabs by repository automatically. Pin what you want to keep.
|
||||
|
||||
**Auto groups** sit below a divider. Every tab you have not pinned is filed
|
||||
under the git repository its working directory is in — a linked worktree under
|
||||
the repository it belongs to, a submodule under itself — and an SSH tab under
|
||||
the host it is connected to, so `/home/ubuntu` on two machines is two groups.
|
||||
**Auto groups** sit below the pinned ones. Every tab you have not pinned is
|
||||
filed under the git repository its working directory is in — a linked worktree
|
||||
under the repository it belongs to, a submodule under itself — and an SSH tab
|
||||
under the host it is connected to, so `/home/ubuntu` on two machines is two
|
||||
groups.
|
||||
Everything else collects in a trailing **Ungrouped** section. An auto group
|
||||
follows the tab's working directory, not its history: `cd` into another
|
||||
repository and the row moves; switching branches never does. When its last tab
|
||||
leaves, the group is gone.
|
||||
|
||||
**Pinned groups** sit above the divider, in the order you put them, and stay
|
||||
until you delete them — an empty one keeps its place with a **+ New Tab** row.
|
||||
**Pinned groups** sit at the top, each marked ◆ beside its name, in the order
|
||||
you put them, and stay until you delete them — an empty one keeps its place
|
||||
with a **+ New Tab** row.
|
||||
A tab in a pinned group never leaves it on its own. There are two kinds:
|
||||
|
||||
- A **folder group** keeps a directory. A tab whose working directory *enters*
|
||||
@@ -36,7 +38,7 @@ A tab in a pinned group never leaves it on its own. There are two kinds:
|
||||
repository the folder is. When folders nest, the deepest one wins, so pinning
|
||||
a monorepo and one package in it files the package's tabs under the package.
|
||||
A tab you drag out while it is still inside stays out until it leaves the
|
||||
folder and comes back. Hover the header for the folder's path; click its pin
|
||||
folder and comes back. Hover the header for the folder's path; click its ◆
|
||||
to unpin it, and its tabs go back to auto groups.
|
||||
- A **label group** is just a name, for tabs that belong together for a reason
|
||||
no directory shows. Tabs go in and out of it by hand.
|
||||
@@ -45,7 +47,7 @@ Ways to pin:
|
||||
|
||||
| To get | Do this |
|
||||
|---|---|
|
||||
| A folder group from an auto group | Click the pin on its header, or drag the header above the divider |
|
||||
| A folder group from an auto group | Click the ◆ on its header, or drag the header up among the pinned groups |
|
||||
| A folder group from a folder | Drop it from Finder onto the sidebar, choose **Pin as Group** on it in the Files panel, or run **Open Folder as Group…** from the command palette |
|
||||
| A label group | Right-click a tab → **Move to Group → New Group…**, or run **New Group** from the command palette |
|
||||
|
||||
@@ -92,8 +94,8 @@ they simply stop opening the overlay.
|
||||
|
||||
Drag a row to reorder it within its group, or drag a group header to move the
|
||||
group — pinned groups among pinned groups, auto groups among auto groups. Drag
|
||||
a row onto a pinned group to put it there, or anywhere below the divider to
|
||||
hand it back to auto grouping. A row cannot be dragged into an auto group: its
|
||||
a row onto a pinned group to put it there, or anywhere below the pinned groups
|
||||
to hand it back to auto grouping. A row cannot be dragged into an auto group: its
|
||||
membership comes from the working directory, so `cd` is what moves it.
|
||||
|
||||
Drag a row out over the panes instead and it stops being a session of its own:
|
||||
|
||||
@@ -34,7 +34,6 @@ fn agent_icon(path: &str) -> Option<&'static [u8]> {
|
||||
"icons/panel-left.svg" => include_bytes!("../../assets/icons/panel-left.svg"),
|
||||
"icons/panel-right.svg" => include_bytes!("../../assets/icons/panel-right.svg"),
|
||||
"icons/plus.svg" => include_bytes!("../../assets/icons/plus.svg"),
|
||||
"icons/pin.svg" => include_bytes!("../../assets/icons/pin.svg"),
|
||||
"icons/ellipsis.svg" => include_bytes!("../../assets/icons/ellipsis.svg"),
|
||||
"icons/folder-closed.svg" => include_bytes!("../../assets/icons/folder-closed.svg"),
|
||||
"icons/folder-open.svg" => include_bytes!("../../assets/icons/folder-open.svg"),
|
||||
|
||||
+78
-41
@@ -34,6 +34,17 @@ const GRAB_HANDLE_W: f32 = 48.;
|
||||
|
||||
const ROW_GAP: f32 = 2.;
|
||||
|
||||
/// What marks a kept group, and what the header button that keeps one reads.
|
||||
///
|
||||
/// A character rather than an icon: at a header's size a drawn pin is a
|
||||
/// smudge, and the mark only has to say "kept" beside the name, the way a
|
||||
/// bullet does. With no line between kept and derived groups it is also the
|
||||
/// only thing that tells the two apart, so every kept group carries it.
|
||||
const PIN_MARK: &str = "\u{25C6}";
|
||||
|
||||
/// The mark's size: small enough to sit under the header text's x-height.
|
||||
const PIN_MARK_SIZE: f32 = 8.;
|
||||
|
||||
/// A single-line tab row: one line of `text_sm` and a little air, the same
|
||||
/// 28px the search field and the workspace chip above it stand at.
|
||||
const ROW_HEIGHT: f32 = 28.;
|
||||
@@ -1283,37 +1294,39 @@ impl Tty7App {
|
||||
.child(Icon::new(IconName::ChevronRight).xsmall()),
|
||||
)
|
||||
})
|
||||
// The pin marks a folder group: kept, and keeping a folder.
|
||||
// It is also the way to stop keeping it — a click unpins,
|
||||
// and the folder's tabs fall back to the groups their cwds
|
||||
// resolve to. A label group has no such mark: it sits above
|
||||
// the divider, and there is no folder to fall back on.
|
||||
.when_some(
|
||||
pinned_id.filter(|_| pinned_folder.is_some()),
|
||||
|header, id| {
|
||||
header.child(
|
||||
div()
|
||||
.id(("sidebar-group-unpin", group_ix))
|
||||
.flex_shrink_0()
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(cx.theme().foreground))
|
||||
.child(Icon::empty().path("icons/pin.svg").xsmall())
|
||||
.tooltip(|window, cx| {
|
||||
gpui_component::tooltip::Tooltip::new(t(
|
||||
L10nKey::SidebarUnpinGroup,
|
||||
))
|
||||
.build(window, cx)
|
||||
})
|
||||
.on_mouse_down(MouseButton::Left, |_, _, cx| {
|
||||
cx.stop_propagation()
|
||||
})
|
||||
.on_click(cx.listener(move |this, _, _window, cx| {
|
||||
cx.stop_propagation();
|
||||
this.delete_group(id, cx);
|
||||
})),
|
||||
)
|
||||
},
|
||||
)
|
||||
// Every kept group carries the mark; it is what sets them
|
||||
// apart from the derived groups below. On a folder group it
|
||||
// is also the way to stop keeping it — a click unpins, and
|
||||
// the folder's tabs fall back to the groups their cwds
|
||||
// resolve to. A label group's mark is only a mark: without a
|
||||
// folder there is nothing to fall back on, so letting go of
|
||||
// it is Delete Group, in its menu, not a stray click.
|
||||
.when_some(pinned_id, |header, id| {
|
||||
let mark = div()
|
||||
.flex_shrink_0()
|
||||
.text_size(px(PIN_MARK_SIZE))
|
||||
.line_height(px(PIN_MARK_SIZE))
|
||||
.child(PIN_MARK);
|
||||
header.child(match pinned_folder.is_some() {
|
||||
false => mark.into_any_element(),
|
||||
true => mark
|
||||
.id(("sidebar-group-unpin", group_ix))
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(cx.theme().foreground))
|
||||
.tooltip(|window, cx| {
|
||||
gpui_component::tooltip::Tooltip::new(t(
|
||||
L10nKey::SidebarUnpinGroup,
|
||||
))
|
||||
.build(window, cx)
|
||||
})
|
||||
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
||||
.on_click(cx.listener(move |this, _, _window, cx| {
|
||||
cx.stop_propagation();
|
||||
this.delete_group(id, cx);
|
||||
}))
|
||||
.into_any_element(),
|
||||
})
|
||||
})
|
||||
.child(match renaming_group {
|
||||
Some(input) => div()
|
||||
.id(("sidebar-group-rename", group_ix))
|
||||
@@ -1823,8 +1836,14 @@ impl Tty7App {
|
||||
.child(handle)
|
||||
}
|
||||
|
||||
/// The line between the kept groups and the derived ones, recording where
|
||||
/// it was drawn so a drag next frame can tell which side it is on.
|
||||
/// The boundary between the kept groups and the derived ones, recording
|
||||
/// where it lies so a drag next frame can tell which side it is on.
|
||||
///
|
||||
/// Not drawn at rest — the mark on each kept header already says which
|
||||
/// side a group is on, and a hairline across the list was one more rule
|
||||
/// for the eye to cross. It keeps its place in the layout all the same, so
|
||||
/// nothing jumps when a drag starts, and shows as a line only while it is
|
||||
/// the target: when letting go would pin a header or hand a tab back.
|
||||
///
|
||||
/// With nothing pinned yet it only appears while an auto header is being
|
||||
/// carried, and then as a drop zone rather than a hairline: a one-pixel
|
||||
@@ -1833,9 +1852,10 @@ impl Tty7App {
|
||||
/// back to auto grouping.
|
||||
fn sidebar_divider(&self, lit: bool, zone: bool, cx: &Context<Self>) -> AnyElement {
|
||||
let bounds = self.sidebar_divider.clone();
|
||||
let ink = match lit {
|
||||
true => cx.theme().drag_border,
|
||||
false => cx.theme().sidebar_border,
|
||||
let ink = match (lit, zone) {
|
||||
(true, _) => cx.theme().drag_border,
|
||||
(false, true) => cx.theme().sidebar_border,
|
||||
(false, false) => gpui::transparent_black(),
|
||||
};
|
||||
let body = match zone {
|
||||
true => h_flex()
|
||||
@@ -1862,7 +1882,9 @@ impl Tty7App {
|
||||
.relative()
|
||||
.w_full()
|
||||
.px_2()
|
||||
.pt(px(10.))
|
||||
// Less than when it was a drawn rule: the next header's own top
|
||||
// margin already opens the gap between the two kinds of group.
|
||||
.pt(px(4.))
|
||||
.pb(px(2.))
|
||||
.child(
|
||||
canvas(move |b, _window, _cx| bounds.set(Some(b)), |_, _, _, _| {})
|
||||
@@ -1895,7 +1917,7 @@ impl Tty7App {
|
||||
fade.a = 0.;
|
||||
let muted = cx.theme().muted_foreground;
|
||||
let ink = cx.theme().foreground;
|
||||
let button = |id: &'static str, path: &'static str, tip: L10nKey| {
|
||||
let button = |id: &'static str, glyph: AnyElement, tip: L10nKey| {
|
||||
div()
|
||||
.id((id, group_ix))
|
||||
.flex_shrink_0()
|
||||
@@ -1904,7 +1926,7 @@ impl Tty7App {
|
||||
.cursor_pointer()
|
||||
.text_color(muted)
|
||||
.hover(move |s| s.text_color(ink))
|
||||
.child(Icon::empty().path(path).xsmall())
|
||||
.child(glyph)
|
||||
.tooltip(move |window, cx| {
|
||||
gpui_component::tooltip::Tooltip::new(t(tip)).build(window, cx)
|
||||
})
|
||||
@@ -1914,7 +1936,19 @@ impl Tty7App {
|
||||
buttons = buttons.child(
|
||||
button(
|
||||
"sidebar-group-pin",
|
||||
"icons/pin.svg",
|
||||
// The mark the group will carry once kept, the size of
|
||||
// the icon beside it so the two buttons line up.
|
||||
div()
|
||||
.size(px(12.))
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_size(px(PIN_MARK_SIZE))
|
||||
// Its own line box: the header's is several times the
|
||||
// mark's size and would drop it below the "+" beside it.
|
||||
.line_height(px(PIN_MARK_SIZE))
|
||||
.child(PIN_MARK)
|
||||
.into_any_element(),
|
||||
L10nKey::SidebarPinGroup,
|
||||
)
|
||||
.on_mouse_down(
|
||||
@@ -1930,7 +1964,10 @@ impl Tty7App {
|
||||
buttons = buttons.child(
|
||||
button(
|
||||
"sidebar-group-add",
|
||||
"icons/plus.svg",
|
||||
Icon::empty()
|
||||
.path("icons/plus.svg")
|
||||
.xsmall()
|
||||
.into_any_element(),
|
||||
L10nKey::SidebarGroupNewTab,
|
||||
)
|
||||
.on_mouse_down(
|
||||
|
||||
Reference in New Issue
Block a user