use crate::theme::ActiveTheme as _;
use fluidattacks_designs_domain::typography::{
HeadingSize, TextSize, Weight, FONT_PRIMARY, SPAN_LINE_HEIGHT,
};
use gpui::{
div, px, rgb, App, FontWeight, IntoElement, ParentElement as _, RenderOnce, SharedString,
Styled as _, Window,
};
fn font_weight(weight: Weight) -> FontWeight {
FontWeight(f32::from(weight.value()))
}
#[derive(IntoElement)]
pub struct Text {
content: SharedString,
size: TextSize,
weight: Weight,
color: Option<u32>,
}
impl Text {
pub fn new(content: impl Into<SharedString>) -> Self {
Self {
content: content.into(),
size: TextSize::default(),
weight: Weight::default(),
color: None,
}
}
#[must_use]
pub const fn size(mut self, size: TextSize) -> Self {
self.size = size;
self
}
#[must_use]
pub const fn weight(mut self, weight: Weight) -> Self {
self.weight = weight;
self
}
#[must_use]
pub const fn color(mut self, color: u32) -> Self {
self.color = Some(color);
self
}
}
impl RenderOnce for Text {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let color = self.color.unwrap_or_else(|| cx.theme().colors.text);
div()
.font_family(FONT_PRIMARY)
.text_size(px(self.size.px()))
.line_height(px(self.size.line_height_px()))
.font_weight(font_weight(self.weight))
.text_color(rgb(color))
.child(self.content)
}
}
#[derive(IntoElement)]
pub struct Heading {
content: SharedString,
size: HeadingSize,
weight: Weight,
color: Option<u32>,
}
impl Heading {
pub fn new(content: impl Into<SharedString>) -> Self {
Self {
content: content.into(),
size: HeadingSize::default(),
weight: Weight::Bold,
color: None,
}
}
#[must_use]
pub const fn size(mut self, size: HeadingSize) -> Self {
self.size = size;
self
}
#[must_use]
pub const fn weight(mut self, weight: Weight) -> Self {
self.weight = weight;
self
}
#[must_use]
pub const fn color(mut self, color: u32) -> Self {
self.color = Some(color);
self
}
}
impl RenderOnce for Heading {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let color = self.color.unwrap_or_else(|| cx.theme().colors.text_strong);
div()
.font_family(FONT_PRIMARY)
.text_size(px(self.size.px()))
.line_height(px(self.size.line_height_px()))
.font_weight(font_weight(self.weight))
.text_color(rgb(color))
.child(self.content)
}
}
#[derive(IntoElement)]
pub struct Span {
content: SharedString,
size: TextSize,
weight: Weight,
color: Option<u32>,
line_height: f32,
}
impl Span {
#[must_use]
pub fn new(content: impl Into<SharedString>) -> Self {
Self {
content: content.into(),
size: TextSize::default(),
weight: Weight::default(),
color: None,
line_height: SPAN_LINE_HEIGHT,
}
}
#[must_use]
pub const fn size(mut self, size: TextSize) -> Self {
self.size = size;
self
}
#[must_use]
pub const fn weight(mut self, weight: Weight) -> Self {
self.weight = weight;
self
}
#[must_use]
pub const fn color(mut self, color: u32) -> Self {
self.color = Some(color);
self
}
#[must_use]
pub const fn line_height(mut self, line_height: f32) -> Self {
self.line_height = line_height;
self
}
}
impl RenderOnce for Span {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let color = self.color.unwrap_or_else(|| cx.theme().colors.text);
div()
.font_family(FONT_PRIMARY)
.text_size(px(self.size.px()))
.line_height(px(self.line_height))
.font_weight(font_weight(self.weight))
.text_color(rgb(color))
.max_w_full()
.child(self.content)
}
}