use std::path::PathBuf;
#[derive(Clone, Debug, Default)]
pub struct Document {
pub blocks: Vec<Block>,
}
#[derive(Clone, Debug)]
pub enum Block {
Heading {
level: u8,
inlines: Vec<Inline>,
align: Align,
},
Paragraph {
inlines: Vec<Inline>,
align: Align,
},
List(List),
Quote(Vec<Block>),
Code {
lang: Option<String>,
text: String,
},
Divider,
Image(BlockImage),
Columns(Columns),
Table(Table),
}
#[derive(Clone, Debug)]
pub struct Table {
pub header: Option<Vec<Cell>>,
pub rows: Vec<Vec<Cell>>,
pub cols: Vec<ColSpec>,
pub style: TableStyle,
}
#[derive(Clone, Debug)]
pub struct TableStyle {
pub pad_x: Option<f32>,
pub pad_y: Option<f32>,
pub grid: TableGrid,
pub header_fill: bool,
}
impl Default for TableStyle {
fn default() -> Self {
Self { pad_x: None, pad_y: None, grid: TableGrid::default(), header_fill: true }
}
}
#[derive(Clone, Copy, Debug)]
pub struct TableGrid {
pub outer: bool,
pub vertical: bool,
pub horizontal: bool,
}
impl Default for TableGrid {
fn default() -> Self {
Self { outer: true, vertical: true, horizontal: true }
}
}
#[derive(Clone, Debug)]
pub struct ColSpec {
pub align: Align,
pub width: Option<Length>,
}
impl Default for ColSpec {
fn default() -> Self {
Self { align: Align::Left, width: None }
}
}
#[derive(Clone, Debug)]
pub struct Cell {
pub inlines: Vec<Inline>,
pub bg: Option<Color>,
}
#[derive(Clone, Debug)]
pub struct Columns {
pub cols: Vec<Column>,
pub gap: Option<f32>,
}
#[derive(Clone, Debug)]
pub struct Column {
pub blocks: Vec<Block>,
pub weight: f32,
}
#[derive(Clone, Debug)]
pub struct List {
pub kind: ListKind,
pub start: u32,
pub items: Vec<ListItem>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ListKind {
Unordered,
Ordered,
}
#[derive(Clone, Debug)]
pub struct ListItem {
pub blocks: Vec<Block>,
pub check: Option<bool>,
}
#[derive(Clone, Debug)]
pub struct BlockImage {
pub src: ImageSource,
pub width: Option<Length>,
pub align: Align,
pub caption: Option<Vec<Inline>>,
}
#[derive(Clone, Debug)]
pub enum Inline {
Text {
text: String,
style: TextStyle,
},
Code(String),
LineBreak,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TextStyle {
pub weight: Option<u16>,
pub italic: bool,
pub underline: bool,
pub strike: bool,
pub color: Option<Color>,
pub highlight: Option<Highlight>,
pub size: f32,
pub font: FontRole,
pub link: bool,
}
impl Default for TextStyle {
fn default() -> Self {
Self {
weight: None,
italic: false,
underline: false,
strike: false,
color: None,
highlight: None,
size: 1.0,
font: FontRole::Sans,
link: false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Highlight {
Theme,
Custom(Color),
}
#[derive(Clone, Debug, PartialEq)]
pub enum FontRole {
Sans,
Serif,
Mono,
Kai,
Named(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum Align {
#[default]
Left,
Center,
Right,
Justify,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b, a: 255 }
}
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn hex(s: &str) -> Option<Self> {
let h = s.strip_prefix('#').unwrap_or(s);
if !h.bytes().all(|b| b.is_ascii_hexdigit()) {
return None;
}
let n = |slice: &str| u8::from_str_radix(slice, 16).ok();
match h.len() {
3 => {
let b = h.as_bytes();
let dup = |c: u8| {
let d = (c as char).to_digit(16)? as u8;
Some(d << 4 | d)
};
Some(Self::rgb(dup(b[0])?, dup(b[1])?, dup(b[2])?))
}
6 => Some(Self::rgb(n(&h[0..2])?, n(&h[2..4])?, n(&h[4..6])?)),
8 => Some(Self::rgba(n(&h[0..2])?, n(&h[2..4])?, n(&h[4..6])?, n(&h[6..8])?)),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Length {
Px(f32),
Percent(f32),
}
#[derive(Clone, Debug)]
pub enum ImageSource {
Bytes(Vec<u8>),
Path(PathBuf),
Named(String),
}