Bring UI crate up to date
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use gpui2::elements::div;
|
||||
use gpui2::elements::div::ScrollState;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::{icon_button, theme};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct ChatPanel<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
pub fn chat_panel<V: 'static>(scroll_state: ScrollState) -> ChatPanel<V> {
|
||||
ChatPanel {
|
||||
view_type: PhantomData,
|
||||
scroll_state,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ChatPanel<V> {
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
div()
|
||||
.h_full()
|
||||
.flex()
|
||||
// Header
|
||||
.child(
|
||||
div()
|
||||
.px_2()
|
||||
.flex()
|
||||
.gap_2()
|
||||
// Nav Buttons
|
||||
.child("#gpui2"),
|
||||
)
|
||||
// Chat Body
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.overflow_y_scroll(self.scroll_state.clone())
|
||||
.child("body"),
|
||||
)
|
||||
// Composer
|
||||
.child(
|
||||
div()
|
||||
.px_2()
|
||||
.flex()
|
||||
.gap_2()
|
||||
// Nav Buttons
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_px()
|
||||
.child(icon_button("icons/plus.svg"))
|
||||
.child(icon_button("icons/split.svg")),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
use crate::theme::theme;
|
||||
use crate::tokens::token;
|
||||
use crate::{icon, label, prelude::*, IconAsset, LabelColor, ListItem, ListSectionHeader};
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{elements::div, IntoElement};
|
||||
use gpui2::{Element, ParentElement, ViewContext};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct List {
|
||||
header: Option<ListSectionHeader>,
|
||||
items: Vec<ListItem>,
|
||||
empty_message: &'static str,
|
||||
toggle: Option<ToggleState>,
|
||||
// footer: Option<ListSectionFooter>,
|
||||
}
|
||||
|
||||
pub fn list(items: Vec<ListItem>) -> List {
|
||||
List {
|
||||
header: None,
|
||||
items,
|
||||
empty_message: "No items",
|
||||
toggle: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl List {
|
||||
pub fn header(mut self, header: ListSectionHeader) -> Self {
|
||||
self.header = Some(header);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn empty_message(mut self, empty_message: &'static str) -> Self {
|
||||
self.empty_message = empty_message;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_toggle(mut self, toggle: ToggleState) -> Self {
|
||||
self.toggle = Some(toggle);
|
||||
self
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
let token = token();
|
||||
|
||||
let disclosure_control = match self.toggle {
|
||||
Some(ToggleState::NotToggled) => Some(icon(IconAsset::ChevronRight)),
|
||||
Some(ToggleState::Toggled) => Some(icon(IconAsset::ChevronDown)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
div()
|
||||
.py_1()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.children(self.header.map(|h| h))
|
||||
.children(
|
||||
self.items
|
||||
.is_empty()
|
||||
.then(|| label(self.empty_message).color(LabelColor::Muted)),
|
||||
)
|
||||
.children(self.items.iter().cloned())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::prelude::OrderMethod;
|
||||
use crate::theme::theme;
|
||||
use crate::{label, palette_item, LabelColor, PaletteItem};
|
||||
use gpui2::elements::div::ScrollState;
|
||||
use gpui2::style::{StyleHelpers, Styleable};
|
||||
use gpui2::{elements::div, IntoElement};
|
||||
use gpui2::{Element, ParentElement, ViewContext};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct Palette<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
scroll_state: ScrollState,
|
||||
input_placeholder: &'static str,
|
||||
empty_string: &'static str,
|
||||
items: Vec<PaletteItem>,
|
||||
default_order: OrderMethod,
|
||||
}
|
||||
|
||||
pub fn palette<V: 'static>(scroll_state: ScrollState) -> Palette<V> {
|
||||
Palette {
|
||||
view_type: PhantomData,
|
||||
scroll_state,
|
||||
input_placeholder: "Find something...",
|
||||
empty_string: "No items found.",
|
||||
items: vec![],
|
||||
default_order: OrderMethod::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Palette<V> {
|
||||
pub fn items(mut self, mut items: Vec<PaletteItem>) -> Self {
|
||||
items.sort_by_key(|item| item.label);
|
||||
self.items = items;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn placeholder(mut self, input_placeholder: &'static str) -> Self {
|
||||
self.input_placeholder = input_placeholder;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn empty_string(mut self, empty_string: &'static str) -> Self {
|
||||
self.empty_string = empty_string;
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: Hook up sort order
|
||||
pub fn default_order(mut self, default_order: OrderMethod) -> Self {
|
||||
self.default_order = default_order;
|
||||
self
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
div()
|
||||
.w_96()
|
||||
.rounded_lg()
|
||||
.fill(theme.lowest.base.default.background)
|
||||
.border()
|
||||
.border_color(theme.lowest.base.default.border)
|
||||
.flex()
|
||||
.flex_col()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_px()
|
||||
.child(
|
||||
div().py_0p5().px_1().flex().flex_col().child(
|
||||
div().px_2().py_0p5().child(
|
||||
label(self.input_placeholder).color(LabelColor::Placeholder),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(div().h_px().w_full().fill(theme.lowest.base.default.border))
|
||||
.child(
|
||||
div()
|
||||
.py_0p5()
|
||||
.px_1()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.grow()
|
||||
.max_h_96()
|
||||
.overflow_y_scroll(self.scroll_state.clone())
|
||||
.children(
|
||||
vec![if self.items.is_empty() {
|
||||
Some(
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_between()
|
||||
.px_2()
|
||||
.py_1()
|
||||
.child(
|
||||
label(self.empty_string).color(LabelColor::Muted),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}]
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
.children(self.items.iter().map(|item| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_between()
|
||||
.px_2()
|
||||
.py_0p5()
|
||||
.rounded_lg()
|
||||
.hover()
|
||||
.fill(theme.lowest.base.hovered.background)
|
||||
.active()
|
||||
.fill(theme.lowest.base.pressed.background)
|
||||
.child(palette_item(item.label, item.keybinding))
|
||||
})),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use gpui2::elements::div;
|
||||
use gpui2::elements::div::ScrollState;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{details, input, label, list_item, theme, IconAsset, LabelColor};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct ProjectPanel<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
pub fn project_panel<V: 'static>(scroll_state: ScrollState) -> ProjectPanel<V> {
|
||||
ProjectPanel {
|
||||
view_type: PhantomData,
|
||||
scroll_state,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ProjectPanel<V> {
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
div()
|
||||
.w_56()
|
||||
.h_full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.fill(theme.middle.base.default.background)
|
||||
.child(
|
||||
div()
|
||||
.w_56()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.overflow_y_scroll(self.scroll_state.clone())
|
||||
.child(details("This is a long string that should wrap when it keeps going for a long time.").meta_text("6 h ago)"))
|
||||
.child(
|
||||
div().flex().flex_col().children(
|
||||
std::iter::repeat_with(|| {
|
||||
vec![
|
||||
list_item(label("sqlez").color(LabelColor::Modified))
|
||||
.left_icon(IconAsset::FolderOpen.into())
|
||||
.indent_level(0)
|
||||
.set_toggle(ToggleState::NotToggled),
|
||||
list_item(label("storybook").color(LabelColor::Modified))
|
||||
.left_icon(IconAsset::FolderOpen.into())
|
||||
.indent_level(0)
|
||||
.set_toggle(ToggleState::Toggled),
|
||||
list_item(label("docs").color(LabelColor::Default))
|
||||
.left_icon(IconAsset::Folder.into())
|
||||
.indent_level(1)
|
||||
.set_toggle(ToggleState::Toggled),
|
||||
list_item(label("src").color(LabelColor::Modified))
|
||||
.left_icon(IconAsset::FolderOpen.into())
|
||||
.indent_level(2)
|
||||
.set_toggle(ToggleState::Toggled),
|
||||
list_item(label("ui").color(LabelColor::Modified))
|
||||
.left_icon(IconAsset::FolderOpen.into())
|
||||
.indent_level(3)
|
||||
.set_toggle(ToggleState::Toggled),
|
||||
list_item(label("component").color(LabelColor::Created))
|
||||
.left_icon(IconAsset::FolderOpen.into())
|
||||
.indent_level(4)
|
||||
.set_toggle(ToggleState::Toggled),
|
||||
list_item(label("facepile.rs").color(LabelColor::Default))
|
||||
.left_icon(IconAsset::File.into())
|
||||
.indent_level(5),
|
||||
list_item(label("follow_group.rs").color(LabelColor::Default))
|
||||
.left_icon(IconAsset::File.into())
|
||||
.indent_level(5),
|
||||
list_item(label("list_item.rs").color(LabelColor::Created))
|
||||
.left_icon(IconAsset::File.into())
|
||||
.indent_level(5),
|
||||
list_item(label("tab.rs").color(LabelColor::Default))
|
||||
.left_icon(IconAsset::File.into())
|
||||
.indent_level(5),
|
||||
]
|
||||
})
|
||||
.take(10)
|
||||
.flatten(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
input("Find something...")
|
||||
.value("buffe".to_string())
|
||||
.state(InteractionState::Focused),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::theme::{theme, Theme};
|
||||
use crate::{icon_button, text_button, tool_divider};
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub enum Tool {
|
||||
#[default]
|
||||
ProjectPanel,
|
||||
CollaborationPanel,
|
||||
Terminal,
|
||||
Assistant,
|
||||
Feedback,
|
||||
Diagnostics,
|
||||
}
|
||||
|
||||
struct ToolGroup {
|
||||
active_index: Option<usize>,
|
||||
tools: Vec<Tool>,
|
||||
}
|
||||
|
||||
impl Default for ToolGroup {
|
||||
fn default() -> Self {
|
||||
ToolGroup {
|
||||
active_index: None,
|
||||
tools: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct StatusBar<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
left_tools: Option<ToolGroup>,
|
||||
right_tools: Option<ToolGroup>,
|
||||
bottom_tools: Option<ToolGroup>,
|
||||
}
|
||||
|
||||
pub fn status_bar<V: 'static>() -> StatusBar<V> {
|
||||
StatusBar {
|
||||
view_type: PhantomData,
|
||||
left_tools: None,
|
||||
right_tools: None,
|
||||
bottom_tools: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> StatusBar<V> {
|
||||
pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
|
||||
self.left_tools = {
|
||||
let mut tools = vec![tool];
|
||||
tools.extend(self.left_tools.take().unwrap_or_default().tools);
|
||||
Some(ToolGroup {
|
||||
active_index,
|
||||
tools,
|
||||
})
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
|
||||
self.right_tools = {
|
||||
let mut tools = vec![tool];
|
||||
tools.extend(self.left_tools.take().unwrap_or_default().tools);
|
||||
Some(ToolGroup {
|
||||
active_index,
|
||||
tools,
|
||||
})
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
|
||||
self.bottom_tools = {
|
||||
let mut tools = vec![tool];
|
||||
tools.extend(self.left_tools.take().unwrap_or_default().tools);
|
||||
Some(ToolGroup {
|
||||
active_index,
|
||||
tools,
|
||||
})
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
div()
|
||||
.py_0p5()
|
||||
.px_1()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.w_full()
|
||||
.fill(theme.lowest.base.default.background)
|
||||
.child(self.left_tools(theme))
|
||||
.child(self.right_tools(theme))
|
||||
}
|
||||
|
||||
fn left_tools(&self, theme: &Theme) -> impl Element<V> {
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(icon_button("icons/project.svg"))
|
||||
.child(icon_button("icons/hash.svg"))
|
||||
.child(tool_divider())
|
||||
.child(icon_button("icons/error.svg"))
|
||||
}
|
||||
fn right_tools(&self, theme: &Theme) -> impl Element<V> {
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(text_button("116:25"))
|
||||
.child(text_button("Rust")),
|
||||
)
|
||||
.child(tool_divider())
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(icon_button("icons/copilot.svg"))
|
||||
.child(icon_button("icons/feedback.svg")),
|
||||
)
|
||||
.child(tool_divider())
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(icon_button("icons/terminal.svg"))
|
||||
.child(icon_button("icons/conversations.svg"))
|
||||
.child(icon_button("icons/ai.svg")),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use gpui2::elements::div;
|
||||
use gpui2::elements::div::ScrollState;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::InteractionState;
|
||||
use crate::{icon_button, tab, theme};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct TabBar<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
pub fn tab_bar<V: 'static>(scroll_state: ScrollState) -> TabBar<V> {
|
||||
TabBar {
|
||||
view_type: PhantomData,
|
||||
scroll_state,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> TabBar<V> {
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
let can_navigate_back = true;
|
||||
let can_navigate_forward = false;
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
// Left Side
|
||||
.child(
|
||||
div()
|
||||
.px_1()
|
||||
.flex()
|
||||
.flex_none()
|
||||
.gap_2()
|
||||
// Nav Buttons
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_px()
|
||||
.child(
|
||||
icon_button("icons/arrow_left.svg")
|
||||
.state(InteractionState::Enabled.if_enabled(can_navigate_back)),
|
||||
)
|
||||
.child(
|
||||
icon_button("icons/arrow_right.svg").state(
|
||||
InteractionState::Enabled.if_enabled(can_navigate_forward),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
div().w_0().flex_1().h_full().child(
|
||||
div()
|
||||
.flex()
|
||||
.gap_1()
|
||||
.overflow_x_scroll(self.scroll_state.clone())
|
||||
.child(tab("Cargo.toml", false))
|
||||
.child(tab("Channels Panel", true))
|
||||
.child(tab("channels_panel.rs", false))
|
||||
.child(tab("workspace.rs", false))
|
||||
.child(tab("icon_button.rs", false))
|
||||
.child(tab("storybook.rs", false))
|
||||
.child(tab("theme.rs", false))
|
||||
.child(tab("theme_registry.rs", false))
|
||||
.child(tab("styleable_helpers.rs", false)),
|
||||
),
|
||||
)
|
||||
// Right Side
|
||||
.child(
|
||||
div()
|
||||
.px_1()
|
||||
.flex()
|
||||
.flex_none()
|
||||
.gap_2()
|
||||
// Nav Buttons
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_px()
|
||||
.child(icon_button("icons/plus.svg"))
|
||||
.child(icon_button("icons/split.svg")),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::Shape;
|
||||
use crate::{avatar, follow_group, icon_button, text_button, theme, tool_divider};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct TitleBar<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
pub fn title_bar<V: 'static>() -> TitleBar<V> {
|
||||
TitleBar {
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> TitleBar<V> {
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
let player_list = vec![
|
||||
avatar("https://avatars.githubusercontent.com/u/1714999?v=4"),
|
||||
avatar("https://avatars.githubusercontent.com/u/1714999?v=4"),
|
||||
];
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.w_full()
|
||||
.h_8()
|
||||
.fill(theme.lowest.base.default.background)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.h_full()
|
||||
.gap_4()
|
||||
.px_2()
|
||||
// === Traffic Lights === //
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.child(
|
||||
div()
|
||||
.w_3()
|
||||
.h_3()
|
||||
.rounded_full()
|
||||
.fill(theme.lowest.positive.default.foreground),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w_3()
|
||||
.h_3()
|
||||
.rounded_full()
|
||||
.fill(theme.lowest.warning.default.foreground),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w_3()
|
||||
.h_3()
|
||||
.rounded_full()
|
||||
.fill(theme.lowest.negative.default.foreground),
|
||||
),
|
||||
)
|
||||
// === Project Info === //
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(text_button("maxbrunsfeld"))
|
||||
.child(text_button("zed"))
|
||||
.child(text_button("nate/gpui2-ui-components")),
|
||||
)
|
||||
.child(follow_group(player_list.clone()).player(0))
|
||||
.child(follow_group(player_list.clone()).player(1))
|
||||
.child(follow_group(player_list.clone()).player(2)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.child(
|
||||
div()
|
||||
.px_2()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(icon_button("icons/stop_sharing.svg"))
|
||||
.child(icon_button("icons/exit.svg")),
|
||||
)
|
||||
.child(tool_divider())
|
||||
.child(
|
||||
div()
|
||||
.px_2()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(icon_button("icons/mic.svg"))
|
||||
.child(icon_button("icons/speaker-loud.svg"))
|
||||
.child(icon_button("icons/desktop.svg")),
|
||||
)
|
||||
.child(
|
||||
div().px_2().flex().items_center().child(
|
||||
avatar("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||
.shape(Shape::RoundedRectangle),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user