update repo list
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M3.75 5.75C3.75 4.64543 4.64543 3.75 5.75 3.75H8.25C9.35457 3.75 10.25 4.64543 10.25 5.75V8.25C10.25 9.35457 9.35457 10.25 8.25 10.25H5.75C4.64543 10.25 3.75 9.35457 3.75 8.25V5.75Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M3.75 15.75C3.75 14.6454 4.64543 13.75 5.75 13.75H8.25C9.35457 13.75 10.25 14.6454 10.25 15.75V18.25C10.25 19.3546 9.35457 20.25 8.25 20.25H5.75C4.64543 20.25 3.75 19.3546 3.75 18.25V15.75Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.75 17C13.75 15.2051 15.2051 13.75 17 13.75C18.7949 13.75 20.25 15.2051 20.25 17C20.25 18.7949 18.7949 20.25 17 20.25C15.2051 20.25 13.75 18.7949 13.75 17Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.75 5.75C13.75 4.64543 14.6454 3.75 15.75 3.75H18.25C19.3546 3.75 20.25 4.64543 20.25 5.75V8.25C20.25 9.35457 19.3546 10.25 18.25 10.25H15.75C14.6454 10.25 13.75 9.35457 13.75 8.25V5.75Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M12 7.75V12L15.5 15.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M2.75 4.75V8.75H6.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M3.25 15.0833C4.52169 18.676 7.95303 21.25 11.9864 21.25C17.1026 21.25 21.25 17.1086 21.25 12C21.25 6.89137 17.1026 2.75 11.9864 2.75C8.14808 2.75 4.85497 5.08106 3.44947 8.40278" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 600 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M15.75 6.75H21.25V12.25M20.7361 7.275L14.4142 13.5878C13.633 14.3679 12.3675 14.3675 11.5868 13.5868L10.4142 12.4142C9.63316 11.6332 8.36684 11.6332 7.58579 12.4142L2.75 17.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 356 B |
@@ -93,6 +93,9 @@ pub enum CustomIconName {
|
|||||||
Tag,
|
Tag,
|
||||||
Markdown,
|
Markdown,
|
||||||
Share,
|
Share,
|
||||||
|
Trending,
|
||||||
|
Recent,
|
||||||
|
Grid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconNamed for CustomIconName {
|
impl IconNamed for CustomIconName {
|
||||||
@@ -118,6 +121,9 @@ impl IconNamed for CustomIconName {
|
|||||||
CustomIconName::Tag => "icons/tag.svg",
|
CustomIconName::Tag => "icons/tag.svg",
|
||||||
CustomIconName::Markdown => "icons/markdown.svg",
|
CustomIconName::Markdown => "icons/markdown.svg",
|
||||||
CustomIconName::Share => "icons/share.svg",
|
CustomIconName::Share => "icons/share.svg",
|
||||||
|
CustomIconName::Trending => "icons/trending.svg",
|
||||||
|
CustomIconName::Recent => "icons/recent.svg",
|
||||||
|
CustomIconName::Grid => "icons/grid.svg",
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -807,7 +807,7 @@ fn tree_diff(
|
|||||||
/// Parse a `git format-patch` output (a single patch or a patch series)
|
/// Parse a `git format-patch` output (a single patch or a patch series)
|
||||||
/// into the same [`CommitDiff`] structure used for commit diffs.
|
/// into the same [`CommitDiff`] structure used for commit diffs.
|
||||||
///
|
///
|
||||||
/// The mbox envelope (From/Subject/… headers, commit body and diffstat)
|
/// The mbox envelope (From/Subject/... headers, commit body and diffstat)
|
||||||
/// is skipped; every `diff --git` section becomes one [`FileDiff`]. Paths
|
/// is skipped; every `diff --git` section becomes one [`FileDiff`]. Paths
|
||||||
/// are taken from the section headers, with git's C-style quoting undone.
|
/// are taken from the section headers, with git's C-style quoting undone.
|
||||||
/// Sections without hunks (pure renames, mode changes, binary files) are
|
/// Sections without hunks (pure renames, mode changes, binary files) are
|
||||||
@@ -895,7 +895,7 @@ fn name_from_address(from: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Strip the `[PATCH]`, `[PATCH 1/2]`, `[RFC PATCH]` … prefix from a patch
|
/// Strip the `[PATCH]`, `[PATCH 1/2]`, `[RFC PATCH]` ... prefix from a patch
|
||||||
/// `Subject:` header.
|
/// `Subject:` header.
|
||||||
fn strip_patch_prefix(subject: &str) -> String {
|
fn strip_patch_prefix(subject: &str) -> String {
|
||||||
let trimmed = subject.trim();
|
let trimmed = subject.trim();
|
||||||
@@ -1060,7 +1060,7 @@ fn parse_hunk(lines: &[&str], start: usize) -> Result<(DiffHunk, usize)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of a hunk body line, from its first character; lines that don't
|
/// The kind of a hunk body line, from its first character; lines that don't
|
||||||
/// belong to the hunk (headers, `\ No newline…`, the next section) yield
|
/// belong to the hunk (headers, `\ No newline...`, the next section) yield
|
||||||
/// `None`.
|
/// `None`.
|
||||||
fn line_prefix_kind(line: &str) -> Option<DiffLineKind> {
|
fn line_prefix_kind(line: &str) -> Option<DiffLineKind> {
|
||||||
match line.as_bytes().first()? {
|
match line.as_bytes().first()? {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ impl RepoDetailView {
|
|||||||
div()
|
div()
|
||||||
.text_sm()
|
.text_sm()
|
||||||
.text_color(cx.theme().muted_foreground)
|
.text_color(cx.theme().muted_foreground)
|
||||||
.child("Cloning repository…"),
|
.child("Cloning repository..."),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
} else if let Some(error) = error {
|
} else if let Some(error) = error {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl IssueDetailView {
|
|||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let comment_input =
|
let comment_input =
|
||||||
cx.new(|cx| TextareaState::new(window, cx).placeholder("Leave a comment…"));
|
cx.new(|cx| TextareaState::new(window, cx).placeholder("Leave a comment..."));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ impl IssuesView {
|
|||||||
/// through [`RepoStore::open_issue`] when confirmed.
|
/// through [`RepoStore::open_issue`] when confirmed.
|
||||||
pub(super) fn open_new_issue_dialog(store: Entity<RepoStore>, window: &mut Window, cx: &mut App) {
|
pub(super) fn open_new_issue_dialog(store: Entity<RepoStore>, window: &mut Window, cx: &mut App) {
|
||||||
let subject = cx.new(|cx| InputState::new(window, cx).placeholder("Issue title"));
|
let subject = cx.new(|cx| InputState::new(window, cx).placeholder("Issue title"));
|
||||||
let content = cx.new(|cx| TextareaState::new(window, cx).placeholder("Describe the issue…"));
|
let content = cx.new(|cx| TextareaState::new(window, cx).placeholder("Describe the issue..."));
|
||||||
|
|
||||||
window.open_dialog(cx, move |dialog, _window, _cx| {
|
window.open_dialog(cx, move |dialog, _window, _cx| {
|
||||||
let subject = subject.clone();
|
let subject = subject.clone();
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ impl PullRequestDetailView {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let tree_state = cx.new(|cx| TreeState::new(cx));
|
let tree_state = cx.new(|cx| TreeState::new(cx));
|
||||||
let comment_input =
|
let comment_input =
|
||||||
cx.new(|cx| TextareaState::new(window, cx).placeholder("Leave a comment…"));
|
cx.new(|cx| TextareaState::new(window, cx).placeholder("Leave a comment..."));
|
||||||
|
|
||||||
// Same display name as the repo detail panel's title.
|
// Same display name as the repo detail panel's title.
|
||||||
let repo_name = store
|
let repo_name = store
|
||||||
|
|||||||
@@ -442,9 +442,9 @@ pub(super) fn open_new_pull_request_dialog(
|
|||||||
) {
|
) {
|
||||||
let subject = cx.new(|cx| InputState::new(window, cx).placeholder("Pull request title"));
|
let subject = cx.new(|cx| InputState::new(window, cx).placeholder("Pull request title"));
|
||||||
let description =
|
let description =
|
||||||
cx.new(|cx| TextareaState::new(window, cx).placeholder("Describe the change…"));
|
cx.new(|cx| TextareaState::new(window, cx).placeholder("Describe the change..."));
|
||||||
let patch =
|
let patch = cx
|
||||||
cx.new(|cx| TextareaState::new(window, cx).placeholder("Paste `git format-patch` output…"));
|
.new(|cx| TextareaState::new(window, cx).placeholder("Paste `git format-patch` output..."));
|
||||||
|
|
||||||
window.open_dialog(cx, move |dialog, _window, _cx| {
|
window.open_dialog(cx, move |dialog, _window, _cx| {
|
||||||
let subject = subject.clone();
|
let subject = subject.clone();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use assets::CustomIconName;
|
||||||
use dock::{BasePanel, DockArea, DockPlacement, Panel, PanelEvent, panel_handle};
|
use dock::{BasePanel, DockArea, DockPlacement, Panel, PanelEvent, panel_handle};
|
||||||
use gpui::prelude::*;
|
use gpui::prelude::*;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -8,9 +9,11 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
use gpui_base::Button as BaseButton;
|
use gpui_base::Button as BaseButton;
|
||||||
use gpui_component::avatar::Avatar;
|
use gpui_component::avatar::Avatar;
|
||||||
|
use gpui_component::input::{Input, InputEvent, InputState};
|
||||||
use gpui_component::scroll::Scrollbar;
|
use gpui_component::scroll::Scrollbar;
|
||||||
use gpui_component::{
|
use gpui_component::{
|
||||||
ActiveTheme, Sizable, StyledExt, VirtualListScrollHandle, h_flex, v_flex, v_virtual_list,
|
ActiveTheme, Icon, IconName, Sizable, StyledExt, VirtualListScrollHandle, h_flex, v_flex,
|
||||||
|
v_virtual_list,
|
||||||
};
|
};
|
||||||
use signed_core::Announcement;
|
use signed_core::Announcement;
|
||||||
use signed_state::{ProfileStore, RepoListStore, Timestamp};
|
use signed_state::{ProfileStore, RepoListStore, Timestamp};
|
||||||
@@ -38,10 +41,24 @@ enum RepoFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RepoFilter {
|
impl RepoFilter {
|
||||||
fn visible(self, store: &RepoListStore) -> Vec<usize> {
|
/// Indices into the store's `announcements` included by this filter, in
|
||||||
|
/// display order, narrowed to repositories whose name (or id) contains
|
||||||
|
/// `query`; an empty query matches everything.
|
||||||
|
fn visible(self, store: &RepoListStore, query: &str) -> Vec<usize> {
|
||||||
let announcements = &store.announcements;
|
let announcements = &store.announcements;
|
||||||
let mut indices: Vec<usize> = (0..announcements.len()).collect();
|
let mut indices: Vec<usize> = (0..announcements.len()).collect();
|
||||||
|
|
||||||
|
// Narrow by the search query first, so "Recent" limits the matches
|
||||||
|
// and "Popular" ranks them.
|
||||||
|
let query = query.trim().to_lowercase();
|
||||||
|
if !query.is_empty() {
|
||||||
|
indices.retain(|&ix| {
|
||||||
|
let announcement = &announcements[ix];
|
||||||
|
let name = announcement.name.as_deref().unwrap_or(&announcement.id);
|
||||||
|
name.to_lowercase().contains(&query)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::All => {}
|
Self::All => {}
|
||||||
Self::Recent => indices.truncate(RECENT_COUNT),
|
Self::Recent => indices.truncate(RECENT_COUNT),
|
||||||
@@ -57,6 +74,14 @@ impl RepoFilter {
|
|||||||
|
|
||||||
indices
|
indices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon_name(self) -> CustomIconName {
|
||||||
|
match self {
|
||||||
|
Self::All => CustomIconName::Grid,
|
||||||
|
Self::Recent => CustomIconName::Recent,
|
||||||
|
Self::Popular => CustomIconName::Trending,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Browse all announced repositories.
|
/// Browse all announced repositories.
|
||||||
@@ -72,22 +97,35 @@ pub struct RepoListView {
|
|||||||
/// Number of rows [`Self::item_sizes`] was built for (the filtered repo count).
|
/// Number of rows [`Self::item_sizes`] was built for (the filtered repo count).
|
||||||
repo_len: usize,
|
repo_len: usize,
|
||||||
/// Indices into the store's `announcements` matching [`Self::filter`],
|
/// Indices into the store's `announcements` matching [`Self::filter`],
|
||||||
/// in display order; rebuilt when the store changes or the filter is switched.
|
/// in display order; rebuilt when the store changes, the filter is
|
||||||
/// The virtual list renders this slice.
|
/// switched, or the search text changes. The virtual list renders this
|
||||||
|
/// slice.
|
||||||
visible: Vec<usize>,
|
visible: Vec<usize>,
|
||||||
|
/// Search box filtering repositories by name.
|
||||||
|
search: Entity<InputState>,
|
||||||
|
/// Rebuilds the visible slice as the search text changes.
|
||||||
|
_search_subscription: Subscription,
|
||||||
_subscription: Subscription,
|
_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepoListView {
|
impl RepoListView {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
dock_area: WeakEntity<DockArea>,
|
dock_area: WeakEntity<DockArea>,
|
||||||
_window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let store = RepoListStore::global(cx);
|
let store = RepoListStore::global(cx);
|
||||||
|
|
||||||
// Keep the visible slice and row sizes in sync with the store, so
|
// Live search over repository names
|
||||||
// newly announced repositories appear without waiting for a click.
|
let search = cx.new(|cx| InputState::new(window, cx).placeholder("Search..."));
|
||||||
|
let search_subscription = cx.subscribe(&search, |this, _search, event, cx| {
|
||||||
|
if matches!(event, InputEvent::Change) {
|
||||||
|
this.rebuild_rows(cx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep the visible slice and row sizes in sync with the store,
|
||||||
|
// so newly announced repositories appear without waiting for a click.
|
||||||
let subscription = cx.observe(&store, |this, _store, cx| {
|
let subscription = cx.observe(&store, |this, _store, cx| {
|
||||||
this.rebuild_rows(cx);
|
this.rebuild_rows(cx);
|
||||||
});
|
});
|
||||||
@@ -101,6 +139,8 @@ impl RepoListView {
|
|||||||
item_sizes: Rc::new(Vec::new()),
|
item_sizes: Rc::new(Vec::new()),
|
||||||
repo_len: 0,
|
repo_len: 0,
|
||||||
visible: Vec::new(),
|
visible: Vec::new(),
|
||||||
|
search,
|
||||||
|
_search_subscription: search_subscription,
|
||||||
_subscription: subscription,
|
_subscription: subscription,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,13 +153,15 @@ impl RepoListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Rebuild [`Self::visible`] and [`Self::item_sizes`] from the current
|
/// Rebuild [`Self::visible`] and [`Self::item_sizes`] from the current
|
||||||
/// store contents and [`Self::filter`]. Called when the view is created,
|
/// store contents, [`Self::filter`] and the search query. Called when
|
||||||
/// when the store changes, and when the filter is switched,
|
/// the view is created, when the store changes, when the filter is
|
||||||
/// so the list is ready before the next render.
|
/// switched, and on every search keystroke, so the list is ready before
|
||||||
|
/// the next render.
|
||||||
fn rebuild_rows(&mut self, cx: &mut Context<Self>) {
|
fn rebuild_rows(&mut self, cx: &mut Context<Self>) {
|
||||||
let filter = self.filter;
|
let filter = self.filter;
|
||||||
|
let query = self.search.read(cx).value();
|
||||||
let store = self.store.read(cx);
|
let store = self.store.read(cx);
|
||||||
self.visible = filter.visible(store);
|
self.visible = filter.visible(store, &query);
|
||||||
|
|
||||||
// Each virtual list row holds `COLUMNS` repo cards.
|
// Each virtual list row holds `COLUMNS` repo cards.
|
||||||
let rows = self.visible.len().div_ceil(COLUMNS);
|
let rows = self.visible.len().div_ceil(COLUMNS);
|
||||||
@@ -252,18 +294,44 @@ impl RepoListView {
|
|||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Header of the explore list: title, the count of visible repositories and the sort filter buttons.
|
fn render_header(&self, count: usize, cx: &mut Context<Self>) -> AnyElement {
|
||||||
fn render_header(&self, cx: &mut Context<Self>) -> AnyElement {
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.px_4()
|
.px_4()
|
||||||
.py_2()
|
.py_2()
|
||||||
.w_full()
|
.w_full()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
.items_center()
|
.child(
|
||||||
.child(self.filter_button(RepoFilter::All, "All", cx))
|
h_flex()
|
||||||
.child(self.filter_button(RepoFilter::Popular, "Popular", cx))
|
.gap_1()
|
||||||
.child(self.filter_button(RepoFilter::Recent, "Recent", cx))
|
.text_xs()
|
||||||
|
.child(div().font_semibold().child("Repositories"))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w_10()
|
||||||
|
.min_w_0()
|
||||||
|
.truncate()
|
||||||
|
.text_ellipsis()
|
||||||
|
.text_color(cx.theme().muted_foreground)
|
||||||
|
.child(SharedString::from(format!("({count})"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Input::new(&self.search)
|
||||||
|
.cleanable(true)
|
||||||
|
.w(px(180.))
|
||||||
|
.text_sm()
|
||||||
|
.border_color(cx.theme().muted)
|
||||||
|
.bg(cx.theme().muted)
|
||||||
|
.prefix(Icon::new(IconName::Search).small()),
|
||||||
|
)
|
||||||
.child(div().flex_1())
|
.child(div().flex_1())
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1()
|
||||||
|
.child(self.filter_button(RepoFilter::All, "All", cx))
|
||||||
|
.child(self.filter_button(RepoFilter::Popular, "Popular", cx))
|
||||||
|
.child(self.filter_button(RepoFilter::Recent, "Recent", cx)),
|
||||||
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,22 +343,22 @@ impl RepoListView {
|
|||||||
label: &'static str,
|
label: &'static str,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
|
let active = self.filter == filter;
|
||||||
|
|
||||||
BaseButton::new(label)
|
BaseButton::new(label)
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.h_7()
|
.h_7()
|
||||||
.px_2()
|
.px_2()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
.child(Icon::new(filter.icon_name()))
|
||||||
.child(div().text_sm().child(label))
|
.child(div().text_sm().child(label))
|
||||||
.text_color(cx.theme().button_foreground)
|
.text_color(cx.theme().button_foreground)
|
||||||
.rounded(cx.theme().radius)
|
.rounded(cx.theme().radius)
|
||||||
.hover(|this| this.bg(cx.theme().button_hover))
|
.hover(|this| this.bg(cx.theme().button_hover))
|
||||||
.active(|this| this.bg(cx.theme().primary_active))
|
.active(|this| this.bg(cx.theme().button_active))
|
||||||
.selected(self.filter == filter)
|
.selected(active)
|
||||||
.when(self.filter == filter, |this| {
|
.when(active, |this| this.bg(cx.theme().button_active))
|
||||||
this.bg(cx.theme().primary)
|
|
||||||
.text_color(cx.theme().primary_foreground)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(move |this, _event, _window, cx| {
|
.on_click(cx.listener(move |this, _event, _window, cx| {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.rebuild_rows(cx);
|
this.rebuild_rows(cx);
|
||||||
@@ -331,8 +399,7 @@ impl Render for RepoListView {
|
|||||||
.relative()
|
.relative()
|
||||||
.image_cache(image_cache("repos", MAX_IMAGES))
|
.image_cache(image_cache("repos", MAX_IMAGES))
|
||||||
.size_full()
|
.size_full()
|
||||||
.pb_3()
|
.child(self.render_header(count, cx))
|
||||||
.child(self.render_header(cx))
|
|
||||||
.when(!has_repos, |this| {
|
.when(!has_repos, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
v_flex().size_full().items_center().justify_center().child(
|
v_flex().size_full().items_center().justify_center().child(
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ pub fn open(dock_area: WeakEntity<DockArea>, window: &mut Window, cx: &mut App)
|
|||||||
div()
|
div()
|
||||||
.text_xs()
|
.text_xs()
|
||||||
.text_color(cx.theme().muted_foreground)
|
.text_color(cx.theme().muted_foreground)
|
||||||
.child("Loading your grasp servers…"),
|
.child("Loading your grasp servers..."),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user