diff --git a/README.md b/README.md
index e84f9ed..e3b791b 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
> search bar that people can use to do many things, like opening apps,
> calculators, quick-notes, etc.
-
+
## Installation:
diff --git a/docs/default.toml b/docs/default.toml
index e81e61e..698317d 100644
--- a/docs/default.toml
+++ b/docs/default.toml
@@ -13,8 +13,11 @@ clear_on_enter = true
[theme]
text_color = [0.95, 0.95, 0.96]
-background_color = [0.0, 0.0, 0.0]
-background_opacity = 0.25
+background_color = [0.09, 0.09, 0.09]
+# Background opacity should / can be omitted from 0.4.5 onwards,
+# as rustcast doesn't support custom opacity's anymore,
+# this field will have no effect on rustcast
+background_opacity = 0.0
blur = false
show_icons = true
show_scroll_bar = true
diff --git a/docs/index.html b/docs/index.html
index b874642..f7828ca 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -98,7 +98,7 @@
-

+
![]()
(
- &'a self,
- theme: &'a crate::config::Theme,
+ pub fn render(
+ self,
+ theme: crate::config::Theme,
id_num: u32,
focussed_id: u32,
- ) -> impl Into
> {
- let mut tile = Row::new().width(Fill).height(55);
+ ) -> iced::Element<'static, Message> {
+ let focused = focussed_id == id_num;
+
+ // Title + subtitle (Raycast style)
+ let text_block = iced::widget::Column::new()
+ .spacing(2)
+ .push(
+ Text::new(self.name)
+ .font(theme.font())
+ .size(16)
+ .color(theme.text_color(1.0)),
+ )
+ .push(
+ Text::new(self.desc)
+ .font(theme.font())
+ .size(13)
+ .color(theme.text_color(0.55)),
+ );
+
+ let mut row = Row::new()
+ .align_y(Alignment::Center)
+ .width(Fill)
+ .spacing(10)
+ .height(50);
if theme.show_icons
&& let Some(icon) = &self.icons
{
- tile = tile
- .push(container(Viewer::new(icon).height(35).width(35)))
- .align_y(Alignment::Center);
+ row = row.push(
+ container(Viewer::new(icon).height(40).width(40))
+ .width(40)
+ .height(40),
+ );
}
+ row = row.push(container(text_block).width(Fill));
- tile = tile.push(
- Button::new(
- Text::new(&self.name)
- .font(theme.font())
- .height(Fill)
- .width(Fill)
- .color(theme.text_color(1.))
- .align_y(Vertical::Center),
- )
- .on_press_maybe({
- match self.open_command.clone() {
- AppCommand::Function(func) => Some(Message::RunFunction(func)),
- AppCommand::Message(msg) => Some(msg),
- AppCommand::Display => None,
- }
- })
- .style(|_, _| iced::widget::button::Style {
- background: None,
- text_color: theme.text_color(1.),
- ..Default::default()
- })
- .width(Fill)
- .height(55),
- );
+ let msg = match self.open_command.clone() {
+ AppCommand::Function(func) => Some(Message::RunFunction(func)),
+ AppCommand::Message(msg) => Some(msg),
+ AppCommand::Display => None,
+ };
- tile = tile
- .push(
- container(
- Text::new(&self.desc)
- .font(theme.font())
- .color(theme.text_color(0.4)),
- )
- .padding(12),
- )
- .width(Fill);
+ let theme_clone = theme.clone();
- let (highlight_opacity, border_width) = if focussed_id == id_num {
- (0.7, 0.55)
- } else {
- (0.5, 0.1)
- };
+ let content = Button::new(row)
+ .on_press_maybe(msg)
+ .style(move |_, _| result_button_style(&theme_clone))
+ .width(Fill)
+ .padding(0)
+ .height(50);
- container(tile)
+ container(content)
.id(format!("result-{}", id_num))
- .style(move |_| iced::widget::container::Style {
- text_color: Some(theme.text_color(1.)),
- background: Some(Background::Color(theme.bg_color())),
- border: iced::Border {
- color: theme.text_color(highlight_opacity),
- width: border_width,
- radius: Radius::new(0),
- },
- ..Default::default()
- })
- .max_height(55)
- .padding(5)
+ .style(move |_| result_row_container_style(&theme, focused))
+ .padding(8)
.width(Fill)
- .height(Fill)
+ .into()
}
}
diff --git a/src/app/tile.rs b/src/app/tile.rs
index d62045f..bcef005 100644
--- a/src/app/tile.rs
+++ b/src/app/tile.rs
@@ -84,16 +84,16 @@ impl AppIndex {
/// - Page ([`Page`]) the current page of the window (main or clipboard history)
#[derive(Clone)]
pub struct Tile {
- theme: iced::Theme,
- focus_id: u32,
- query: String,
+ pub theme: iced::Theme,
+ pub focus_id: u32,
+ pub query: String,
query_lc: String,
results: Vec,
options: AppIndex,
visible: bool,
focused: bool,
frontmost: Option>,
- config: Config,
+ pub config: Config,
/// The opening hotkey
hotkey: HotKey,
clipboard_content: Vec,
@@ -137,12 +137,10 @@ impl Tile {
/// - Window focus changes
pub fn subscription(&self) -> Subscription {
let keyboard = event::listen_with(|event, _, id| match event {
- event::Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => match key {
- keyboard::Key::Named(keyboard::key::Named::Escape) => {
- Some(Message::EscKeyPressed(id))
- }
- _ => None,
- },
+ event::Event::Keyboard(keyboard::Event::KeyPressed {
+ key: keyboard::Key::Named(keyboard::key::Named::Escape),
+ ..
+ }) => Some(Message::EscKeyPressed(id)),
_ => None,
});
Subscription::batch([
diff --git a/src/app/tile/elm.rs b/src/app/tile/elm.rs
index 0e52a09..60000f1 100644
--- a/src/app/tile/elm.rs
+++ b/src/app/tile/elm.rs
@@ -15,9 +15,8 @@ use rayon::{
slice::ParallelSliceMut,
};
-use crate::app::apps::AppCommand;
use crate::app::tile::AppIndex;
-use crate::config::Theme;
+use crate::styles::{contents_style, rustcast_text_input_style};
use crate::{
app::{Message, Page, apps::App, default_settings, tile::Tile},
config::Config,
@@ -93,8 +92,8 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
.on_submit(Message::OpenFocused)
.id("query")
.width(Fill)
- .line_height(LineHeight::Relative(1.5))
- .style(|_, _| text_input_style(&tile.config.theme))
+ .line_height(LineHeight::Relative(1.75))
+ .style(|_, status| rustcast_text_input_style(&tile.config.theme, status))
.padding(20);
let scrollbar_direction = if tile.config.theme.show_scroll_bar {
@@ -107,70 +106,42 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
} else {
Direction::Vertical(Scrollbar::hidden())
};
- let results = match tile.page {
- Page::Main => {
- let mut search_results = Column::new();
- for (i, result) in tile.results.iter().enumerate() {
- search_results = search_results.push(result.render(
- &tile.config.theme,
- i as u32,
- tile.focus_id,
- ));
- }
- search_results
- }
- Page::ClipboardHistory => {
- let mut clipboard_history = Column::new();
- for result in &tile.clipboard_content {
- clipboard_history = clipboard_history
- .push(result.render_clipboard_item(tile.config.theme.clone()));
- }
- clipboard_history
- }
+
+ let results = if tile.page == Page::ClipboardHistory {
+ Column::from_iter(
+ tile.clipboard_content
+ .iter()
+ .enumerate()
+ .map(|(i, content)| {
+ content
+ .to_app()
+ .render(tile.config.theme.clone(), i as u32, tile.focus_id)
+ }),
+ )
+ } else {
+ Column::from_iter(tile.results.iter().enumerate().map(|(i, app)| {
+ app.clone()
+ .render(tile.config.theme.clone(), i as u32, tile.focus_id)
+ }))
};
- let scrollable = Scrollable::with_direction(results, scrollbar_direction).id("results");
- let contents = Column::new().push(title_input).push(scrollable);
- container(contents)
- .style(|_| iced::widget::container::Style {
- background: None,
+ let scrollable = Scrollable::with_direction(results, scrollbar_direction).id("results");
+ let contents = container(Column::new().push(title_input).push(scrollable).spacing(0))
+ .style(|_| container::Style {
text_color: None,
+ background: None,
border: iced::Border {
- color: tile.config.theme.text_color(1.),
+ color: Color::WHITE,
width: 1.,
- radius: Radius::new(0),
+ radius: Radius::new(5),
},
..Default::default()
- })
- .padding(0)
- .clip(true)
+ });
+
+ container(contents.clip(true))
+ .style(|_| contents_style(&tile.config.theme))
.into()
} else {
space().into()
}
}
-
-fn text_input_style(theme: &Theme) -> iced::widget::text_input::Style {
- text_input::Style {
- background: iced::Background::Color(Color::TRANSPARENT),
- border: iced::Border {
- color: iced::Color {
- r: 0.95,
- g: 0.95,
- b: 0.95,
- a: 0.7,
- },
- width: 0.5,
- radius: iced::border::Radius {
- top_left: 0.,
- top_right: 0.,
- bottom_right: 0.,
- bottom_left: 0.,
- },
- },
- icon: theme.text_color(0.),
- placeholder: theme.text_color(0.7),
- value: theme.text_color(1.),
- selection: theme.text_color(0.2),
- }
-}
diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs
index 46cd75b..6a83322 100644
--- a/src/app/tile/update.rs
+++ b/src/app/tile/update.rs
@@ -219,7 +219,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task {
id,
iced::Size {
width: WINDOW_WIDTH,
- height: ((max_elem * 55) + DEFAULT_WINDOW_HEIGHT as usize) as f32,
+ height: ((max_elem * 70) + DEFAULT_WINDOW_HEIGHT as usize) as f32,
},
),
Task::done(Message::ChangeFocus(ArrowKey::Left)),
@@ -230,7 +230,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task {
id,
iced::Size {
width: WINDOW_WIDTH,
- height: ((element_count * 55) + DEFAULT_WINDOW_HEIGHT as usize) as f32,
+ height: ((element_count * 70) + DEFAULT_WINDOW_HEIGHT as usize) as f32,
},
)
} else {
diff --git a/src/clipboard.rs b/src/clipboard.rs
index ec671f6..07d6d87 100644
--- a/src/clipboard.rs
+++ b/src/clipboard.rs
@@ -1,12 +1,7 @@
//! This has all the logic regarding the cliboard history
use arboard::ImageData;
-use iced::{
- Length::Fill,
- alignment::Vertical,
- widget::{Button, Row, Text, container},
-};
-use crate::{app::Message, commands::Function, config::Theme as ConfigTheme};
+use crate::{app::apps::App, commands::Function};
/// The kinds of clipboard content that rustcast can handle and their contents
#[derive(Debug, Clone)]
@@ -17,60 +12,23 @@ pub enum ClipBoardContentType {
impl ClipBoardContentType {
/// Returns the iced element for rendering the clipboard item
- pub fn render_clipboard_item(
- &self,
- theme: ConfigTheme,
- ) -> impl Into> {
- let mut tile = Row::new().width(Fill).height(55);
-
- let text = match self {
- ClipBoardContentType::Text(text) => text,
- ClipBoardContentType::Image(_) => "
",
+ pub fn to_app(&self) -> App {
+ let name = match self {
+ ClipBoardContentType::Image(_) => "
".to_string(),
+ ClipBoardContentType::Text(a) => a.to_owned(),
};
- let text_color = theme.text_color(1.);
- let text_color_clone = text_color;
-
- tile = tile.push(
- container(
- Button::new(
- Text::new(text.to_owned())
- .font(theme.font())
- .height(Fill)
- .width(Fill)
- .align_y(Vertical::Center),
- )
- .on_press(Message::RunFunction(Function::CopyToClipboard(
- self.to_owned(),
- )))
- .style(move |_, _| iced::widget::button::Style {
- background: None,
- text_color: text_color_clone,
- ..Default::default()
- })
- .width(Fill)
- .height(55),
- )
- .style(move |_| iced::widget::container::Style {
- text_color: None,
- background: None,
- border: iced::Border {
- color: theme.text_color(0.5),
- width: 0.1,
- radius: iced::border::Radius::new(0),
- },
- ..Default::default()
- }),
- );
+ let self_clone = self.clone();
- container(tile)
- .style(move |_| iced::widget::container::Style {
- text_color: Some(text_color),
- background: None,
- ..Default::default()
- })
- .width(Fill)
- .height(Fill)
+ App {
+ open_command: crate::app::apps::AppCommand::Function(Function::CopyToClipboard(
+ self_clone.to_owned(),
+ )),
+ desc: "Clipboard Item".to_string(),
+ icons: None,
+ name_lc: name.to_lowercase(),
+ name,
+ }
}
}
diff --git a/src/config.rs b/src/config.rs
index 7fa8dc7..5fa79e5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -46,7 +46,6 @@ impl Default for Config {
pub struct Theme {
pub text_color: (f32, f32, f32),
pub background_color: (f32, f32, f32),
- pub background_opacity: f32,
pub blur: bool,
pub show_icons: bool,
pub show_scroll_bar: bool,
@@ -57,8 +56,7 @@ impl Default for Theme {
fn default() -> Self {
Self {
text_color: (0.95, 0.95, 0.96),
- background_color: (0., 0., 0.),
- background_opacity: 0.25,
+ background_color: (0.09, 0.09, 0.09),
blur: false,
show_icons: true,
show_scroll_bar: true,
@@ -119,7 +117,7 @@ impl Theme {
r: self.background_color.0,
g: self.background_color.1,
b: self.background_color.2,
- a: self.background_opacity,
+ a: 0.,
}
}
diff --git a/src/main.rs b/src/main.rs
index 633dd5f..cb1ef46 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@ mod commands;
mod config;
mod haptics;
mod macos;
+mod styles;
mod utils;
use std::path::Path;
diff --git a/src/styles.rs b/src/styles.rs
new file mode 100644
index 0000000..8154ff4
--- /dev/null
+++ b/src/styles.rs
@@ -0,0 +1,89 @@
+use iced::border::Radius;
+use iced::widget::text_input::Status;
+use iced::widget::{button, container};
+use iced::{Background, Border, Color, widget::text_input};
+
+use crate::config::Theme as ConfigTheme;
+
+/// Helper: mix base color with white (simple “tint”)
+pub fn tint(mut c: Color, amount: f32) -> Color {
+ c.r = c.r + (1.0 - c.r) * amount;
+ c.g = c.g + (1.0 - c.g) * amount;
+ c.b = c.b + (1.0 - c.b) * amount;
+ c
+}
+
+/// Helper: apply alpha
+pub fn with_alpha(mut c: Color, a: f32) -> Color {
+ c.a = a;
+ c
+}
+
+pub fn rustcast_text_input_style(theme: &ConfigTheme, status: Status) -> text_input::Style {
+ let base_bg = theme.bg_color();
+ let surface = with_alpha(tint(base_bg, 0.06), 1.0);
+
+ let (border_color, border_width) = match status {
+ text_input::Status::Focused { .. } => (theme.text_color(0.20), 1.),
+ text_input::Status::Hovered => (theme.text_color(0.20), 1.),
+ text_input::Status::Active => (theme.text_color(0.20), 1.),
+ text_input::Status::Disabled => (theme.text_color(0.20), 1.),
+ };
+
+ text_input::Style {
+ background: Background::Color(surface),
+ border: Border {
+ color: border_color,
+ width: border_width,
+ radius: Radius::new(5.0),
+ },
+ icon: theme.text_color(0.7),
+ placeholder: theme.text_color(0.45),
+ value: theme.text_color(1.0),
+ selection: theme.text_color(0.2),
+ }
+}
+
+pub fn contents_style(theme: &ConfigTheme) -> container::Style {
+ container::Style {
+ background: None,
+ text_color: None,
+ border: iced::Border {
+ color: theme.text_color(0.7),
+ width: 1.0,
+ radius: Radius::new(14.0),
+ },
+ ..Default::default()
+ }
+}
+
+pub fn result_button_style(theme: &ConfigTheme) -> button::Style {
+ button::Style {
+ text_color: theme.text_color(1.),
+ background: Some(Background::Color(theme.bg_color())),
+ ..Default::default()
+ }
+}
+
+pub fn result_row_container_style(tile: &ConfigTheme, focused: bool) -> container::Style {
+ let base = tile.bg_color();
+ let row_bg = if focused {
+ with_alpha(tint(base, 0.10), 1.0)
+ } else {
+ with_alpha(tint(base, 0.04), 1.0)
+ };
+
+ container::Style {
+ background: Some(Background::Color(row_bg)),
+ border: Border {
+ color: if focused {
+ tile.text_color(0.35)
+ } else {
+ tile.text_color(0.10)
+ },
+ width: 0.2,
+ radius: Radius::new(0.),
+ },
+ ..Default::default()
+ }
+}