返回 CodeWhale
website.rs
1 //! Export actual Ratatui previews for the Codewhale component website.
2 //!
3 //! cargo run --locked --example website -- target/website-buffers
4 //! python3 tools/export-website.py target/website-buffers /path/to/public/ratatui
5 //!
6 //! The website receives painted buffers, rather than a second implementation
7 //! of the components. Width choices redraw the same fixture at that width.
8
9 use std::{collections::BTreeSet, io, path::PathBuf};
10
11 use codewhale_ratatui::{
12 gallery,
13 testing::{self, Profile},
14 };
15 use serde_json::{Map, Value, json};
16
17 fn export(dir: PathBuf) -> io::Result<()> {
18 let entries = gallery::entries();
19 let names: BTreeSet<_> = entries.iter().map(|entry| entry.name).collect();
20 let safe_name = |name: &str| {
21 !name.is_empty()
22 && name
23 .bytes()
24 .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
25 };
26 if names.len() != entries.len() || names.iter().any(|name| !safe_name(name)) {
27 return Err(io::Error::other(
28 "gallery names must be unique safe basenames",
29 ));
30 }
31 std::fs::create_dir_all(&dir)?;
32 let mut manifest = Vec::with_capacity(entries.len());
33 let mut count = 0;
34 for entry in &entries {
35 let mut previews = Map::new();
36 for profile in Profile::ALL {
37 let theme = profile.theme();
38 let resolved = gallery::theme_for(entry, &theme);
39 let mut widths = Map::new();
40 for (key, width) in [
41 ("native", entry.width),
42 ("40", 40),
43 ("80", 80),
44 ("120", 120),
45 ] {
46 let buffer = gallery::render_at(entry, &theme, width, entry.height);
47 widths.insert(key.into(), Value::String(testing::svg(&buffer, &resolved)));
48 count += 1;
49 }
50 previews.insert(profile.name().into(), Value::Object(widths));
51 }
52 let value = json!({
53 "name": entry.name,
54 "width": entry.width,
55 "height": entry.height,
56 "previews": previews,
57 });
58 std::fs::write(
59 dir.join(format!("{}.json", entry.name)),
60 serde_json::to_vec(&value)?,
61 )?;
62 manifest.push(json!({"name": entry.name, "width": entry.width, "height": entry.height}));
63 }
64 std::fs::write(
65 dir.join("manifest.json"),
66 serde_json::to_vec_pretty(&manifest)?,
67 )?;
68 println!(
69 "Exported {count} actual buffers for {} gallery entries to {}",
70 entries.len(),
71 dir.display()
72 );
73 Ok(())
74 }
75
76 fn main() -> io::Result<()> {
77 let args: Vec<_> = std::env::args_os().skip(1).collect();
78 if args.len() != 1 {
79 return Err(io::Error::new(
80 io::ErrorKind::InvalidInput,
81 "usage: website OUTPUT_DIRECTORY",
82 ));
83 }
84 export(PathBuf::from(&args[0]))
85 }
86
86 lines RUST