mod lucide;
pub use lucide::{IconName, LUCIDE_VERSION};
use std::borrow::Cow;
use std::sync::atomic::{AtomicBool, Ordering};
use gpui::prelude::*;
use gpui::{div, px, App, IntoElement, SharedString, Window};
use crate::theme::{theme, ColorName, Size};
pub(crate) const FONT_FAMILY: &str = "lucide";
static FONT_BYTES: &[u8] = include_bytes!("../../assets/lucide/lucide.ttf");
static FONT_REGISTERED: AtomicBool = AtomicBool::new(false);
pub(crate) fn ensure_font(cx: &App) {
if !FONT_REGISTERED.swap(true, Ordering::Relaxed) {
cx.text_system()
.add_fonts(vec![Cow::Borrowed(FONT_BYTES)])
.expect("failed to register the embedded Lucide icon font");
}
}
#[derive(Debug, Clone, IntoElement)]
pub enum Glyph {
Lucide(IconName),
Text(SharedString),
}
impl From<IconName> for Glyph {
fn from(name: IconName) -> Self {
Glyph::Lucide(name)
}
}
impl From<&'static str> for Glyph {
fn from(text: &'static str) -> Self {
Glyph::Text(SharedString::new_static(text))
}
}
impl From<String> for Glyph {
fn from(text: String) -> Self {
Glyph::Text(text.into())
}
}
impl From<SharedString> for Glyph {
fn from(text: SharedString) -> Self {
Glyph::Text(text)
}
}
impl RenderOnce for Glyph {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
match self {
Glyph::Lucide(name) => {
ensure_font(cx);
div()
.font_family(FONT_FAMILY)
.child(SharedString::new_static(name.glyph()))
}
Glyph::Text(text) => div().child(text),
}
}
}
#[derive(IntoElement)]
pub struct Icon {
name: IconName,
size: Size,
color: Option<ColorName>,
}
impl Icon {
pub fn new(name: IconName) -> Self {
Icon {
name,
size: Size::Md,
color: None,
}
}
pub fn size(mut self, size: Size) -> Self {
self.size = size;
self
}
pub fn color(mut self, color: ColorName) -> Self {
self.color = Some(color);
self
}
fn glyph_px(&self) -> f32 {
match self.size {
Size::Xs => 14.0,
Size::Sm => 16.0,
Size::Md => 20.0,
Size::Lg => 26.0,
Size::Xl => 32.0,
}
}
}
impl RenderOnce for Icon {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
ensure_font(cx);
let t = theme(cx);
let tint = self.color.map(|c| t.color(c, t.primary_shade()).hsla());
let size = px(self.glyph_px());
let mut el = div()
.flex()
.items_center()
.justify_center()
.font_family(FONT_FAMILY)
.text_size(size)
.line_height(size)
.child(SharedString::new_static(self.name.glyph()));
if let Some(tint) = tint {
el = el.text_color(tint);
}
el
}
}