diff --git a/crates/trawler/assets/icons/LICENSE b/crates/trawler/assets/icons/LICENSE new file mode 100644 index 0000000..3e82379 --- /dev/null +++ b/crates/trawler/assets/icons/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2026 Paweł Kuna + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/trawler/assets/icons/arrow-left.svg b/crates/trawler/assets/icons/arrow-left.svg new file mode 100644 index 0000000..52db8fe --- /dev/null +++ b/crates/trawler/assets/icons/arrow-left.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/crates/trawler/assets/icons/arrow-right.svg b/crates/trawler/assets/icons/arrow-right.svg new file mode 100644 index 0000000..25221b2 --- /dev/null +++ b/crates/trawler/assets/icons/arrow-right.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/crates/trawler/assets/icons/calendar.svg b/crates/trawler/assets/icons/calendar.svg new file mode 100644 index 0000000..20d6753 --- /dev/null +++ b/crates/trawler/assets/icons/calendar.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/crates/trawler/assets/icons/chevron-left.svg b/crates/trawler/assets/icons/chevron-left.svg new file mode 100644 index 0000000..137fa6e --- /dev/null +++ b/crates/trawler/assets/icons/chevron-left.svg @@ -0,0 +1,19 @@ + + + + diff --git a/crates/trawler/assets/icons/chevron-right.svg b/crates/trawler/assets/icons/chevron-right.svg new file mode 100644 index 0000000..39d1618 --- /dev/null +++ b/crates/trawler/assets/icons/chevron-right.svg @@ -0,0 +1,19 @@ + + + + diff --git a/crates/trawler/assets/icons/layout-sidebar-right-collapse.svg b/crates/trawler/assets/icons/layout-sidebar-right-collapse.svg new file mode 100644 index 0000000..cb8264f --- /dev/null +++ b/crates/trawler/assets/icons/layout-sidebar-right-collapse.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/crates/trawler/assets/icons/layout-sidebar-right-expand.svg b/crates/trawler/assets/icons/layout-sidebar-right-expand.svg new file mode 100644 index 0000000..79ed430 --- /dev/null +++ b/crates/trawler/assets/icons/layout-sidebar-right-expand.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/crates/trawler/src/assets.rs b/crates/trawler/src/assets.rs new file mode 100644 index 0000000..3c0e1da --- /dev/null +++ b/crates/trawler/src/assets.rs @@ -0,0 +1,109 @@ +//! Embedded UI assets (openspec change ui-polish, capability app-chrome): +//! the bundled Tabler icons, compiled into the binary and served to gpui's +//! `svg()` element through an [`AssetSource`] — the same spirit as the +//! bundled fonts: no system dependencies, identical rendering everywhere. +//! +//! Icons are the MIT-licensed Tabler outline set +//! (); see `assets/icons/LICENSE`. Only the icons +//! the UI actually uses are bundled — add to [`ICONS`] when a new one is +//! needed. + +use std::borrow::Cow; + +use gpui::{AssetSource, Result, SharedString}; + +/// Every bundled icon: the path `svg().path(...)` refers to it by, and its +/// embedded bytes. +const ICONS: &[(&str, &[u8])] = &[ + ( + "icons/arrow-left.svg", + include_bytes!("../assets/icons/arrow-left.svg"), + ), + ( + "icons/arrow-right.svg", + include_bytes!("../assets/icons/arrow-right.svg"), + ), + ( + "icons/calendar.svg", + include_bytes!("../assets/icons/calendar.svg"), + ), + ( + "icons/chevron-left.svg", + include_bytes!("../assets/icons/chevron-left.svg"), + ), + ( + "icons/chevron-right.svg", + include_bytes!("../assets/icons/chevron-right.svg"), + ), + ( + "icons/layout-sidebar-right-collapse.svg", + include_bytes!("../assets/icons/layout-sidebar-right-collapse.svg"), + ), + ( + "icons/layout-sidebar-right-expand.svg", + include_bytes!("../assets/icons/layout-sidebar-right-expand.svg"), + ), +]; + +/// The application's [`AssetSource`], registered via +/// `Application::with_assets` at startup. +pub struct Assets; + +impl AssetSource for Assets { + fn load(&self, path: &str) -> Result>> { + Ok(ICONS + .iter() + .find(|(p, _)| *p == path) + .map(|(_, bytes)| Cow::Borrowed(*bytes))) + } + + fn list(&self, path: &str) -> Result> { + Ok(ICONS + .iter() + .filter(|(p, _)| p.starts_with(path)) + .map(|(p, _)| (*p).into()) + .collect()) + } +} + +/// A bundled Tabler icon sized to sit inline with UI text, tinted a neutral +/// UI-chrome gray. gpui's `Svg` element paints only when a text color is set +/// on the element itself (`Svg::paint` zips the path with the element's own +/// `style.text.color` — there is no cascade for svg tinting), so the color +/// must be explicit here; call sites can override it via `.text_color(...)`. +pub fn icon(path: &'static str) -> gpui::Svg { + use gpui::Styled as _; + gpui::svg() + .path(path) + .size(gpui::px(16.0)) + .flex_none() + .text_color(gpui::rgb(0xd0d0d0)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn every_registered_icon_loads_and_parses_as_svg() { + for (path, _) in ICONS { + let bytes = Assets + .load(path) + .unwrap() + .unwrap_or_else(|| panic!("{path} must load")); + let text = std::str::from_utf8(&bytes).expect("svg is utf-8"); + assert!(text.contains("