feat(style): generate checked class tokens

Add a boring CSS/SCSS class-token surface: slhx-build discovers static class tokens from hemplate/templates/stylesheets and emits generated CssClass constants. Add CssClasses for hemplate +class/view data and migrate techdemo dynamic/effect fragments toward hemplate-owned views with DOM-aware assertions.

req: style/001

req: style/002

req: style/003

req: html_safety/002

req: view/001

req: test/005
This commit is contained in:
slhx agent
2026-05-25 20:48:31 +02:00
parent 9ceea7de94
commit fee9762069
13 changed files with 638 additions and 54 deletions
+79
View File
@@ -143,6 +143,85 @@ impl SafeHtml {
}
}
/// A generated, checked CSS class token.
///
/// Plain CSS/SCSS owns appearance; slhx only gives Rust a typed reference to
/// class names discovered from build inputs. req: style/001
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct CssClass {
name: &'static str,
}
impl CssClass {
pub const fn new(name: &'static str) -> Self {
Self { name }
}
pub const fn as_str(self) -> &'static str {
self.name
}
}
impl AsRef<str> for CssClass {
fn as_ref(&self) -> &str {
self.name
}
}
impl core::fmt::Display for CssClass {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.name)
}
}
/// A small displayable list of generated CSS class tokens for hemplate `+class`.
/// req: style/003
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct CssClasses {
names: String,
}
impl CssClasses {
pub fn new(classes: impl IntoIterator<Item = CssClass>) -> Self {
let mut names = String::new();
for class in classes {
if !names.is_empty() {
names.push(' ');
}
names.push_str(class.as_str());
}
Self { names }
}
pub fn as_str(&self) -> &str {
&self.names
}
}
impl From<CssClass> for CssClasses {
fn from(class: CssClass) -> Self {
Self::new([class])
}
}
impl<const N: usize> From<[CssClass; N]> for CssClasses {
fn from(classes: [CssClass; N]) -> Self {
Self::new(classes)
}
}
impl AsRef<str> for CssClasses {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl core::fmt::Display for CssClasses {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.names)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct FormContract {
pub fields: &'static [FormField],