use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum PropValue {
Str(String),
Num(f64),
Bool(bool),
Var(String), Asset(String), Content(String), ContentField(String), }
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum Element {
Text(String),
Node {
tag: String,
#[serde(default)]
class_name: Option<String>,
#[serde(default)]
props: HashMap<String, PropValue>,
#[serde(default)]
children: Vec<Box<Element>>,
},
ComponentRef {
component: String,
#[serde(default)]
props: HashMap<String, PropValue>,
#[serde(default)]
children: Vec<Box<Element>>,
},
ContentList {
source: String, template: Box<Element>, },
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ComponentDef {
pub name: String,
pub tag: String,
#[serde(default)]
pub class_name: Option<String>,
#[serde(default)]
pub default_props: HashMap<String, PropValue>,
#[serde(default)]
pub required_props: Vec<String>,
#[serde(default)]
pub children_template: Option<Box<Element>>,
#[serde(default)]
pub import_path: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ComponentDefs {
pub components: Vec<ComponentDef>,
}
impl ComponentDefs {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let options = ron::Options::default()
.with_default_extension(ron::extensions::Extensions::IMPLICIT_SOME);
let defs: ComponentDefs = options.from_str(&content)?;
Ok(defs)
}
pub fn get(&self, name: &str) -> Option<&ComponentDef> {
self.components.iter().find(|c| c.name == name)
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum AssetKind {
Image,
Youtube,
Video,
Audio,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AssetDef {
pub name: String,
pub kind: AssetKind,
#[serde(default)]
pub path: Option<String>, #[serde(default)]
pub url: Option<String>, }
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AssetDefs {
pub assets: Vec<AssetDef>,
}
impl AssetDefs {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let options = ron::Options::default()
.with_default_extension(ron::extensions::Extensions::IMPLICIT_SOME);
let defs: AssetDefs = options.from_str(&content)?;
Ok(defs)
}
pub fn get(&self, name: &str) -> Option<&AssetDef> {
self.assets.iter().find(|a| a.name == name)
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Import {
pub name: String,
pub path: String,
#[serde(default)]
pub kind: ImportKind,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ImportKind {
#[default]
Component,
Asset,
Hook,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ViewProto {
pub name: String,
#[serde(default)]
pub imports: Vec<Import>,
#[serde(default)]
pub observer: bool,
pub tree: Box<Element>,
}
impl ViewProto {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let options = ron::Options::default()
.with_default_extension(ron::extensions::Extensions::IMPLICIT_SOME);
let proto: ViewProto = options.from_str(&content)?;
Ok(proto)
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum ContentValue {
Str(String),
Record(HashMap<String, String>),
List(Vec<ContentValue>),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ContentDefs {
pub content: HashMap<String, ContentValue>,
}
impl ContentDefs {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let options = ron::Options::default()
.with_default_extension(ron::extensions::Extensions::IMPLICIT_SOME);
let defs: ContentDefs = options.from_str(&content)?;
Ok(defs)
}
pub fn get(&self, name: &str) -> Option<&ContentValue> {
self.content.get(name)
}
pub fn get_str(&self, name: &str) -> Option<&String> {
match self.content.get(name) {
Some(ContentValue::Str(s)) => Some(s),
_ => None,
}
}
pub fn get_list(&self, name: &str) -> Option<&Vec<ContentValue>> {
match self.content.get(name) {
Some(ContentValue::List(list)) => Some(list),
_ => None,
}
}
}