diff options
45 files changed, 3661 insertions, 1098 deletions
diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.nojekyll diff --git a/CHANGELOG.md b/CHANGELOG.md index a888cc2..4c86be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ 1. **\[core:flag\]** Refactored the `special_argument!` and `special_arguments!` macros to replace index‑based `while` loops with iterator `position` and `drain`, improving both performance and readability. +2. **\[core:comp\]** Changed the completion system's node filtering to exclude all hidden nodes (names starting with `_`) instead of only the specific `__comp` node. This makes the completion script generation more general — any node prefixed with an underscore is now treated as internal/hidden and excluded from suggestions. + #### Features: 1. **\[core\]** Added the `unpack_chain_process!` macro for ergonomically extracting the inner value from a `ChainProcess` result. @@ -35,6 +37,8 @@ program.with_setup(ConfirmFlagSetup::new(["-C", "--confirm"])); program.with_setup(BasicProgramSetup); ``` +3. **\[core\]** Added `verbose`, `quiet`, `debug`, `color`, and `progress` fields to `ProgramStdoutSetting`, and `dry_run`, `force`, `interactive`, and `assume_yes` fields to `ProgramUserContext`. These fields are annotated as conventions only, meaning the framework does not enforce any particular behavior — it is up to the application to read and act on them. + #### **BREAKING CHANGES** (API CHANGES): 1. **\[core\]** Changed the signature of `ProgramSetup::setup` from `fn setup(&mut self, program: &mut Program<C>) -> S` to `fn setup(self, program: &mut Program<C>)`, consuming `self` instead of taking a mutable reference. Correspondingly, `Program::with_setup` now accepts `S` by value (`&mut self, setup: S`) instead of by mutable reference (`&mut self, setup: &mut S`). @@ -135,9 +135,8 @@ You can read the following docs to learn more about the `Mingling` framework: - [ ] \[**0.2.0**\] Complete documentation, tests, and examples - [ ] Milestone.2 "More Comfortable Dev and User Experience" - - [ ] ... + - [ ] \[**0.2.1**\] \[`macros`\] `r_println!` in `#[chain]` support. - [ ] \[**0.2.5**\] \[`mling`\] Helpdoc Maker - - [ ] ... - [ ] \[**0.2.8**\] \[`picker`\] A more efficient and intelligent argument parser - [ ] Milestone.3 "Unplanned" diff --git a/dev_tools/Cargo.lock b/dev_tools/Cargo.lock index 35d3a8f..1180474 100644 --- a/dev_tools/Cargo.lock +++ b/dev_tools/Cargo.lock @@ -34,6 +34,12 @@ dependencies = [ ] [[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] name = "just_fmt" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -103,6 +109,19 @@ dependencies = [ ] [[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] name = "serde_spanned" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -171,6 +190,7 @@ dependencies = [ "just_fmt", "just_template", "serde", + "serde_json", "toml", ] @@ -203,3 +223,9 @@ checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/dev_tools/Cargo.toml b/dev_tools/Cargo.toml index 280a50c..a904bd5 100644 --- a/dev_tools/Cargo.toml +++ b/dev_tools/Cargo.toml @@ -16,3 +16,4 @@ just_fmt = "0.1.2" colored = "3.1.1" toml = "0.8" serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/dev_tools/scripts/http-page-preview.ps1 b/dev_tools/scripts/http-page-preview.ps1 index 79ed77a..8cc3579 100644 --- a/dev_tools/scripts/http-page-preview.ps1 +++ b/dev_tools/scripts/http-page-preview.ps1 @@ -1,4 +1,3 @@ $starting_dir = Get-Location -Set-Location "docs" python -m http.server 3000 Set-Location $starting_dir diff --git a/dev_tools/scripts/http-page-preview.sh b/dev_tools/scripts/http-page-preview.sh index 6c822d8..bed4b1c 100755 --- a/dev_tools/scripts/http-page-preview.sh +++ b/dev_tools/scripts/http-page-preview.sh @@ -1,3 +1,2 @@ #!/bin/bash -cd "docs" python3 -m http.server 3000 diff --git a/dev_tools/src/bin/ci.rs b/dev_tools/src/bin/ci.rs index 86b930c..a90c413 100644 --- a/dev_tools/src/bin/ci.rs +++ b/dev_tools/src/bin/ci.rs @@ -123,6 +123,7 @@ fn docs_refresh() -> Result<(), i32> { run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docsify-sidebar-gen")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-docs")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-feature-mod")?; + run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin sync-examples")?; Ok(()) } diff --git a/dev_tools/src/bin/sync-examples.rs b/dev_tools/src/bin/sync-examples.rs new file mode 100644 index 0000000..c317af6 --- /dev/null +++ b/dev_tools/src/bin/sync-examples.rs @@ -0,0 +1,134 @@ +use std::fs; +use std::path::Path; + +use serde::{Deserialize, Serialize}; +use tools::println_cargo_style; + +#[derive(Serialize)] +struct ExampleMeta { + id: String, + name: String, + icon: String, + category: String, + desc: String, + tags: Vec<String>, + files: Vec<String>, +} + +#[derive(Deserialize)] +struct PageToml { + example: PageTomlExample, +} + +#[derive(Deserialize)] +struct PageTomlExample { + id: String, + #[serde(default)] + name: String, + #[serde(default = "default_icon")] + icon: String, + #[serde(default)] + category: String, + #[serde(default)] + desc: String, + #[serde(default)] + tags: Vec<String>, + #[serde(default = "default_files")] + files: Vec<String>, +} + +fn default_icon() -> String { + "📦".to_string() +} + +fn default_files() -> Vec<String> { + vec!["Cargo.toml".to_string(), "src/main.rs".to_string()] +} + +fn main() { + #[cfg(windows)] + let _ = colored::control::set_virtual_terminal(true); + + let examples_dir = Path::new("examples"); + let output_dir = Path::new("docs/example-pages"); + fs::create_dir_all(output_dir).expect("failed to create docs/example-pages"); + + let mut examples: Vec<ExampleMeta> = Vec::new(); + + let entries = fs::read_dir(examples_dir).expect("failed to read examples/"); + for entry in entries.flatten() { + let path = entry.path(); + if !path.is_dir() { + continue; + } + + let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + if !dir_name.starts_with("example-") { + continue; + } + + let id = dir_name.to_string(); + let page_toml_path = path.join("page.toml"); + + let meta = if page_toml_path.exists() { + match fs::read_to_string(&page_toml_path) + .map_err(|e| e.to_string()) + .and_then(|content| toml::from_str::<PageToml>(&content).map_err(|e| e.to_string())) + { + Ok(page) => { + let ex = page.example; + ExampleMeta { + id: if ex.id.is_empty() { id.clone() } else { ex.id }, + name: if ex.name.is_empty() { + id.clone() + } else { + ex.name + }, + icon: ex.icon, + category: ex.category, + desc: ex.desc, + tags: ex.tags, + files: if ex.files.is_empty() { + default_files() + } else { + ex.files + }, + } + } + Err(e) => { + eprintln!( + "Warning: failed to parse {}: {}", + page_toml_path.display(), + e + ); + continue; + } + } + } else { + continue; + }; + + examples.push(meta); + } + + // Sort: basic first, then alphabetical + examples.sort_by(|a, b| { + if a.id == "example-basic" { + return std::cmp::Ordering::Less; + } + if b.id == "example-basic" { + return std::cmp::Ordering::Greater; + } + a.id.cmp(&b.id) + }); + + let json = serde_json::to_string_pretty(&examples).expect("failed to serialize"); + let output_path = output_dir.join("examples.json"); + fs::write(&output_path, &json).expect("failed to write examples.json"); + + println_cargo_style!( + "Sync: {} examples -> {}", + examples.len(), + output_path.display() + ); +} diff --git a/docs/README.md b/docs/README.md index 151e348..15c072e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,4 @@ -<p align="center"> - <a href="https://github.com/CatilGrass/mingling"> - <img alt="Mingling" src="res/pixel_icon_o_1024.png" width="40%"> - </a> -</p> -<h1 align="center">Mingling Documentation</h1> +<h1 align="center">Mingling Helpdoc</h1> <p align="center"> This is documentation for the <b>Mingling</b> command-line framework, maintained by <a href="https://github.com/Weicao-CatilGrass">Weicao-CatilGrass</a> diff --git a/docs/_zh_CN/README.md b/docs/_zh_CN/README.md index 36019aa..b302220 100644 --- a/docs/_zh_CN/README.md +++ b/docs/_zh_CN/README.md @@ -1,8 +1,3 @@ -<p align="center"> - <a href="https://github.com/CatilGrass/mingling"> - <img alt="Mingling" src="../res/pixel_icon_o_1024.png" width="40%"> - </a> -</p> <h1 align="center">Mingling 中文文档 🇨🇳</h1> <p align="center"> diff --git a/docs/_zh_CN/index.html b/docs/_zh_CN/index.html index 5420691..a61fde3 100644 --- a/docs/_zh_CN/index.html +++ b/docs/_zh_CN/index.html @@ -16,9 +16,10 @@ <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link - href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&family=Roboto+Mono&family=Dosis:wght@500&display=swap" + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" rel="stylesheet" /> + <link rel="stylesheet" href="../css/light.css" /> <link id="dark-style" @@ -30,11 +31,6 @@ <body> <nav> - <a href="https://crates.io/crates/mingling">发布页</a> - <a href="https://docs.rs/mingling/latest/mingling/">API文档</a> - <a href="https://git.catilgrass.cn/catilgrass/mingling.git" - ><b>源代码</b></a - > <a href="#" onclick=" @@ -43,7 +39,7 @@ " >🌗 主题</a > - <a href="../"><b>英文文档</b></a> + <a href="../doc.html"><b>English Docs</b></a> </nav> <div id="app"></div> diff --git a/docs/_zh_CN/pages/1-intro.md b/docs/_zh_CN/pages/1-intro.md index eea766b..8c5472d 100644 --- a/docs/_zh_CN/pages/1-intro.md +++ b/docs/_zh_CN/pages/1-intro.md @@ -11,22 +11,6 @@ 若您在使用过程中遇到任何问题,欢迎提交 [Issue](https://github.com/catilgrass/mingling/issues),我们乐意解决。 -<div style="display: flex; gap: 16px; padding: 8px; align-items: stretch; max-width: 90%;"> - <div style="flex-shrink: 0; display: flex; align-items: center;"> - <a href="https://github.com/catilgrass/mingling" target="_blank"> - <img src="../res/pixel_icon_core_1024.png" style="height: 120px; object-fit: contain; padding: 8px;" /> - </a> - </div> - <div style="display: flex; flex-direction: column; justify-content: flex-start;"> - <div style="font-weight: bold; font-size: 1.2em; margin-bottom: 8px;"> - <a href="https://github.com/catilgrass/mingling" target="_blank" style="text-decoration: none; color: inherit;">Mingling - Github</a> - </div> - <div style="color: #555;"> - A Rust CLI framework for many subcmds & complex workflows, reduces boilerplate via proc macros, focus on biz logic - </div> - </div> -</div> - ## Mingling 是什么? **Mingling** 是一款 Rust 命令行开发框架,更准确地说,它是一款在调度、执行、渲染等方面提供高度抽象的框架。 diff --git a/docs/css/dark.css b/docs/css/dark.css index 551be70..b14f3dc 100644 --- a/docs/css/dark.css +++ b/docs/css/dark.css @@ -1,9 +1,8 @@ /* - * Based on vue.css - * Original: https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/themes/vue.css + * Mingling Helpdoc — Dark theme (Imperial Edict style) + * Warm dark parchment / gold & vermilion accents */ -@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600"); * { -webkit-font-smoothing: antialiased; -webkit-overflow-scrolling: touch; @@ -15,9 +14,9 @@ body:not(.ready) { overflow: hidden; } +body:not(.ready) [data-cloak], body:not(.ready) .app-nav, -body:not(.ready) > nav, -body:not(.ready) [data-cloak] { +body:not(.ready) > nav { display: none; } div#app { @@ -26,61 +25,57 @@ div#app { margin: 40vh auto; text-align: center; } -div#app:empty:before { +div#app:empty::before { content: "Loading..."; } img.emoji { height: 1.2em; -} -img.emoji, -span.emoji { vertical-align: middle; } span.emoji { font-family: - Apple Color Emoji, - Segoe UI Emoji, - Segoe UI Symbol, - Noto Color Emoji; + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; font-size: 1.2em; + vertical-align: middle; } + +/* ── Progress bar ── */ .progress { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); + background-color: #c43931; height: 2px; - left: 0; + left: 0px; position: fixed; - right: 0; - top: 0; + right: 0px; + top: 0px; transition: width 0.2s, opacity 0.4s; - width: 0; + width: 0%; z-index: 999999; } -.search .search-keyword, + +/* ── Search ── */ .search a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #d4a84b; } .search .search-keyword { + color: #d4a84b; font-style: normal; - font-weight: 700; + font-weight: bold; } -body, -html { + +/* ── Base ── */ +html, +body { height: 100%; } body { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; - background-color: #121212 !important; - color: #f4fefe; - font-family: - Source Sans Pro, - Helvetica Neue, - Arial, - sans-serif; + background-color: #1a1410; + color: #e8ddd0; + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; font-size: 15px; letter-spacing: 0; margin: 0; @@ -94,8 +89,8 @@ a[disabled] { opacity: 0.6; } kbd { - border: 1px solid #ccc; - border-radius: 3px; + border: solid 1px #3a2e24; + border-radius: 2px; display: inline-block; font-size: 12px !important; line-height: 12px; @@ -107,6 +102,8 @@ li input[type="checkbox"] { margin: 0 0.2em 0.25em 0; vertical-align: middle; } + +/* ── Nav bar ── */ .app-nav { margin: 25px 60px 0 0; position: absolute; @@ -124,26 +121,24 @@ li input[type="checkbox"] { margin: 0 1rem; padding: 5px 0; } -.app-nav li, -.app-nav ul { +.app-nav ul, +.app-nav li { display: inline-block; list-style: none; margin: 0; } .app-nav a { - color: inherit; + color: #9a8a7a; font-size: 16px; text-decoration: none; transition: color 0.3s; } -.app-nav a.active, .app-nav a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #d4a84b; } .app-nav a.active { - border-bottom: 2px solid #ff5722; - border-bottom: 2px solid var(--theme-color, #ff5722); + border-bottom: 2px solid #d4a84b; + color: #d4a84b; } .app-nav li { display: inline-block; @@ -153,10 +148,9 @@ li input[type="checkbox"] { cursor: pointer; } .app-nav li ul { - background-color: #fff; - border: 1px solid; - border-color: #ddd #ddd #ccc; - border-radius: 4px; + background-color: #241c16; + border: 1px solid #3a2e24; + border-radius: 2px; box-sizing: border-box; display: none; max-height: calc(100vh - 61px); @@ -187,6 +181,8 @@ li input[type="checkbox"] { .app-nav li:hover ul { display: block; } + +/* ── GitHub corner ── */ .github-corner { border-bottom: 0; position: fixed; @@ -196,15 +192,16 @@ li input[type="checkbox"] { z-index: 1; } .github-corner:hover .octo-arm { - animation: octocat-wave 0.56s ease-in-out; + animation: octocat-wave 560ms ease-in-out; } .github-corner svg { - color: #fff; - fill: #ff5722; - fill: var(--theme-color, #ff5722); + color: #1a1410; + fill: #d4a84b; height: 80px; width: 80px; } + +/* ── Main ── */ main { display: block; position: relative; @@ -221,20 +218,23 @@ main.hidden { transition: all 0.3s; } .anchor span { - color: #f4fefe; + color: #e8ddd0; } .anchor:hover { text-decoration: underline; } + +/* ── Sidebar ── */ .sidebar { - border-right: 1px solid rgba(0, 0, 0, 0.07); + background-color: #0e0a08; + border-right: 1px solid rgba(212, 168, 75, 0.1); overflow-y: auto; padding: 40px 0 0; position: absolute; top: 0; bottom: 0; left: 0; - transition: transform 0.25s ease-out; + transition: transform 250ms ease-out; width: 300px; z-index: 20; } @@ -243,6 +243,7 @@ main.hidden { font-size: 1.5rem; font-weight: 300; text-align: center; + color: #e8ddd0; } .sidebar > h1 a { color: inherit; @@ -266,6 +267,7 @@ main.hidden { .sidebar li > p { font-weight: 700; margin: 0; + color: #e8ddd0; } .sidebar ul, .sidebar ul li { @@ -274,10 +276,31 @@ main.hidden { .sidebar ul li a { border-bottom: none; display: block; + color: #9a8a7a; + font-size: 14px; + font-weight: 400; + overflow: hidden; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + transition: color 0.2s; +} +.sidebar ul li a:hover { + color: #d4a84b; } .sidebar ul li ul { padding-left: 20px; } +.sidebar ul li.active > a { + border-right: 2px solid #c43931; + color: #d4a84b; + font-weight: 600; + background: linear-gradient( + to left, + rgba(196, 57, 49, 0.15), + transparent 30% + ); +} .sidebar::-webkit-scrollbar { width: 4px; } @@ -286,14 +309,15 @@ main.hidden { border-radius: 4px; } .sidebar:hover::-webkit-scrollbar-thumb { - background: hsla(0, 0%, 53.3%, 0.4); + background: rgba(212, 168, 75, 0.3); } .sidebar:hover::-webkit-scrollbar-track { - background: hsla(0, 0%, 53.3%, 0.1); + background: rgba(212, 168, 75, 0.08); } + +/* ── Sidebar toggle ── */ .sidebar-toggle { background-color: transparent; - background-color: transparent; border: 0; outline: none; padding: 10px; @@ -310,8 +334,7 @@ main.hidden { opacity: 0.4; } .sidebar-toggle span { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); + background-color: #d4a84b; display: block; margin-bottom: 4px; width: 16px; @@ -321,6 +344,8 @@ body.sticky .sidebar, body.sticky .sidebar-toggle { position: fixed; } + +/* ── Content ── */ .content { padding-top: 60px; position: absolute; @@ -328,16 +353,15 @@ body.sticky .sidebar-toggle { right: 0; bottom: 0; left: 300px; - transition: left 0.25s ease; - background-color: #121212; + transition: left 250ms ease; } + +/* ── Markdown ── */ .markdown-section { margin: 0 auto; max-width: 80%; - padding: 30px 45px 40px; + padding: 30px 15px 40px 15px; position: relative; - background-color: #121212; - color: #fefefe; } .markdown-section > * { box-sizing: border-box; @@ -348,14 +372,9 @@ body.sticky .sidebar-toggle { } .markdown-section hr { border: none; - border-bottom: 1px solid #323232; + border-bottom: 1px solid #3a2e24; margin: 2em 0; } -.markdown-section iframe { - border: 1px solid #eee; - width: 1px; - min-width: 100%; -} .markdown-section table { border-collapse: collapse; border-spacing: 0; @@ -365,311 +384,28 @@ body.sticky .sidebar-toggle { width: 100%; } .markdown-section th { - font-weight: 700; + border: 1px solid #3a2e24; + font-weight: bold; + padding: 6px 13px; + color: #e8ddd0; + background-color: #241c16; } -.markdown-section td, -.markdown-section th { - border: 1px solid #333; +.markdown-section td { + border: 1px solid #3a2e24; padding: 6px 13px; } .markdown-section tr { - border-top: 1px solid #222; + border-top: 1px solid #3a2e24; } -.markdown-section p.tip, .markdown-section tr:nth-child(2n) { - background-color: #252525; -} -.markdown-section p.tip { - border-bottom-right-radius: 2px; - border-left: 4px solid #ff4081; - border-top-right-radius: 2px; - margin: 2em 0; - padding: 12px 24px 12px 30px; - position: relative; -} -.markdown-section p.tip:before { - background-color: #ff4081; - border-radius: 100%; - color: #fff; - content: "!"; - font-family: - Dosis, - Source Sans Pro, - Helvetica Neue, - Arial, - sans-serif; - font-size: 14px; - font-weight: 700; - left: -12px; - line-height: 20px; - position: absolute; - height: 20px; - width: 20px; - text-align: center; - top: 14px; -} -.markdown-section p.tip code { - background-color: #efefef; -} -.markdown-section p.tip em { - color: #f4fefe; -} -.markdown-section p.warn { - background: rgba(66, 185, 131, 0.1); - border-radius: 2px; - padding: 1rem; -} -.markdown-section ul.task-list > li { - list-style-type: none; -} -body.close .sidebar { - transform: translateX(-300px); -} -body.close .sidebar-toggle { - width: auto; -} -body.close .content { - left: 0; -} -@media print { - .app-nav, - .github-corner, - .sidebar, - .sidebar-toggle { - display: none; - } -} -@media screen and (max-width: 768px) { - .github-corner, - .sidebar, - .sidebar-toggle { - position: fixed; - } - .app-nav { - margin-top: 16px; - } - .app-nav li ul { - top: 30px; - } - main { - height: auto; - min-height: 100vh; - overflow-x: hidden; - } - .sidebar { - left: -300px; - transition: transform 0.25s ease-out; - } - .content { - left: 0; - max-width: 100vw; - position: static; - padding-top: 20px; - transition: transform 0.25s ease; - } - .app-nav, - .github-corner { - transition: transform 0.25s ease-out; - } - .sidebar-toggle { - background-color: transparent; - width: auto; - padding: 30px 30px 10px 10px; - } - body.close .sidebar { - transform: translateX(300px); - } - body.close .sidebar-toggle { - transition: background-color 1s; - width: 284px; - padding: 10px; - } - body.close .content { - transform: translateX(300px); - } - body.close .app-nav, - body.close .github-corner { - display: none; - } - .github-corner:hover .octo-arm { - animation: none; - } - .github-corner .octo-arm { - animation: octocat-wave 0.56s ease-in-out; - } -} -@keyframes octocat-wave { - 0%, - to { - transform: rotate(0); - } - 20%, - 60% { - transform: rotate(-25deg); - } - 40%, - 80% { - transform: rotate(10deg); - } -} -section.cover { - position: relative; - align-items: center; - background-position: 50%; - background-repeat: no-repeat; - background-size: cover; - min-height: 100vh; - width: 100%; - display: none; -} -section.cover.show { - display: flex; -} -section.cover.has-mask .mask { - background-color: #fff; - opacity: 0.8; - position: absolute; - top: 0; - bottom: 0; - width: 100%; -} -section.cover .cover-main { - flex: 1; - margin: 0 16px; - text-align: center; - position: relative; -} -section.cover a { - color: inherit; -} -section.cover a, -section.cover a:hover { - text-decoration: none; -} -section.cover p { - line-height: 1.5rem; - margin: 1em 0; -} -section.cover h1 { - color: inherit; - font-size: 2.5rem; - font-weight: 300; - margin: 0.625rem 0 2.5rem; - position: relative; - text-align: center; -} -section.cover h1 a { - display: block; -} -section.cover h1 small { - bottom: -0.4375rem; - font-size: 1rem; - position: absolute; -} -section.cover blockquote { - font-size: 1.5rem; - text-align: center; -} -section.cover ul { - line-height: 1.8; - list-style-type: none; - margin: 1em auto; - max-width: 500px; - padding: 0; -} -section.cover .cover-main > p:last-child a { - border-radius: 2rem; - border: 1px solid #ff5722; - border-color: var(--theme-color, #ff5722); - box-sizing: border-box; - color: #ff5722; - color: var(--theme-color, #ff5722); - display: inline-block; - font-size: 1.05rem; - letter-spacing: 0.1rem; - margin: 0.5rem 1rem; - padding: 0.75em 2rem; - text-decoration: none; - transition: all 0.15s ease; -} -section.cover .cover-main > p:last-child a:last-child { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); - color: #fff; -} -section.cover .cover-main > p:last-child a:last-child:hover { - color: inherit; - opacity: 0.8; -} -section.cover .cover-main > p:last-child a:hover { - color: inherit; -} -section.cover blockquote > p > a { - border-bottom: 2px solid #ff5722; - border-bottom: 2px solid var(--theme-color, #ff5722); - transition: color 0.3s; -} -section.cover blockquote > p > a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); -} -.sidebar, -body { - background-color: #fefefe; -} -.sidebar { - background-color: #080808; - color: #fefefe; -} -.sidebar li { - margin: 6px 0; -} -.sidebar ul li a { - color: #fefefe; - font-size: 14px; - font-weight: 400; - overflow: hidden; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; -} -.sidebar ul li a:hover { - text-decoration: underline; -} -.sidebar ul li ul { - padding: 0; -} -.sidebar ul li.active > a { - border-right: 2px solid; - color: #ff5722; - color: var(--theme-color, #ff5722); - font-weight: 600; - background: linear-gradient(to left, #ff572255, transparent 30%); - text-shadow: 0 0 8px rgba(255, 87, 34, 0.3); -} -.sidebar ul li > a:hover { - background: linear-gradient( - to left, - rgba(255, 87, 34, 0.05), - transparent 50% - ); -} -.app-sub-sidebar li:before { - content: "-"; - padding-right: 4px; - float: left; + background-color: #1e1612; } .markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section strong { - color: #f2fefe; - font-weight: 600; -} -.markdown-section a { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #e8ddd0; font-weight: 600; } .markdown-section h1 { @@ -686,106 +422,85 @@ body { } .markdown-section h4 { font-size: 1.25rem; + margin: 35px 0 0.5rem; } .markdown-section h5 { font-size: 1rem; } .markdown-section h6 { - color: #777; - font-size: 1rem; + font-size: 0.9rem; + color: #9a8a7a; } -.markdown-section figure, -.markdown-section p { - margin: 1.2em 0; -} -.markdown-section ol, -.markdown-section p, -.markdown-section ul { - line-height: 1.6rem; - word-spacing: 0.05rem; +.markdown-section a { + color: #d4a84b; } -.markdown-section ol, -.markdown-section ul { - padding-left: 1.5rem; +.markdown-section code { + color: #e8c46a; + background-color: #241c16; + border-radius: 2px; + padding: 0.15em 0.4em; } -.markdown-section blockquote { - border-left: 4px solid #ff5722; - border-left: 4px solid var(--theme-color, #ff5722); - color: #858585; - margin: 2em 0; - padding-left: 20px; +.markdown-section pre { + background-color: #241c16; + border: 1px solid #3a2e24; + border-radius: 2px; + padding: 1rem; + overflow-x: auto; } -.markdown-section blockquote p { - font-weight: 600; - margin-left: 0; +.markdown-section pre > code { + background: transparent; + padding: 0; + color: #e8ddd0; } -.markdown-section iframe { +.markdown-section blockquote { + border-left: 3px solid #c43931; + color: #9a8a7a; margin: 1em 0; + padding: 0.5em 1em; } -.markdown-section em { - color: #7f8c8d; +.markdown-section p.tip { + background-color: #241c16; + border-bottom-right-radius: 2px; + border-left: 4px solid #c43931; + border-top-right-radius: 2px; + margin: 2em 0; + padding: 12px 24px 12px 30px; + position: relative; } -.markdown-section code, -.markdown-section output:after, -.markdown-section pre { - font-family: - Roboto Mono, - Monaco, - courier, - monospace; +.markdown-section p.tip:before { + background-color: #c43931; + border-radius: 100%; + color: #e8ddd0; + content: "!"; + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; + font-size: 14px; + font-weight: bold; + left: -12px; + line-height: 20px; + position: absolute; + height: 20px; + width: 20px; + text-align: center; + top: 14px; } -.markdown-section code, -.markdown-section pre { - background-color: #212121; +.markdown-section p.tip code { + background-color: #1a1410; } -.markdown-section output, -.markdown-section pre { - margin: 1.2em 0; - position: relative; - border-radius: 6px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +.markdown-section p.tip em { + color: #d4a84b; } -.markdown-section output, -.markdown-section pre > code { +.markdown-section p.warn { + background: rgba(212, 168, 75, 0.06); border-radius: 2px; - display: block; + padding: 1rem; } -.markdown-section output:after, -.markdown-section pre > code { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; +.markdown-section ul.task-list > li { + list-style-type: none; } -.markdown-section code { + +/* ── Flexible alerts (docsify-plugin-flexible-alerts) ── */ +.alert.callout { border-radius: 2px; - color: #f64739; - margin: 0 2px; - padding: 3px 5px; - white-space: pre-wrap; -} -.markdown-section > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code { - font-size: 0.8rem; -} -.markdown-section pre { - padding: 0 1.4rem; - line-height: 1.5rem; - overflow: auto; - word-wrap: normal; -} -.markdown-section pre > code { - color: #525252; - font-size: 0.8rem; - padding: 2.2em 5px; - line-height: inherit; - margin: 0 2px; - max-width: inherit; - overflow: inherit; - white-space: inherit; -} -.markdown-section pre code { - color: #eee; -} -.markdown-section pre code .token.punctuation { - color: #eee; } .alert.callout.note { border: 1px solid #00bcd4; @@ -837,99 +552,74 @@ body { .alert.callout.attention a { color: #f9483b; } -.markdown-section output { - padding: 1.7rem 1.4rem; - border: 1px dotted #ccc; -} -.markdown-section output > :first-child { - margin-top: 0; -} -.markdown-section output > :last-child { - margin-bottom: 0; -} -.markdown-section code:after, -.markdown-section code:before, -.markdown-section output:after, -.markdown-section output:before { - letter-spacing: 0.05rem; -} -.markdown-section output:after, -.markdown-section pre:after { - color: #ccc; - font-size: 0.6rem; - font-weight: 600; - height: 15px; - line-height: 15px; - padding: 5px 10px 0; - position: absolute; - right: 0; - text-align: right; - top: 0; - content: attr(data-lang); +.alert.callout code { + background-color: transparent; } + +/* ── Prism syntax highlighting ── */ .token.cdata, .token.comment, .token.doctype, .token.prolog { - color: #8e908c; + color: #6a5a4a; } .token.namespace { opacity: 0.7; } .token.boolean, .token.number { - color: #4caf50; + color: #d4a84b; } .token.punctuation { - color: #525252; + color: #6a5a4a; } .token.property { - color: #c08b30; + color: #e8c46a; } .token.tag { - color: #ff5722; + color: #c43931; } .token.string { - color: #4caf50; - color: var(--theme-color, #4caf50); + color: #b8943e; } .token.selector { - color: #6679cc; + color: #7a9aba; } .token.attr-name { - color: #2973b7; + color: #9a8a7a; } .language-css .token.string, .style .token.string, .token.entity, .token.url { - color: #22a2c9; + color: #6a9aba; } .token.attr-value, .token.control, .token.directive, .token.unit { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #d4a84b; +} +.token.function { + color: #d4a84b; } -.token.function, .token.keyword { - color: #f44336; + color: #c43931; } .token.atrule, .token.regex, .token.statement { - color: #22a2c9; + color: #6a9aba; } .token.placeholder, .token.variable { - color: #3d8fd1; + color: #7a9aba; } .token.deleted { text-decoration: line-through; } .token.inserted { - border-bottom: 1px dotted #202746; + border-bottom: 1px dotted #3a2e24; text-decoration: none; } .token.italic { @@ -940,7 +630,7 @@ body { font-weight: 700; } .token.important { - color: #c94922; + color: #c43931; } .token.entity { cursor: help; @@ -953,23 +643,11 @@ code .token { left: auto; } -/* App name link styles */ -.app-name-link { - display: inline-block; - color: #f4fefe; - font-size: 1.5rem; - font-weight: 700; - text-decoration: none; - padding: 0 20px; - line-height: 1.5; -} - -/* Search styles */ +/* ── Search ── */ .search { - background-color: #101010; - border-bottom-width: 0px !important; + background-color: #0e0a08; + border-bottom: none !important; } - .search .input-wrap { position: relative; display: flex; @@ -978,22 +656,21 @@ code .token { .search .input-wrap input[type="search"] { width: 100%; padding: 8px 40px 8px 12px; - border: 1px solid #444; - border-radius: 4px; + border: 1px solid #3a2e24; + border-radius: 2px; font-size: 14px; outline: none; transition: border-color 0.3s; box-sizing: border-box; - background-color: #1f1f1f; - color: #f4fefe; + background-color: #241c16; + color: #e8ddd0; } .search .input-wrap input[type="search"]::placeholder { - color: #888; + color: #6a5a4a; } .search .input-wrap input[type="search"]:focus { - border-color: #ff5722; - border-color: var(--theme-color, #ff5722); - box-shadow: 0 0 0 3px #ff572212; + border-color: #d4a84b; + box-shadow: 0 0 0 3px rgba(212, 168, 75, 0.15); } .search .input-wrap .clear-button { position: absolute; @@ -1006,25 +683,235 @@ code .token { justify-content: center; opacity: 0.4; transition: opacity 0.3s; - color: #666; + color: #6a5a4a; } .search .input-wrap .clear-button:hover { opacity: 0.7; } .search .results-panel { margin-top: 8px; - border: 1px solid #444; - border-radius: 4px; - background: #2a2a2a; + border: 1px solid #3a2e24; + border-radius: 2px; + background: #241c16; max-height: 300px; overflow-y: auto; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); - color: #f4fefe; + color: #e8ddd0; +} + +.app-name-link { + display: inline-block; + color: #d4a84b; + font-size: 1.5rem; + font-weight: 700; + text-decoration: none; + padding: 0 20px; + line-height: 1.5; } .markdown-section iframe { border: none; - border-radius: 16px; + border-radius: 2px; + display: block; + margin: 1em auto; + width: 1px; + min-width: 100%; +} + +/* ── Body close states ── */ +body.close .sidebar { + transform: translateX(-300px); +} +body.close .sidebar-toggle { + width: auto; +} +body.close .content { + left: 0; +} + +/* ── Print ── */ +@media print { + .github-corner, + .sidebar-toggle, + .sidebar, + .app-nav { + display: none; + } +} + +/* ── Mobile ── */ +@media screen and (max-width: 768px) { + .github-corner, + .sidebar-toggle, + .sidebar { + position: fixed; + } + .app-nav { + margin-top: 16px; + } + .app-nav li ul { + top: 30px; + } + main { + height: auto; + min-height: 100vh; + overflow-x: hidden; + } + .sidebar { + left: -300px; + transition: transform 250ms ease-out; + } + .content { + left: 0; + max-width: 100vw; + position: static; + padding-top: 20px; + transition: transform 250ms ease; + } + .app-nav, + .github-corner { + transition: transform 250ms ease-out; + } + .sidebar-toggle { + background-color: transparent; + width: auto; + padding: 30px 30px 10px 10px; + } + body.close .sidebar { + transform: translateX(300px); + } + body.close .sidebar-toggle { + background-color: rgba(14, 10, 8, 0.9); + transition: 1s background-color; + width: 284px; + padding: 10px; + } + body.close .content { + transform: translateX(300px); + } + body.close .app-nav, + body.close .github-corner { + display: none; + } + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } +} +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +section.cover { + position: relative; + align-items: center; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + min-height: 100vh; + width: 100%; + display: none; +} +section.cover.show { + display: flex; +} +section.cover.has-mask .mask { + background-color: #1a1410; + opacity: 0.85; + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} +section.cover .cover-main { + flex: 1; + margin: 0 16px; + text-align: center; + position: relative; +} +section.cover a { + color: inherit; + text-decoration: none; +} +section.cover a:hover { + text-decoration: none; +} +section.cover p { + line-height: 1.5rem; + margin: 1em 0; + color: #9a8a7a; +} +section.cover h1 { + color: #e8ddd0; + font-size: 2.5rem; + font-weight: 300; + margin: 0.625rem 0 2.5rem; + position: relative; + text-align: center; +} +section.cover h1 a { display: block; +} +section.cover h1 small { + bottom: -0.4375rem; + font-size: 1rem; + position: absolute; + color: #9a8a7a; +} +section.cover blockquote { + font-size: 1.5rem; + text-align: center; + color: #e8ddd0; +} +section.cover ul { + line-height: 1.8; + list-style-type: none; margin: 1em auto; + max-width: 500px; + padding: 0; +} +section.cover .cover-main > p:last-child a { + border-color: #d4a84b; + border-radius: 2px; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + color: #d4a84b; + display: inline-block; + font-size: 1.05rem; + letter-spacing: 0.1rem; + margin: 0.5rem 1rem; + padding: 0.75em 2rem; + text-decoration: none; + transition: all 0.15s ease; +} +section.cover .cover-main > p:last-child a:last-child { + background-color: #c43931; + border-color: #c43931; + color: #e8ddd0; +} +section.cover .cover-main > p:last-child a:last-child:hover { + opacity: 0.85; +} +section.cover .cover-main > p:last-child a:hover { + background: rgba(212, 168, 75, 0.08); +} +section.cover blockquote > p > a { + border-bottom: 2px solid #d4a84b; + transition: color 0.3s; +} +section.cover blockquote > p > a:hover { + color: #d4a84b; } diff --git a/docs/css/light.css b/docs/css/light.css index fd04754..17aa40a 100644 --- a/docs/css/light.css +++ b/docs/css/light.css @@ -1,9 +1,8 @@ /* - * Based on vue.css - * Original: https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/themes/vue.css + * Mingling Helpdoc — Light theme (Imperial Edict style) + * Cream parchment / gold & vermilion accents */ -@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600"); * { -webkit-font-smoothing: antialiased; -webkit-overflow-scrolling: touch; @@ -15,9 +14,9 @@ body:not(.ready) { overflow: hidden; } +body:not(.ready) [data-cloak], body:not(.ready) .app-nav, -body:not(.ready) > nav, -body:not(.ready) [data-cloak] { +body:not(.ready) > nav { display: none; } div#app { @@ -26,60 +25,57 @@ div#app { margin: 40vh auto; text-align: center; } -div#app:empty:before { +div#app:empty::before { content: "Loading..."; } img.emoji { height: 1.2em; -} -img.emoji, -span.emoji { vertical-align: middle; } span.emoji { font-family: - Apple Color Emoji, - Segoe UI Emoji, - Segoe UI Symbol, - Noto Color Emoji; + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; font-size: 1.2em; + vertical-align: middle; } + +/* ── Progress bar ── */ .progress { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); + background-color: #b8352d; height: 2px; - left: 0; + left: 0px; position: fixed; - right: 0; - top: 0; + right: 0px; + top: 0px; transition: width 0.2s, opacity 0.4s; - width: 0; + width: 0%; z-index: 999999; } -.search .search-keyword, + +/* ── Search ── */ .search a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #b8943e; } .search .search-keyword { + color: #b8943e; font-style: normal; - font-weight: 700; + font-weight: bold; } -body, -html { + +/* ── Base ── */ +html, +body { height: 100%; } body { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; - color: #34495e; - font-family: - Source Sans Pro, - Helvetica Neue, - Arial, - sans-serif; + background-color: #f5ede0; + color: #3a2a1a; + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; font-size: 15px; letter-spacing: 0; margin: 0; @@ -93,8 +89,8 @@ a[disabled] { opacity: 0.6; } kbd { - border: 1px solid #ccc; - border-radius: 3px; + border: solid 1px #d4c8b8; + border-radius: 2px; display: inline-block; font-size: 12px !important; line-height: 12px; @@ -106,6 +102,8 @@ li input[type="checkbox"] { margin: 0 0.2em 0.25em 0; vertical-align: middle; } + +/* ── Nav bar ── */ .app-nav { margin: 25px 60px 0 0; position: absolute; @@ -123,26 +121,24 @@ li input[type="checkbox"] { margin: 0 1rem; padding: 5px 0; } -.app-nav li, -.app-nav ul { +.app-nav ul, +.app-nav li { display: inline-block; list-style: none; margin: 0; } .app-nav a { - color: inherit; + color: #6a5a4a; font-size: 16px; text-decoration: none; transition: color 0.3s; } -.app-nav a.active, .app-nav a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #b8943e; } .app-nav a.active { - border-bottom: 2px solid #ff5722; - border-bottom: 2px solid var(--theme-color, #ff5722); + border-bottom: 2px solid #b8943e; + color: #b8943e; } .app-nav li { display: inline-block; @@ -152,10 +148,9 @@ li input[type="checkbox"] { cursor: pointer; } .app-nav li ul { - background-color: #fff; - border: 1px solid; - border-color: #ddd #ddd #ccc; - border-radius: 4px; + background-color: #f0e8d8; + border: 1px solid #d4c8b8; + border-radius: 2px; box-sizing: border-box; display: none; max-height: calc(100vh - 61px); @@ -186,6 +181,8 @@ li input[type="checkbox"] { .app-nav li:hover ul { display: block; } + +/* ── GitHub corner ── */ .github-corner { border-bottom: 0; position: fixed; @@ -195,15 +192,16 @@ li input[type="checkbox"] { z-index: 1; } .github-corner:hover .octo-arm { - animation: octocat-wave 0.56s ease-in-out; + animation: octocat-wave 560ms ease-in-out; } .github-corner svg { - color: #fff; - fill: #ff5722; - fill: var(--theme-color, #ff5722); + color: #f5ede0; + fill: #b8943e; height: 80px; width: 80px; } + +/* ── Main ── */ main { display: block; position: relative; @@ -220,20 +218,23 @@ main.hidden { transition: all 0.3s; } .anchor span { - color: #34495e; + color: #3a2a1a; } .anchor:hover { text-decoration: underline; } + +/* ── Sidebar ── */ .sidebar { - border-right: 1px solid rgba(0, 0, 0, 0.07); + background-color: #ede0d0; + border-right: 1px solid rgba(184, 148, 62, 0.15); overflow-y: auto; padding: 40px 0 0; position: absolute; top: 0; bottom: 0; left: 0; - transition: transform 0.25s ease-out; + transition: transform 250ms ease-out; width: 300px; z-index: 20; } @@ -242,6 +243,7 @@ main.hidden { font-size: 1.5rem; font-weight: 300; text-align: center; + color: #3a2a1a; } .sidebar > h1 a { color: inherit; @@ -265,6 +267,7 @@ main.hidden { .sidebar li > p { font-weight: 700; margin: 0; + color: #3a2a1a; } .sidebar ul, .sidebar ul li { @@ -273,10 +276,31 @@ main.hidden { .sidebar ul li a { border-bottom: none; display: block; + color: #6a5a4a; + font-size: 14px; + font-weight: 400; + overflow: hidden; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + transition: color 0.2s; +} +.sidebar ul li a:hover { + color: #b8943e; } .sidebar ul li ul { padding-left: 20px; } +.sidebar ul li.active > a { + border-right: 2px solid #b8352d; + color: #b8943e; + font-weight: 600; + background: linear-gradient( + to left, + rgba(184, 53, 45, 0.12), + transparent 30% + ); +} .sidebar::-webkit-scrollbar { width: 4px; } @@ -285,14 +309,15 @@ main.hidden { border-radius: 4px; } .sidebar:hover::-webkit-scrollbar-thumb { - background: hsla(0, 0%, 53.3%, 0.4); + background: rgba(184, 148, 62, 0.25); } .sidebar:hover::-webkit-scrollbar-track { - background: hsla(0, 0%, 53.3%, 0.1); + background: rgba(184, 148, 62, 0.1); } + +/* ── Sidebar toggle ── */ .sidebar-toggle { background-color: transparent; - background-color: hsla(0, 0%, 100%, 0.8); border: 0; outline: none; padding: 10px; @@ -309,8 +334,7 @@ main.hidden { opacity: 0.4; } .sidebar-toggle span { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); + background-color: #b8943e; display: block; margin-bottom: 4px; width: 16px; @@ -320,6 +344,8 @@ body.sticky .sidebar, body.sticky .sidebar-toggle { position: fixed; } + +/* ── Content ── */ .content { padding-top: 60px; position: absolute; @@ -327,12 +353,14 @@ body.sticky .sidebar-toggle { right: 0; bottom: 0; left: 300px; - transition: left 0.25s ease; + transition: left 250ms ease; } + +/* ── Markdown ── */ .markdown-section { margin: 0 auto; max-width: 80%; - padding: 30px 45px 40px; + padding: 30px 15px 40px 15px; position: relative; } .markdown-section > * { @@ -344,14 +372,9 @@ body.sticky .sidebar-toggle { } .markdown-section hr { border: none; - border-bottom: 1px solid #eee; + border-bottom: 1px solid #d4c8b8; margin: 2em 0; } -.markdown-section iframe { - border: 1px solid #eee; - width: 1px; - min-width: 100%; -} .markdown-section table { border-collapse: collapse; border-spacing: 0; @@ -361,41 +384,97 @@ body.sticky .sidebar-toggle { width: 100%; } .markdown-section th { - font-weight: 700; + border: 1px solid #d4c8b8; + font-weight: bold; + padding: 6px 13px; + color: #3a2a1a; + background-color: #f0e8d8; } -.markdown-section td, -.markdown-section th { - border: 1px solid #ddd; +.markdown-section td { + border: 1px solid #d4c8b8; padding: 6px 13px; } .markdown-section tr { - border-top: 1px solid #ccc; + border-top: 1px solid #d4c8b8; } -.markdown-section p.tip, .markdown-section tr:nth-child(2n) { - background-color: #f8f8f8; + background-color: #e8ddd0; +} +.markdown-section h1, +.markdown-section h2, +.markdown-section h3, +.markdown-section h4, +.markdown-section strong { + color: #3a2a1a; + font-weight: 600; +} +.markdown-section h1 { + font-size: 2rem; + margin: 0 0 1rem; +} +.markdown-section h2 { + font-size: 1.75rem; + margin: 45px 0 0.8rem; +} +.markdown-section h3 { + font-size: 1.5rem; + margin: 40px 0 0.6rem; +} +.markdown-section h4 { + font-size: 1.25rem; + margin: 35px 0 0.5rem; +} +.markdown-section h5 { + font-size: 1rem; +} +.markdown-section h6 { + font-size: 0.9rem; + color: #9a8a7a; +} +.markdown-section a { + color: #b8943e; +} +.markdown-section code { + color: #7a6a2a; + background-color: #f0e8d8; + border-radius: 2px; + padding: 0.15em 0.4em; +} +.markdown-section pre { + background-color: #f0e8d8; + border: 1px solid #d4c8b8; + border-radius: 2px; + padding: 1rem; + overflow-x: auto; +} +.markdown-section pre > code { + background: transparent; + padding: 0; + color: #3a2a1a; +} +.markdown-section blockquote { + border-left: 3px solid #b8352d; + color: #6a5a4a; + margin: 1em 0; + padding: 0.5em 1em; } .markdown-section p.tip { + background-color: #f0e8d8; border-bottom-right-radius: 2px; - border-left: 4px solid #ff4081; + border-left: 4px solid #b8352d; border-top-right-radius: 2px; margin: 2em 0; padding: 12px 24px 12px 30px; position: relative; } .markdown-section p.tip:before { - background-color: #ff4081; + background-color: #b8352d; border-radius: 100%; - color: #fff; + color: #3a2a1a; content: "!"; - font-family: - Dosis, - Source Sans Pro, - Helvetica Neue, - Arial, - sans-serif; + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; font-size: 14px; - font-weight: 700; + font-weight: bold; left: -12px; line-height: 20px; position: absolute; @@ -405,19 +484,241 @@ body.sticky .sidebar-toggle { top: 14px; } .markdown-section p.tip code { - background-color: #efefef; + background-color: #f5ede0; } .markdown-section p.tip em { - color: #34495e; + color: #b8943e; } .markdown-section p.warn { - background: rgba(66, 185, 131, 0.1); + background: rgba(184, 148, 62, 0.08); border-radius: 2px; padding: 1rem; } .markdown-section ul.task-list > li { list-style-type: none; } + +/* ── Flexible alerts (docsify-plugin-flexible-alerts) ── */ +.alert.callout { + border-radius: 2px; +} +.alert.callout.note { + border: 1px solid #00bcd4; + box-shadow: 0 2px 8px rgba(0, 188, 212, 0.2); +} +.alert.callout.tip { + border: 1px solid #4caf50; + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.2); +} +.alert.callout.important { + border: 1px solid #7c4dff; + box-shadow: 0 2px 8px rgba(124, 77, 255, 0.2); +} +.alert.callout.warning { + border: 1px solid #ffc107; + box-shadow: 0 2px 8px rgba(255, 193, 7, 0.2); +} +.alert.callout.attention { + border: 1px solid #f44336; + box-shadow: 0 2px 8px rgba(244, 67, 54, 0.2); +} +.alert.callout.note code { + color: #00c1d9; +} +.alert.callout.tip code { + color: #51af55; +} +.alert.callout.important code { + color: #8152ff; +} +.alert.callout.warning code { + color: #ffc60c; +} +.alert.callout.attention code { + color: #f9483b; +} +.alert.callout.note a { + color: #00c1d9; +} +.alert.callout.tip a { + color: #51af55; +} +.alert.callout.important a { + color: #8152ff; +} +.alert.callout.warning a { + color: #ffc60c; +} +.alert.callout.attention a { + color: #f9483b; +} +.alert.callout code { + background-color: transparent; +} + +/* ── Prism syntax highlighting ── */ +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #9a8a7a; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.number { + color: #b8943e; +} +.token.punctuation { + color: #9a8a7a; +} +.token.property { + color: #8a7a3a; +} +.token.tag { + color: #b8352d; +} +.token.string { + color: #8a7a3a; +} +.token.selector { + color: #5a7aaa; +} +.token.attr-name { + color: #6a5a4a; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.url { + color: #4a8aaa; +} +.token.attr-value, +.token.control, +.token.directive, +.token.unit { + color: #b8943e; +} +.token.function { + color: #b8943e; +} +.token.keyword { + color: #b8352d; +} +.token.atrule, +.token.regex, +.token.statement { + color: #4a8aaa; +} +.token.placeholder, +.token.variable { + color: #5a7aaa; +} +.token.deleted { + text-decoration: line-through; +} +.token.inserted { + border-bottom: 1px dotted #d4c8b8; + text-decoration: none; +} +.token.italic { + font-style: italic; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.important { + color: #b8352d; +} +.token.entity { + cursor: help; +} +code .token { + -moz-osx-font-smoothing: initial; + -webkit-font-smoothing: initial; + min-height: 1.5rem; + position: relative; + left: auto; +} + +/* ── Search ── */ +.search { + background-color: #ede0d0; + border-bottom: none !important; +} +.search .input-wrap { + position: relative; + display: flex; + align-items: center; +} +.search .input-wrap input[type="search"] { + width: 100%; + padding: 8px 40px 8px 12px; + border: 1px solid #d4c8b8; + border-radius: 2px; + font-size: 14px; + outline: none; + transition: border-color 0.3s; + box-sizing: border-box; + background-color: #f0e8d8; + color: #3a2a1a; +} +.search .input-wrap input[type="search"]::placeholder { + color: #9a8a7a; +} +.search .input-wrap input[type="search"]:focus { + border-color: #b8943e; + box-shadow: 0 0 0 3px rgba(184, 148, 62, 0.15); +} +.search .input-wrap .clear-button { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.6; + transition: opacity 0.3s; + color: #9a8a7a; +} +.search .input-wrap .clear-button:hover { + opacity: 1; +} +.search .results-panel { + margin-top: 8px; + border: 1px solid #d4c8b8; + border-radius: 2px; + background: #f0e8d8; + max-height: 300px; + overflow-y: auto; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + color: #3a2a1a; +} + +.app-name-link { + display: inline-block; + color: #b8943e; + font-size: 1.5rem; + font-weight: 700; + text-decoration: none; + padding: 0 20px; + line-height: 1.5; +} + +.markdown-section iframe { + border: none; + border-radius: 2px; + display: block; + margin: 1em auto; + width: 1px; + min-width: 100%; +} + +/* ── Body close states ── */ body.close .sidebar { transform: translateX(-300px); } @@ -427,18 +728,22 @@ body.close .sidebar-toggle { body.close .content { left: 0; } + +/* ── Print ── */ @media print { - .app-nav, .github-corner, + .sidebar-toggle, .sidebar, - .sidebar-toggle { + .app-nav { display: none; } } + +/* ── Mobile ── */ @media screen and (max-width: 768px) { .github-corner, - .sidebar, - .sidebar-toggle { + .sidebar-toggle, + .sidebar { position: fixed; } .app-nav { @@ -454,18 +759,18 @@ body.close .content { } .sidebar { left: -300px; - transition: transform 0.25s ease-out; + transition: transform 250ms ease-out; } .content { left: 0; max-width: 100vw; position: static; padding-top: 20px; - transition: transform 0.25s ease; + transition: transform 250ms ease; } .app-nav, .github-corner { - transition: transform 0.25s ease-out; + transition: transform 250ms ease-out; } .sidebar-toggle { background-color: transparent; @@ -476,8 +781,8 @@ body.close .content { transform: translateX(300px); } body.close .sidebar-toggle { - background-color: hsla(0, 0%, 100%, 0.8); - transition: background-color 1s; + background-color: rgba(14, 10, 8, 0.9); + transition: 1s background-color; width: 284px; padding: 10px; } @@ -492,12 +797,12 @@ body.close .content { animation: none; } .github-corner .octo-arm { - animation: octocat-wave 0.56s ease-in-out; + animation: octocat-wave 560ms ease-in-out; } } @keyframes octocat-wave { 0%, - to { + 100% { transform: rotate(0); } 20%, @@ -512,7 +817,7 @@ body.close .content { section.cover { position: relative; align-items: center; - background-position: 50%; + background-position: center center; background-repeat: no-repeat; background-size: cover; min-height: 100vh; @@ -523,8 +828,8 @@ section.cover.show { display: flex; } section.cover.has-mask .mask { - background-color: #fff; - opacity: 0.8; + background-color: #f5ede0; + opacity: 0.85; position: absolute; top: 0; bottom: 0; @@ -538,17 +843,18 @@ section.cover .cover-main { } section.cover a { color: inherit; + text-decoration: none; } -section.cover a, section.cover a:hover { text-decoration: none; } section.cover p { line-height: 1.5rem; margin: 1em 0; + color: #6a5a4a; } section.cover h1 { - color: inherit; + color: #3a2a1a; font-size: 2.5rem; font-weight: 300; margin: 0.625rem 0 2.5rem; @@ -562,10 +868,12 @@ section.cover h1 small { bottom: -0.4375rem; font-size: 1rem; position: absolute; + color: #6a5a4a; } section.cover blockquote { font-size: 1.5rem; text-align: center; + color: #3a2a1a; } section.cover ul { line-height: 1.8; @@ -575,12 +883,12 @@ section.cover ul { padding: 0; } section.cover .cover-main > p:last-child a { - border-radius: 2rem; - border: 1px solid #ff5722; - border-color: var(--theme-color, #ff5722); + border-color: #b8943e; + border-radius: 2px; + border-style: solid; + border-width: 1px; box-sizing: border-box; - color: #ff5722; - color: var(--theme-color, #ff5722); + color: #b8943e; display: inline-block; font-size: 1.05rem; letter-spacing: 0.1rem; @@ -590,370 +898,20 @@ section.cover .cover-main > p:last-child a { transition: all 0.15s ease; } section.cover .cover-main > p:last-child a:last-child { - background-color: #ff5722; - background-color: var(--theme-color, #ff5722); - color: #fff; + background-color: #b8352d; + border-color: #b8352d; + color: #3a2a1a; } section.cover .cover-main > p:last-child a:last-child:hover { - color: inherit; - opacity: 0.8; + opacity: 0.85; } section.cover .cover-main > p:last-child a:hover { - color: inherit; + background: rgba(184, 148, 62, 0.1); } section.cover blockquote > p > a { - border-bottom: 2px solid #ff5722; - border-bottom: 2px solid var(--theme-color, #ff5722); + border-bottom: 2px solid #b8943e; transition: color 0.3s; } section.cover blockquote > p > a:hover { - color: #ff5722; - color: var(--theme-color, #ff5722); -} -.sidebar, -body { - background-color: #fefefe; -} -.sidebar { - color: #364149; -} -.sidebar li { - margin: 6px 0; -} -.sidebar ul li a { - color: #505d6b; - font-size: 14px; - font-weight: 400; - overflow: hidden; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; -} -.sidebar ul li a:hover { - text-decoration: underline; -} -.sidebar ul li ul { - padding: 0; -} -.sidebar ul li.active > a { - border-right: 2px solid; - color: #ff5722; - color: var(--theme-color, #ff5722); - font-weight: 600; - background: linear-gradient(to left, #ff572255, transparent 30%); - text-shadow: 0 0 8px rgba(255, 87, 34, 0.3); -} -.sidebar ul li > a:hover { - background: linear-gradient( - to left, - rgba(255, 87, 34, 0.05), - transparent 50% - ); -} -.app-sub-sidebar li:before { - content: "-"; - padding-right: 4px; - float: left; -} -.markdown-section h1, -.markdown-section h2, -.markdown-section h3, -.markdown-section h4, -.markdown-section strong { - color: #2c3e50; - font-weight: 600; -} -.markdown-section a { - color: #ff5722; - color: var(--theme-color, #ff5722); - font-weight: 600; -} -.markdown-section h1 { - font-size: 2rem; - margin: 0 0 1rem; -} -.markdown-section h2 { - font-size: 1.75rem; - margin: 45px 0 0.8rem; -} -.markdown-section h3 { - font-size: 1.5rem; - margin: 40px 0 0.6rem; -} -.markdown-section h4 { - font-size: 1.25rem; -} -.markdown-section h5 { - font-size: 1rem; -} -.markdown-section h6 { - color: #777; - font-size: 1rem; -} -.markdown-section figure, -.markdown-section p { - margin: 1.2em 0; -} -.markdown-section ol, -.markdown-section p, -.markdown-section ul { - line-height: 1.6rem; - word-spacing: 0.05rem; -} -.markdown-section ol, -.markdown-section ul { - padding-left: 1.5rem; -} -.markdown-section blockquote { - border-left: 4px solid #ff5722; - border-left: 4px solid var(--theme-color, #ff5722); - color: #858585; - margin: 2em 0; - padding-left: 20px; -} -.markdown-section blockquote p { - font-weight: 600; - margin-left: 0; -} -.markdown-section iframe { - margin: 1em 0; -} -.markdown-section em { - color: #7f8c8d; -} -.markdown-section code, -.markdown-section output:after, -.markdown-section pre { - font-family: - Roboto Mono, - Monaco, - courier, - monospace; -} -.markdown-section code, -.markdown-section pre { - background-color: #f2f2f2; -} -.markdown-section output, -.markdown-section pre { - margin: 1.2em 0; - position: relative; - border-radius: 6px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); -} -.markdown-section output, -.markdown-section pre > code { - border-radius: 2px; - display: block; -} -.markdown-section output:after, -.markdown-section pre > code { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; -} -.markdown-section code { - border-radius: 2px; - color: #f44336; - margin: 0 2px; - padding: 3px 5px; - white-space: pre-wrap; -} -.markdown-section > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code { - font-size: 0.8rem; -} -.markdown-section pre { - padding: 0 1.4rem; - line-height: 1.5rem; - overflow: auto; - word-wrap: normal; -} -.markdown-section pre > code { - color: #525252; - font-size: 0.8rem; - padding: 2.2em 5px; - line-height: inherit; - margin: 0 2px; - max-width: inherit; - overflow: inherit; - white-space: inherit; -} -.markdown-section output { - padding: 1.7rem 1.4rem; - border: 1px dotted #ccc; -} -.markdown-section output > :first-child { - margin-top: 0; -} -.markdown-section output > :last-child { - margin-bottom: 0; -} -.markdown-section code:after, -.markdown-section code:before, -.markdown-section output:after, -.markdown-section output:before { - letter-spacing: 0.05rem; -} -.markdown-section output:after, -.markdown-section pre:after { - color: #ccc; - font-size: 0.6rem; - font-weight: 600; - height: 15px; - line-height: 15px; - padding: 5px 10px 0; - position: absolute; - right: 0; - text-align: right; - top: 0; - content: attr(data-lang); -} -.token.cdata, -.token.comment, -.token.doctype, -.token.prolog { - color: #8e908c; -} -.token.namespace { - opacity: 0.7; -} -.token.boolean, -.token.number { - color: #4caf50; -} -.token.punctuation { - color: #525252; -} -.token.property { - color: #c08b30; -} -.token.tag { - color: #ff5722; -} -.token.string { - color: #4caf50; - color: var(--theme-color, #4caf50); -} -.token.selector { - color: #6679cc; -} -.token.attr-name { - color: #2973b7; -} -.language-css .token.string, -.style .token.string, -.token.entity, -.token.url { - color: #22a2c9; -} -.token.attr-value, -.token.control, -.token.directive, -.token.unit { - color: #ff5722; - color: var(--theme-color, #ff5722); -} -.token.function, -.token.keyword { - color: #f44336; -} -.token.atrule, -.token.regex, -.token.statement { - color: #22a2c9; -} -.token.placeholder, -.token.variable { - color: #3d8fd1; -} -.token.deleted { - text-decoration: line-through; -} -.token.inserted { - border-bottom: 1px dotted #202746; - text-decoration: none; -} -.token.italic { - font-style: italic; -} -.token.bold, -.token.important { - font-weight: 700; -} -.token.important { - color: #c94922; -} -.token.entity { - cursor: help; -} -code .token { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; - min-height: 1.5rem; - position: relative; - left: auto; -} - -/* App name link styles */ -.app-name-link { - display: inline-block; - color: #34495e; - font-size: 1.5rem; - font-weight: 700; - text-decoration: none; - padding: 0 20px; - line-height: 1.5; -} - -/* Search styles */ -.search .input-wrap { - position: relative; - display: flex; - align-items: center; -} -.search .input-wrap input[type="search"] { - width: 100%; - padding: 8px 40px 8px 12px; - border: 1px solid #ccc; - border-radius: 4px; - font-size: 14px; - outline: none; - transition: border-color 0.3s; - box-sizing: border-box; -} -.search .input-wrap input[type="search"]:focus { - border-color: #ff5722; - border-color: var(--theme-color, #ff5722); - box-shadow: 0 0 0 3px #ff572212; -} -.search .input-wrap .clear-button { - position: absolute; - right: 8px; - top: 50%; - transform: translateY(-50%); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - opacity: 0.6; - transition: opacity 0.3s; -} -.search .input-wrap .clear-button:hover { - opacity: 1; -} -.search .results-panel { - margin-top: 8px; - border: 1px solid #e0e0e0; - border-radius: 4px; - background: #fff; - max-height: 300px; - overflow-y: auto; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -.markdown-section iframe { - border: none; - border-radius: 16px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); - display: block; - margin: 1em auto; + color: #b8943e; } diff --git a/docs/index.html b/docs/doc.html index 505f02a..1e78918 100644 --- a/docs/index.html +++ b/docs/doc.html @@ -7,29 +7,25 @@ content="width=device-width, initial-scale=1, minimum-scale=1.0, shrink-to-fit=no, viewport-fit=cover" /> - <title>Mingling Documents</title> + <title>Mingling Helpdoc</title> <meta - name="Mingling Documents" + name="Mingling Helpdoc" content="Quick start with Mingling and build your command-line program!" /> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link - href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&family=Roboto+Mono&family=Dosis:wght@500&display=swap" + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" rel="stylesheet" /> + <link rel="stylesheet" href="css/light.css" /> <link id="dark-style" rel="stylesheet" href="css/dark.css" disabled /> </head> <body> <nav> - <a href="https://crates.io/crates/mingling">Crates.io</a> - <a href="https://docs.rs/mingling/latest/mingling/">API Docs</a> - <a href="https://git.catilgrass.cn/catilgrass/mingling.git" - ><b>Source</b></a - > <a href="#" onclick=" @@ -38,13 +34,13 @@ " >🌗 Theme</a > - <a href="./_zh_CN/"><b>🇨🇳 CN Docs</b></a> + <a href="_zh_CN/index.html"><b>🇨🇳 CN Docs</b></a> </nav> <div id="app"></div> <script> window.$docsify = { - name: "Mingling Document", + name: "Mingling Helpdoc", repo: "true", corner: { url: "https://github.com/catilgrass/mingling", diff --git a/docs/example-pages/examples.json b/docs/example-pages/examples.json new file mode 100644 index 0000000..4db968c --- /dev/null +++ b/docs/example-pages/examples.json @@ -0,0 +1,281 @@ +[ + { + "id": "example-basic", + "name": "Basic", + "icon": "🚀", + "category": "core", + "desc": "Example The Basic Usage of Mingling\n", + "tags": [ + "dispatcher!", + "#[chain]", + "#[renderer]" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-argument-parse", + "name": "Argument Parse", + "icon": "📋", + "category": "parsing", + "desc": "Example Argument Parse\n", + "tags": [ + "pick", + "Pickable" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-async-support", + "name": "Async Support", + "icon": "⚡", + "category": "runtime", + "desc": "Example Async Runtime Support\n", + "tags": [ + "async", + "tokio" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-clap-binding", + "name": "Clap Binding", + "icon": "🔗", + "category": "parsing", + "desc": "Example Clap Binding\n", + "tags": [ + "clap" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-completion", + "name": "Completion", + "icon": "🔄", + "category": "ux", + "desc": "Example Completion\n", + "tags": [ + "comp" + ], + "files": [ + "src/main.rs", + "build.rs", + "Cargo.toml" + ] + }, + { + "id": "example-custom-pickable", + "name": "Custom Pickable", + "icon": "🎯", + "category": "parsing", + "desc": "Example Custom Pickable\n", + "tags": [ + "Pickable", + "custom" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-dispatch-tree", + "name": "Dispatch Tree", + "icon": "🌳", + "category": "dispatch", + "desc": "Example Dispatch Tree\n", + "tags": [ + "dispatch_tree" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-enum-tag", + "name": "Enum Tag", + "icon": "🏷️", + "category": "parsing", + "desc": "Example Enum Tag\n", + "tags": [ + "enum_tag", + "Pickable" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-error-handling", + "name": "Error Handling", + "icon": "⚠️", + "category": "runtime", + "desc": "Example Error Handling\n", + "tags": [ + "Result" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-exitcode", + "name": "Exitcode", + "icon": "🚪", + "category": "runtime", + "desc": "Example Error Handling\n", + "tags": [ + "ExitCode" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-general-renderer", + "name": "General Renderer", + "icon": "📤", + "category": "output", + "desc": "Example General Renderer\n", + "tags": [ + "general_renderer", + "--json", + "--yaml" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-help", + "name": "Help", + "icon": "💡", + "category": "ux", + "desc": "Example Help\n", + "tags": [ + "#[helper]" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-hook", + "name": "Hook", + "icon": "🪝", + "category": "runtime", + "desc": "Example Hook\n", + "tags": [ + "ProgramHook" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-implicit-dispatcher", + "name": "Implicit Dispatcher", + "icon": "🫥", + "category": "dispatch", + "desc": "Example Implicit Dispatcher\n", + "tags": [ + "implicit" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-panic-unwind", + "name": "Panic Unwind", + "icon": "💥", + "category": "runtime", + "desc": "Example Panic Unwind\n", + "tags": [ + "panic_unwind" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-repl-basic", + "name": "REPL Basic", + "icon": "🔁", + "category": "repl", + "desc": "Example REPL Basic\n", + "tags": [ + "repl" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-resources", + "name": "Resources", + "icon": "📦", + "category": "advanced", + "desc": "Example Resource Injection\n", + "tags": [ + "Resources", + "injection" + ], + "files": [ + "Cargo.toml", + "src/main.rs", + "src/lib.rs" + ] + }, + { + "id": "example-setup", + "name": "Setup", + "icon": "🏗️", + "category": "core", + "desc": "Example Setup\n", + "tags": [ + "#[setup]", + "extra_macros" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, + { + "id": "example-unit-test", + "name": "Unit Test", + "icon": "🧪", + "category": "testing", + "desc": "Example Unit Test\n", + "tags": [ + "testing", + "extra_macros" + ], + "files": [ + "Cargo.toml", + "src/main.rs" + ] + } +]
\ No newline at end of file diff --git a/docs/example-viewer.html b/docs/example-viewer.html new file mode 100644 index 0000000..4eedbd9 --- /dev/null +++ b/docs/example-viewer.html @@ -0,0 +1,628 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Example — Mìng Lìng</title> + <link rel="icon" type="image/png" href="res/icon_shadow.png" /> + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" + rel="stylesheet" + /> + <link rel="stylesheet" href="scripts/highlight/github-dark.min.css" /> + <style> + *, + *::before, + *::after { + box-sizing: border-box; + margin: 0; + padding: 0; + } + html { + scroll-behavior: smooth; + } + body { + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; + background-color: #1a1410; + color: #e8ddd0; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; + } + a { + color: #d4a84b; + text-decoration: none; + transition: color 0.2s; + } + a:hover { + color: #e8c46a; + } + + nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.8rem 2rem; + background: rgba(26, 20, 16, 0.88); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid rgba(212, 168, 75, 0.12); + } + nav .logo { + display: flex; + align-items: center; + gap: 0.5rem; + font-weight: 700; + font-size: 1.1rem; + color: #e8ddd0; + } + nav .logo img { + width: 28px; + height: 28px; + filter: brightness(0) invert(1); + } + nav .nav-links { + display: flex; + gap: 1.5rem; + align-items: center; + font-size: 0.9rem; + } + nav .nav-links a { + color: #9a8a7a; + transition: color 0.2s; + } + nav .nav-links a:hover { + color: #d4a84b; + } + + .viewer { + margin-top: 4rem; + padding: 1.5rem; + max-width: 960px; + margin-left: auto; + margin-right: auto; + } + + .viewer-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1.5rem; + flex-wrap: wrap; + gap: 0.75rem; + } + .viewer-header h1 { + font-size: 1.6rem; + font-weight: 700; + color: #e8ddd0; + } + .viewer-header h1 span { + color: #c43931; + } + .viewer-header .gh-link { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.4rem 1rem; + border: 1px solid #d4a84b; + color: #d4a84b; + font-size: 0.85rem; + font-weight: 600; + border-radius: 2px; + transition: all 0.2s; + } + .viewer-header .gh-link:hover { + background: rgba(212, 168, 75, 0.1); + } + .viewer-header .back-link { + color: #9a8a7a; + font-size: 0.9rem; + } + .viewer-header .back-link:hover { + color: #d4a84b; + } + + .file-tabs { + display: flex; + gap: 0.25rem; + margin-bottom: 0; + flex-wrap: wrap; + } + .file-tabs button { + background: #241c16; + border: 1px solid #3a2e24; + border-bottom: none; + color: #9a8a7a; + padding: 0.4rem 1rem; + font-size: 0.82rem; + font-family: "Cascadia Code", "Fira Code", monospace; + cursor: pointer; + transition: all 0.2s; + border-radius: 2px 2px 0 0; + } + .file-tabs button:hover { + color: #e8ddd0; + border-color: #d4a84b; + } + .file-tabs button.active { + background: #1a1410; + color: #d4a84b; + border-color: #3a2e24; + border-bottom: 1px solid #1a1410; + margin-bottom: -1px; + } + + .code-frame { + background: #1a1410; + border: 1px solid #3a2e24; + border-radius: 0 2px 2px 2px; + padding: 0; + overflow: hidden; + } + .code-frame pre { + margin: 0; + padding: 1.25rem; + overflow-x: auto; + font-family: "Cascadia Code", "Fira Code", monospace; + font-size: 0.85rem; + line-height: 1.65; + } + .code-frame pre code.hljs { + background: transparent; + padding: 0; + } + + .doc-box { + background: #241c16; + border: 1px solid #3a2e24; + border-top: none; + padding: 1.25rem 1.5rem; + font-size: 0.92rem; + line-height: 1.7; + color: #c0b0a0; + } + .doc-box h3 { + font-size: 1.15rem; + font-weight: 700; + color: #d4a84b; + margin-bottom: 0.5rem; + } + .doc-box h4 { + font-size: 1rem; + font-weight: 600; + color: #e8ddd0; + margin-top: 0.75rem; + margin-bottom: 0.25rem; + } + .doc-box p { + margin-bottom: 0.5rem; + } + .doc-box p:last-child { + margin-bottom: 0; + } + .doc-box code { + background: rgba(212, 168, 75, 0.1); + color: #e8c46a; + padding: 0.12em 0.4em; + border-radius: 2px; + font-size: 0.85em; + font-family: "Cascadia Code", "Fira Code", monospace; + } + .doc-box strong { + color: #e8ddd0; + } + + .loading { + text-align: center; + padding: 4rem 1rem; + color: #6a5a4a; + font-size: 1rem; + } + .error { + text-align: center; + padding: 4rem 1rem; + color: #c43931; + } + + footer { + padding: 2rem 1.5rem; + text-align: center; + color: #6a5a4a; + font-size: 0.85rem; + border-top: 1px solid #2a1e14; + margin-top: 3rem; + } + footer a { + color: #7a6a5a; + } + footer a:hover { + color: #d4a84b; + } + + @media (max-width: 600px) { + .viewer { + padding: 1rem; + } + .viewer-header h1 { + font-size: 1.2rem; + } + } + </style> + </head> + <body> + <nav> + <a href="../index.html" class="logo"> + <img + src="res/icon.png" + alt="Mingling icon" + width="28" + height="28" + /> + Mìng Lìng + </a> + <div class="nav-links"> + <a href="doc.html">Docs</a> + <a href="examples.html">Examples</a> + <a href="https://github.com/catilgrass/mingling" target="_blank" + >GitHub</a + > + </div> + </nav> + + <div class="viewer"> + <div class="viewer-header"> + <div> + <a href="examples.html" class="back-link" + >← Back to Examples</a + > + <h1> + <span>✦</span> <span id="exampleName">Loading...</span> + </h1> + </div> + <a id="githubLink" href="#" target="_blank" class="gh-link" + >View on GitHub ↗</a + > + </div> + + <div class="file-tabs" id="fileTabs"></div> + <div class="doc-box" id="docBox" style="display: none"></div> + <div class="code-frame" id="codeFrame"> + <div class="loading" id="loadingMsg"> + Loading source code... + </div> + <pre + style="display: none" + id="codePre" + ><code id="codeContent"></code></pre> + </div> + </div> + + <footer> + <p> + Built With ❤️ by + <a href="https://github.com/Weicao-CatilGrass" target="_blank" + >Weicao-CatilGrass</a + > + · Licensed under + <a href="LICENSE-MIT" target="_blank">MIT</a> / + <a href="LICENSE-APACHE" target="_blank">Apache-2.0</a> + </p> + </footer> + + <script src="scripts/highlight/highlight.min.js"></script> + <script src="scripts/highlight/rust.min.js"></script> + <script src="scripts/highlight/bash.min.js"></script> + <script> + (function () { + var params = new URLSearchParams(window.location.search); + var exampleName = params.get("name") || ""; + if (!exampleName) { + document.getElementById("exampleName").textContent = + "No example specified"; + return; + } + + document.getElementById("exampleName").textContent = + exampleName.replace(/^example-/, ""); + document.getElementById("githubLink").href = + "https://github.com/catilgrass/mingling/tree/main/examples/" + + exampleName; + + // ── Load file list from auto-generated JSON ── + fetch("example-pages/examples.json") + .then(function (r) { + if (!r.ok) throw new Error("HTTP " + r.status); + return r.json(); + }) + .then(function (data) { + var matched = null; + for (var i = 0; i < data.length; i++) { + if (data[i].id === exampleName) { + matched = data[i]; + break; + } + } + var files = matched + ? matched.files + : ["Cargo.toml", "src/main.rs"]; + initViewer(files); + }) + .catch(function () { + // Fallback + initViewer(["Cargo.toml", "src/main.rs"]); + }); + + function renderMarkdown(md) { + var html = ""; + var lines = md.split("\n"); + var i = 0; + + while (i < lines.length) { + var line = lines[i]; + + // Fenced code block + var codeMatch = line.match(/^```(\w*)/); + if (codeMatch) { + var lang = codeMatch[1]; + var codeLines = []; + i++; + while ( + i < lines.length && + !lines[i].startsWith("```") + ) { + codeLines.push(lines[i]); + i++; + } + i++; // skip closing ``` + var codeText = escapeHtml(codeLines.join("\n")); + html += + '<pre style="background:#1a1410;border:1px solid #3a2e24;border-radius:2px;padding:0.75rem;margin:0.5rem 0;overflow-x:auto;font-size:0.8rem;line-height:1.5"><code>' + + codeText + + "</code></pre>"; + continue; + } + + // Headings + var hMatch = line.match(/^(#{1,4})\s+(.+)/); + if (hMatch) { + var level = hMatch[1].length; + var tag = level <= 2 ? "h3" : "h4"; + html += + "<" + + tag + + ">" + + inlineMd(hMatch[2]) + + "</" + + tag + + ">"; + i++; + continue; + } + + // Blockquote + if (line.startsWith("> ")) { + var quoteLines = []; + while ( + i < lines.length && + lines[i].startsWith("> ") + ) { + quoteLines.push(lines[i].slice(2)); + i++; + } + html += + '<blockquote style="border-left:3px solid #c43931;padding:0.25em 1em;margin:0.5em 0;color:#9a8a7a">' + + inlineMd(quoteLines.join("<br>")) + + "</blockquote>"; + continue; + } + + // Unordered list + var ulMatch = line.match(/^[-*]\s+(.+)/); + if (ulMatch) { + var items = []; + while ( + i < lines.length && + lines[i].match(/^[-*]\s+(.+)/) + ) { + items.push( + inlineMd(lines[i].match(/^[-*]\s+(.+)/)[1]), + ); + i++; + } + html += + '<ul style="margin:0.25em 0;padding-left:1.5em">' + + items + .map(function (x) { + return "<li>" + x + "</li>"; + }) + .join("") + + "</ul>"; + continue; + } + + // Empty line + if (line.trim() === "") { + i++; + continue; + } + + // Paragraph + var paraLines = []; + while ( + i < lines.length && + lines[i].trim() !== "" && + !lines[i].match(/^#{1,4}\s/) && + !lines[i].startsWith("> ") && + !lines[i].startsWith("```") && + !lines[i].match(/^[-*]\s/) + ) { + paraLines.push(lines[i]); + i++; + } + if (paraLines.length > 0) { + html += + "<p>" + + inlineMd(paraLines.join("<br>")) + + "</p>"; + } + } + + return html; + + function inlineMd(text) { + return text + .replace(/`([^`]+)`/g, "<code>$1</code>") + .replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>") + .replace(/\*(.+?)\*/g, "<em>$1</em>"); + } + + function escapeHtml(t) { + return t + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); + } + } + + function initViewer(files) { + var tabsEl = document.getElementById("fileTabs"); + var codePre = document.getElementById("codePre"); + var codeContent = document.getElementById("codeContent"); + var loadingMsg = document.getElementById("loadingMsg"); + + function loadFile(filePath) { + loadingMsg.style.display = "block"; + codePre.style.display = "none"; + + var url = "../examples/" + exampleName + "/" + filePath; + + fetch(url) + .then(function (r) { + if (!r.ok) throw new Error("HTTP " + r.status); + return r.text(); + }) + .then(function (code) { + loadingMsg.style.display = "none"; + + // ── Extract //! doc block from .rs files ── + var docHtml = ""; + var cleanCode = code; + var ext = filePath.split(".").pop(); + + if (ext === "rs") { + var lines = code.split("\n"); + var docLines = []; + var codeStart = 0; + var inDoc = true; + + for (var i = 0; i < lines.length; i++) { + var trimmed = lines[i]; + var docMatch = + trimmed.match( + /^\s*\/\/!( ?(.*))?$/, + ); + + if (inDoc && docMatch) { + docLines.push(docMatch[2] || ""); + codeStart = i + 1; + } else if ( + inDoc && + trimmed.trim() === "" + ) { + docLines.push(""); + codeStart = i + 1; + } else { + inDoc = false; + } + } + + // Render doc lines to HTML + if (docLines.length > 0) { + docHtml = renderMarkdown( + docLines.join("\n"), + ); + } + + // Remove leading //! lines for code display + cleanCode = lines + .slice(codeStart) + .join("\n") + .trimStart(); + } + + // Show/hide doc box + var docBox = document.getElementById("docBox"); + if (docHtml) { + docBox.innerHTML = docHtml; + docBox.style.display = "block"; + } else { + docBox.style.display = "none"; + } + + codePre.style.display = "block"; + codeContent.textContent = cleanCode; + + // Set language class + codeContent.className = ""; + var lang = + { + rs: "language-rust", + toml: "language-toml", + md: "language-markdown", + js: "language-javascript", + sh: "language-bash", + ps1: "language-powershell", + }[ext] || ""; + if (lang) codeContent.className = lang; + + delete codeContent.dataset.highlighted; + hljs.highlightElement(codeContent); + + tabsEl + .querySelectorAll("button") + .forEach(function (b) { + b.classList.toggle( + "active", + b.dataset.file === filePath, + ); + }); + }) + .catch(function (err) { + loadingMsg.style.display = "block"; + loadingMsg.textContent = + "Failed to load: " + + filePath + + " (" + + err.message + + ")"; + loadingMsg.className = "error"; + }); + } + + // Build tabs + files.forEach(function (f, i) { + var btn = document.createElement("button"); + btn.textContent = f; + btn.dataset.file = f; + if (i === 0) btn.className = "active"; + btn.addEventListener("click", function () { + loadFile(f); + }); + tabsEl.appendChild(btn); + }); + + // Load first file + if (files.length > 0) loadFile(files[0]); + } + })(); + </script> + </body> +</html> diff --git a/docs/examples.html b/docs/examples.html new file mode 100644 index 0000000..47513f2 --- /dev/null +++ b/docs/examples.html @@ -0,0 +1,488 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Examples — Mìng Lìng</title> + <link rel="icon" type="image/png" href="res/icon_shadow.png" /> + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" + rel="stylesheet" + /> + <link rel="stylesheet" href="scripts/highlight/github-dark.min.css" /> + <style> + *, + *::before, + *::after { + box-sizing: border-box; + margin: 0; + padding: 0; + } + + html { + scroll-behavior: smooth; + } + + body { + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; + background-color: #1a1410; + color: #e8ddd0; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; + } + + a { + color: #d4a84b; + text-decoration: none; + transition: color 0.2s; + } + a:hover { + color: #e8c46a; + } + + img { + max-width: 100%; + height: auto; + } + + .container { + max-width: 1100px; + margin: 0 auto; + padding: 0 1.5rem; + } + + /* ── Nav ── */ + nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.8rem 2rem; + background: rgba(26, 20, 16, 0.88); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid rgba(212, 168, 75, 0.12); + } + + nav .logo { + display: flex; + align-items: center; + gap: 0.5rem; + font-weight: 700; + font-size: 1.1rem; + color: #e8ddd0; + } + nav .logo img { + width: 28px; + height: 28px; + filter: brightness(0) invert(1); + } + + nav .nav-links { + display: flex; + gap: 1.5rem; + align-items: center; + font-size: 0.9rem; + } + nav .nav-links a { + color: #9a8a7a; + transition: color 0.2s; + } + nav .nav-links a:hover { + color: #d4a84b; + } + nav .nav-links .active { + color: #d4a84b; + font-weight: 600; + } + nav .nav-links .btn-nav { + display: inline-block; + padding: 0.35rem 1rem; + border: 1px solid #d4a84b; + border-radius: 2px; + color: #d4a84b; + font-weight: 600; + font-size: 0.85rem; + transition: + background 0.2s, + color 0.2s; + } + nav .nav-links .btn-nav:hover { + background: #d4a84b; + color: #1a1410; + } + + /* ── Hero ── */ + .hero { + padding: 8rem 1.5rem 3rem; + text-align: center; + position: relative; + } + .hero h1 { + font-size: 3rem; + font-weight: 800; + letter-spacing: 1px; + color: #e8ddd0; + margin-bottom: 0.75rem; + } + .hero h1 span { + color: #c43931; + } + .hero p { + color: #9a8a7a; + font-size: 1.05rem; + max-width: 600px; + margin: 0 auto; + } + + /* ── Filter bar ── */ + .filter-bar { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + justify-content: center; + margin-bottom: 2.5rem; + } + .filter-bar button { + background: transparent; + border: 1px solid #3a2e24; + color: #9a8a7a; + padding: 0.35rem 1rem; + border-radius: 2px; + font-size: 0.85rem; + cursor: pointer; + font-family: inherit; + transition: all 0.2s; + } + .filter-bar button:hover { + border-color: #d4a84b; + color: #d4a84b; + } + .filter-bar button.active { + background: #d4a84b; + color: #1a1410; + border-color: #d4a84b; + font-weight: 600; + } + + /* ── Card grid ── */ + .examples-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.25rem; + padding-bottom: 4rem; + } + + .example-card { + background: #241c16; + border: 1px solid #3a2e24; + border-radius: 2px; + padding: 1.5rem; + display: flex; + flex-direction: column; + transition: + border-color 0.25s, + transform 0.2s; + cursor: pointer; + } + .example-card:hover { + border-color: #d4a84b; + transform: translateY(-3px); + } + + .example-card .icon { + font-size: 1.6rem; + margin-bottom: 0.6rem; + display: block; + } + .example-card h3 { + font-size: 1.1rem; + font-weight: 700; + color: #e8ddd0; + margin-bottom: 0.4rem; + } + .example-card .desc { + font-size: 0.88rem; + color: #9a8a7a; + line-height: 1.6; + flex: 1; + margin-bottom: 0.75rem; + } + + .example-card .tags { + display: flex; + gap: 0.4rem; + flex-wrap: wrap; + margin-bottom: 1rem; + } + .example-card .tags span { + font-size: 0.72rem; + padding: 0.15rem 0.5rem; + background: rgba(212, 168, 75, 0.1); + color: #d4a84b; + border-radius: 2px; + font-family: "Cascadia Code", "Fira Code", monospace; + } + + .example-card .card-actions { + display: flex; + gap: 0.6rem; + align-items: center; + margin-top: auto; + } + .example-card .card-actions a { + font-size: 0.82rem; + font-weight: 600; + padding: 0.3rem 0.8rem; + border-radius: 2px; + transition: all 0.2s; + } + .example-card .card-actions .view-code { + background: #c43931; + color: #e8ddd0; + border: none; + } + .example-card .card-actions .view-code:hover { + background: #d44a42; + } + .example-card .card-actions .github-link { + background: transparent; + color: #d4a84b; + border: 1px solid #d4a84b; + margin-left: auto; + } + .example-card .card-actions .github-link:hover { + background: rgba(212, 168, 75, 0.1); + } + + /* ── Footer ── */ + footer { + padding: 2rem 1.5rem; + text-align: center; + color: #6a5a4a; + font-size: 0.85rem; + border-top: 1px solid #2a1e14; + } + footer a { + color: #7a6a5a; + } + footer a:hover { + color: #d4a84b; + } + + /* ── Responsive ── */ + @media (max-width: 900px) { + .examples-grid { + grid-template-columns: repeat(2, 1fr); + } + .hero h1 { + font-size: 2.2rem; + } + } + + @media (max-width: 550px) { + .examples-grid { + grid-template-columns: 1fr; + } + nav { + padding: 0.6rem 1rem; + } + nav .nav-links { + gap: 0.8rem; + font-size: 0.8rem; + } + } + </style> + </head> + <body> + <!-- ── Nav ── --> + <nav> + <a href="../index.html" class="logo" aria-label="Home"> + <img + src="res/icon.png" + alt="Mingling icon" + width="28" + height="28" + /> + Mìng Lìng + </a> + <div class="nav-links"> + <a href="doc.html">Docs</a> + <a href="examples.html" class="active">Examples</a> + <a href="https://github.com/catilgrass/mingling" target="_blank" + >GitHub</a + > + <a + href="https://crates.io/crates/mingling" + target="_blank" + class="btn-nav" + >cargo add mingling</a + > + </div> + </nav> + + <!-- ── Hero ── --> + <section class="hero"> + <div class="container"> + <h1><span>✦</span> Examples</h1> + <p> + Real projects built with Mingling — from basic to advanced. + Click any card to explore its source code. + </p> + </div> + </section> + + <!-- ── Grid ── --> + <section class="container"> + <div class="filter-bar" id="filterBar"></div> + <div class="examples-grid" id="examplesGrid"></div> + </section> + + <!-- ── Footer ── --> + <footer> + <p> + Built With ❤️ by + <a href="https://github.com/Weicao-CatilGrass" target="_blank" + >Weicao-CatilGrass</a + > + · Licensed under + <a href="LICENSE-MIT" target="_blank">MIT</a> / + <a href="LICENSE-APACHE" target="_blank">Apache-2.0</a> + </p> + </footer> + + <script> + // ── Load examples from auto-generated JSON ── + var examples = []; + + fetch("example-pages/examples.json") + .then(function (r) { + if (!r.ok) throw new Error("HTTP " + r.status); + return r.json(); + }) + .then(function (data) { + examples = data; + buildFilters(); + renderGrid(""); + }) + .catch(function (err) { + document.getElementById("examplesGrid").innerHTML = + '<p style="text-align:center;color:#c43931;padding:3rem">Failed to load examples: ' + + err.message + + "<br><small>Run <code>cargo run --bin sync-examples</code> in dev_tools to generate.</small></p>"; + }); + + // ═══════════════════════════════════════════════════════════════ + // RENDERING + // ═══════════════════════════════════════════════════════════════ + + function buildFilters() { + var allTags = {}; + examples.forEach(function (ex) { + if (ex.category) allTags[ex.category] = true; + }); + allTags = Object.keys(allTags); + + var filterBar = document.getElementById("filterBar"); + filterBar.innerHTML = ""; + var allBtn = document.createElement("button"); + allBtn.textContent = "All"; + allBtn.className = "active"; + allBtn.dataset.tag = ""; + filterBar.appendChild(allBtn); + + allTags.forEach(function (tag) { + var btn = document.createElement("button"); + btn.textContent = + tag.charAt(0).toUpperCase() + tag.slice(1); + btn.dataset.tag = tag; + filterBar.appendChild(btn); + }); + + filterBar.addEventListener("click", function (e) { + if (e.target.tagName !== "BUTTON") return; + filterBar.querySelectorAll("button").forEach(function (b) { + b.classList.remove("active"); + }); + e.target.classList.add("active"); + renderGrid(e.target.dataset.tag); + }); + } + + function renderGrid(filter) { + var grid = document.getElementById("examplesGrid"); + grid.innerHTML = ""; + var filtered = filter + ? examples.filter(function (ex) { + return ex.category === filter; + }) + : examples; + + filtered.forEach(function (ex) { + var card = document.createElement("div"); + card.className = "example-card"; + + var ghBase = + "https://github.com/catilgrass/mingling/tree/main/examples/" + + ex.id; + var viewUrl = + "example-viewer.html?name=" + encodeURIComponent(ex.id); + + var tagsHtml = ex.tags + .map(function (t) { + return "<span>" + escapeHtml(t) + "</span>"; + }) + .join(""); + + card.innerHTML = + '<span class="icon">' + + ex.icon + + "</span>" + + "<h3>" + + escapeHtml(ex.name) + + "</h3>" + + '<p class="desc">' + + escapeHtml(ex.desc).replace( + /`([^`]+)`/g, + "<code>$1</code>", + ) + + "</p>" + + '<div class="tags">' + + tagsHtml + + "</div>" + + '<div class="card-actions">' + + '<a href="' + + viewUrl + + '" class="view-code">View Code</a>' + + '<a href="' + + ghBase + + '" target="_blank" class="github-link">GitHub ↗</a>' + + "</div>"; + + card.addEventListener("click", function (e) { + if (e.target.tagName === "A") return; + window.location.href = viewUrl; + }); + + grid.appendChild(card); + }); + } + + function escapeHtml(text) { + return text + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """); + } + </script> + </body> +</html> diff --git a/docs/play/play.html b/docs/play/play.html index 8620908..7a00142 100644 --- a/docs/play/play.html +++ b/docs/play/play.html @@ -24,7 +24,11 @@ <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link - href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" + rel="stylesheet" + /> + <link + href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="style.css" /> diff --git a/docs/play/player.js b/docs/play/player.js index 6e01ce5..691957c 100644 --- a/docs/play/player.js +++ b/docs/play/player.js @@ -111,7 +111,7 @@ function renderSpeech(paragraphs) { .replace(/`([^`]+)`/g, "<code>$1</code>") .replace( /\*\*([^*]+)\*\*/g, - '<strong style="color:#7dcfff">$1</strong>', + '<strong style="color:#d4a84b">$1</strong>', ); return `<p>${html}</p>`; }) @@ -219,6 +219,11 @@ const layoutEl = document.getElementById("layout"); const speechPanel = document.querySelector(".speech-panel"); const codePanel = document.querySelector(".code-panel"); layoutEl.append(speechPanel, codePanel); -layoutEl.classList.add("layout--tb"); +// layoutEl.classList.add("layout--tb"); + +// On narrow screens, switch to vertical +if (window.innerWidth < 800) { + layoutEl.classList.add("layout--tb"); +} loadTutorial(tutorialFile); diff --git a/docs/play/style.css b/docs/play/style.css index 5e51114..70bb7cb 100644 --- a/docs/play/style.css +++ b/docs/play/style.css @@ -7,62 +7,62 @@ } :root { - --bg-primary: #1a1b1c; - --bg-secondary: #1f2021; - --border: #2f3031; - --text-primary: #c0c1c2; - --text-secondary: #7a7b7c; - --text-muted: #565758; - --code-bg: #292a2b; - --code-text: #bbbcbd; - --bubble-bg: #e64a199f; - --bubble-text: #ffccbc; - --line-num: #3b3c3d; - --btn-bg: #2f3031; - --btn-text: #c0c1c2; - --btn-hover: #3b3c3d; - --btn-primary-bg: #7a7b7c; - --btn-primary-text: #1a1b1c; - --btn-primary-hover: #898a8b; - --progress-bg: #2f3031; - --progress-fill: #7a7b7c; - --cmd-bg: #1a1b1c; - --cmd-border: #2f3031; - --cmd-text: #9e9fa0; - --topbar-bg: #1f2021; - --hljs-bg: #1a1b1c; + --bg-primary: #1a1410; + --bg-secondary: #241c16; + --border: #3a2e24; + --text-primary: #e8ddd0; + --text-secondary: #9a8a7a; + --text-muted: #6a5a4a; + --code-bg: #241c16; + --code-text: #e8ddd0; + --bubble-bg: rgba(196, 57, 49, 0.85); + --bubble-text: #e8ddd0; + --line-num: #6a5a4a; + --btn-bg: #3a2e24; + --btn-text: #e8ddd0; + --btn-hover: #4a3e34; + --btn-primary-bg: #c43931; + --btn-primary-text: #e8ddd0; + --btn-primary-hover: #d44a42; + --progress-bg: #3a2e24; + --progress-fill: #d4a84b; + --cmd-bg: #1a1410; + --cmd-border: #3a2e24; + --cmd-text: #9a8a7a; + --topbar-bg: #241c16; + --hljs-bg: #1a1410; } [data-theme="light"] { - --bg-primary: #ffffff; - --bg-secondary: #f5f6f7; - --border: #dcddde; - --text-primary: #2c2d2e; - --text-secondary: #5a5b5c; - --text-muted: #8a8b8c; - --code-bg: #e8e9ea; - --code-text: #2c2d2e; - --bubble-bg: #e64a19cf; - --bubble-text: #ffffff; - --line-num: #b0b1b2; - --btn-bg: #dcddde; - --btn-text: #2c2d2e; - --btn-hover: #c8c9ca; - --btn-primary-bg: #3a7bd5; - --btn-primary-text: #ffffff; - --btn-primary-hover: #2a6bc5; - --progress-bg: #dcddde; - --progress-fill: #3a7bd5; - --cmd-bg: #f5f6f7; - --cmd-border: #dcddde; - --cmd-text: #5a5b5c; - --topbar-bg: #f5f6f7; - --hljs-bg: #f5f6f7; + --bg-primary: #f5ede0; + --bg-secondary: #ede0d0; + --border: #d4c8b8; + --text-primary: #3a2a1a; + --text-secondary: #6a5a4a; + --text-muted: #9a8a7a; + --code-bg: #f0e8d8; + --code-text: #3a2a1a; + --bubble-bg: rgba(184, 53, 45, 0.85); + --bubble-text: #f5ede0; + --line-num: #c0b0a0; + --btn-bg: #d4c8b8; + --btn-text: #3a2a1a; + --btn-hover: #c4b8a8; + --btn-primary-bg: #b8352d; + --btn-primary-text: #f5ede0; + --btn-primary-hover: #c8453d; + --progress-bg: #d4c8b8; + --progress-fill: #b8943e; + --cmd-bg: #f0e8d8; + --cmd-border: #d4c8b8; + --cmd-text: #6a5a4a; + --topbar-bg: #ede0d0; + --hljs-bg: #f0e8d8; } body { font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", + -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Serif SC", Roboto, sans-serif; background: var(--bg-primary); color: var(--text-primary); @@ -71,7 +71,7 @@ body { flex-direction: column; } -/* Top bar */ +/* ── Top bar ── */ .topbar { padding: 12px 24px; background: var(--topbar-bg); @@ -101,7 +101,7 @@ body { cursor: pointer; font-size: 16px; padding: 4px 10px; - border-radius: 6px; + border-radius: 2px; transition: all 0.15s; font-family: inherit; line-height: 1; @@ -111,14 +111,14 @@ body { background: var(--btn-hover); } -/* Main panel */ +/* ── Main panel ── */ .layout { display: flex; flex: 1; overflow: hidden; } -/* Left: code panel */ +/* ── Left: code panel ── */ .code-panel { flex: 1; background: var(--bg-primary); @@ -159,7 +159,7 @@ body { color: var(--bubble-text); border-radius: 10px; font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", + -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Serif SC", Roboto, sans-serif; font-size: 13px; font-style: normal; @@ -191,9 +191,9 @@ body { user-select: none; } -/* Right: description panel */ +/* ── Right: description panel ── */ .speech-panel { - width: 380px; + flex: 0 0 320px; background: var(--bg-secondary); border-left: 1px solid var(--border); display: flex; @@ -209,8 +209,8 @@ body { width: 100%; border-left: none; border-bottom: 1px solid var(--border); - max-height: none; flex: 0 0 auto; + max-height: 40%; } .layout--tb .code-panel { @@ -218,6 +218,20 @@ body { min-height: 0; } +.layout--tb .speech-content { + padding: 16px 20px; +} + +.layout--tb .speech-content p { + font-size: 14px; + line-height: 1.6; + margin-bottom: 10px; +} + +.layout--tb .code-panel pre { + padding: 16px 20px; +} + .speech-content { flex: 1; padding: 32px 24px; @@ -239,7 +253,7 @@ body { background: var(--code-bg); color: var(--code-text); padding: 2px 6px; - border-radius: 4px; + border-radius: 2px; font-size: 13px; } @@ -247,7 +261,7 @@ body { display: block; background: var(--cmd-bg); border: 1px solid var(--cmd-border); - border-radius: 6px; + border-radius: 2px; padding: 10px 14px; margin: 12px 0; font-family: "JetBrains Mono", monospace; @@ -255,7 +269,7 @@ body { color: var(--cmd-text); } -/* Control panel */ +/* ── Control panel ── */ .controls { padding: 12px 24px; background: var(--bg-secondary); @@ -271,7 +285,7 @@ body { border: none; color: var(--btn-text); padding: 8px 20px; - border-radius: 6px; + border-radius: 2px; font-size: 14px; cursor: pointer; transition: all 0.15s; diff --git a/examples/example-argument-parse/page.toml b/examples/example-argument-parse/page.toml new file mode 100644 index 0000000..1a85621 --- /dev/null +++ b/examples/example-argument-parse/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-argument-parse" +name = "Argument Parse" +icon = "📋" +category = "parsing" +desc = """ +Example Argument Parse +""" +tags = ["pick", "Pickable"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-async-support/page.toml b/examples/example-async-support/page.toml new file mode 100644 index 0000000..a54ff04 --- /dev/null +++ b/examples/example-async-support/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-async-support" +name = "Async Support" +icon = "⚡" +category = "runtime" +desc = """ +Example Async Runtime Support +""" +tags = ["async", "tokio"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-basic/page.toml b/examples/example-basic/page.toml new file mode 100644 index 0000000..a9e1a15 --- /dev/null +++ b/examples/example-basic/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-basic" +name = "Basic" +icon = "🚀" +category = "core" +desc = """ +Example The Basic Usage of Mingling +""" +tags = ["dispatcher!", "#[chain]", "#[renderer]"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-clap-binding/page.toml b/examples/example-clap-binding/page.toml new file mode 100644 index 0000000..bd8a9eb --- /dev/null +++ b/examples/example-clap-binding/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-clap-binding" +name = "Clap Binding" +icon = "🔗" +category = "parsing" +desc = """ +Example Clap Binding +""" +tags = ["clap"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-completion/page.toml b/examples/example-completion/page.toml new file mode 100644 index 0000000..029cfb5 --- /dev/null +++ b/examples/example-completion/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-completion" +name = "Completion" +icon = "🔄" +category = "ux" +desc = """ +Example Completion +""" +tags = ["comp"] +files = ["src/main.rs", "build.rs", "Cargo.toml"] diff --git a/examples/example-custom-pickable/page.toml b/examples/example-custom-pickable/page.toml new file mode 100644 index 0000000..9b6cd05 --- /dev/null +++ b/examples/example-custom-pickable/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-custom-pickable" +name = "Custom Pickable" +icon = "🎯" +category = "parsing" +desc = """ +Example Custom Pickable +""" +tags = ["Pickable", "custom"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-dispatch-tree/page.toml b/examples/example-dispatch-tree/page.toml new file mode 100644 index 0000000..220ea16 --- /dev/null +++ b/examples/example-dispatch-tree/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-dispatch-tree" +name = "Dispatch Tree" +icon = "🌳" +category = "dispatch" +desc = """ +Example Dispatch Tree +""" +tags = ["dispatch_tree"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-enum-tag/page.toml b/examples/example-enum-tag/page.toml new file mode 100644 index 0000000..01eb9b0 --- /dev/null +++ b/examples/example-enum-tag/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-enum-tag" +name = "Enum Tag" +icon = "🏷️" +category = "parsing" +desc = """ +Example Enum Tag +""" +tags = ["enum_tag", "Pickable"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-error-handling/page.toml b/examples/example-error-handling/page.toml new file mode 100644 index 0000000..7c07928 --- /dev/null +++ b/examples/example-error-handling/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-error-handling" +name = "Error Handling" +icon = "⚠️" +category = "runtime" +desc = """ +Example Error Handling +""" +tags = ["Result"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-exitcode/page.toml b/examples/example-exitcode/page.toml new file mode 100644 index 0000000..f0be05c --- /dev/null +++ b/examples/example-exitcode/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-exitcode" +name = "Exitcode" +icon = "🚪" +category = "runtime" +desc = """ +Example Error Handling +""" +tags = ["ExitCode"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-general-renderer/page.toml b/examples/example-general-renderer/page.toml new file mode 100644 index 0000000..c07b26a --- /dev/null +++ b/examples/example-general-renderer/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-general-renderer" +name = "General Renderer" +icon = "📤" +category = "output" +desc = """ +Example General Renderer +""" +tags = ["general_renderer", "--json", "--yaml"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-help/page.toml b/examples/example-help/page.toml new file mode 100644 index 0000000..38e3632 --- /dev/null +++ b/examples/example-help/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-help" +name = "Help" +icon = "💡" +category = "ux" +desc = """ +Example Help +""" +tags = ["#[helper]"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-hook/page.toml b/examples/example-hook/page.toml new file mode 100644 index 0000000..beca75a --- /dev/null +++ b/examples/example-hook/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-hook" +name = "Hook" +icon = "🪝" +category = "runtime" +desc = """ +Example Hook +""" +tags = ["ProgramHook"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-implicit-dispatcher/page.toml b/examples/example-implicit-dispatcher/page.toml new file mode 100644 index 0000000..2812b79 --- /dev/null +++ b/examples/example-implicit-dispatcher/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-implicit-dispatcher" +name = "Implicit Dispatcher" +icon = "🫥" +category = "dispatch" +desc = """ +Example Implicit Dispatcher +""" +tags = ["implicit"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-panic-unwind/page.toml b/examples/example-panic-unwind/page.toml new file mode 100644 index 0000000..8b9a7cd --- /dev/null +++ b/examples/example-panic-unwind/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-panic-unwind" +name = "Panic Unwind" +icon = "💥" +category = "runtime" +desc = """ +Example Panic Unwind +""" +tags = ["panic_unwind"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-repl-basic/page.toml b/examples/example-repl-basic/page.toml new file mode 100644 index 0000000..83d92c0 --- /dev/null +++ b/examples/example-repl-basic/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-repl-basic" +name = "REPL Basic" +icon = "🔁" +category = "repl" +desc = """ +Example REPL Basic +""" +tags = ["repl"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-resources/page.toml b/examples/example-resources/page.toml new file mode 100644 index 0000000..0121f8a --- /dev/null +++ b/examples/example-resources/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-resources" +name = "Resources" +icon = "📦" +category = "advanced" +desc = """ +Example Resource Injection +""" +tags = ["Resources", "injection"] +files = ["Cargo.toml", "src/main.rs", "src/lib.rs"] diff --git a/examples/example-setup/page.toml b/examples/example-setup/page.toml new file mode 100644 index 0000000..c12443e --- /dev/null +++ b/examples/example-setup/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-setup" +name = "Setup" +icon = "🏗️" +category = "core" +desc = """ +Example Setup +""" +tags = ["#[setup]", "extra_macros"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-unit-test/page.toml b/examples/example-unit-test/page.toml new file mode 100644 index 0000000..7356cc2 --- /dev/null +++ b/examples/example-unit-test/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-unit-test" +name = "Unit Test" +icon = "🧪" +category = "testing" +desc = """ +Example Unit Test +""" +tags = ["testing", "extra_macros"] +files = ["Cargo.toml", "src/main.rs"] diff --git a/index.html b/index.html new file mode 100644 index 0000000..da42f99 --- /dev/null +++ b/index.html @@ -0,0 +1,921 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mìng Lìng — Macro magician in your CLI</title> + <link rel="icon" type="image/png" href="docs/res/icon_shadow.png" /> + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" + rel="stylesheet" + /> + <link + rel="stylesheet" + href="docs/scripts/highlight/github-dark.min.css" + /> + <style> + *, + *::before, + *::after { + box-sizing: border-box; + margin: 0; + padding: 0; + } + + html { + scroll-behavior: smooth; + } + + body { + font-family: "Noto Serif SC", Georgia, "Times New Roman", serif; + background-color: #1a1410; + color: #e8ddd0; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; + } + + a { + color: #d4a84b; + text-decoration: none; + transition: color 0.2s; + } + a:hover { + color: #e8c46a; + } + + img { + max-width: 100%; + height: auto; + } + + .container { + max-width: 1080px; + margin: 0 auto; + padding: 0 1.5rem; + } + + .section-title { + font-size: 1.75rem; + font-weight: 700; + text-align: center; + margin-bottom: 3rem; + color: #e8ddd0; + } + + .section-title span { + color: #d4a84b; + } + + nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.8rem 2rem; + background: rgba(26, 20, 16, 0.88); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid rgba(212, 168, 75, 0.12); + } + + nav .logo { + display: flex; + align-items: center; + gap: 0.5rem; + font-weight: 700; + font-size: 1.1rem; + color: #e8ddd0; + } + + nav .logo img { + width: 28px; + height: 28px; + filter: brightness(0) invert(1); + } + + nav .nav-links { + display: flex; + gap: 1.5rem; + align-items: center; + font-size: 0.9rem; + } + + nav .nav-links a { + color: #9a8a7a; + transition: color 0.2s; + } + + nav .nav-links a:hover { + color: #d4a84b; + } + + nav .nav-links .btn-nav { + display: inline-block; + padding: 0.35rem 1rem; + border: 1px solid #d4a84b; + border-radius: 20px; + color: #d4a84b; + font-weight: 600; + font-size: 0.85rem; + transition: + background 0.2s, + color 0.2s; + } + + nav .nav-links .btn-nav:hover { + background: #d4a84b; + color: #1a1410; + } + + .hero { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 6rem 1.5rem 4rem; + position: relative; + overflow: hidden; + } + + /* subtle glow behind the title — now a warm golden halo */ + .hero::before { + content: ""; + position: absolute; + top: 20%; + left: 50%; + width: 600px; + height: 600px; + transform: translate(-50%, -50%); + background: radial-gradient( + circle, + rgba(212, 168, 75, 0.07) 0%, + transparent 70% + ); + pointer-events: none; + } + + .hero-content { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 1.5rem; + max-width: 820px; + position: relative; + z-index: 1; + } + + .hero h1 { + font-size: 5rem; + font-weight: 800; + letter-spacing: 2px; + color: #e8ddd0; + opacity: 0; + animation: fadeInDown 0.8s ease 0.2s forwards; + line-height: 1.2; + } + + .hero .slogan { + font-size: 2.2rem; + color: #c43931; + font-weight: 400; + opacity: 0; + animation: fadeInDown 0.8s ease 0.3s forwards; + min-height: 3rem; + } + + .hero .slogan .cursor { + display: inline-block; + width: 2px; + height: 1.2em; + background: #c43931; + margin-left: 2px; + vertical-align: text-bottom; + animation: blink 0.8s step-end infinite; + } + + @keyframes blink { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0; + } + } + + .hero .desc { + font-size: 1rem; + color: #9a8a7a; + max-width: 560px; + line-height: 1.6; + opacity: 0; + animation: fadeInDown 0.8s ease 0.4s forwards; + } + + .hero .cta-row { + display: flex; + gap: 1rem; + flex-wrap: wrap; + justify-content: center; + margin-top: 1rem; + opacity: 0; + animation: fadeInDown 0.8s ease 0.6s forwards; + } + + .btn-primary { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.75rem 2rem; + background: #c43931; + color: #e8ddd0; + font-weight: 700; + font-size: 1rem; + border-radius: 2px; + border: none; + cursor: pointer; + transition: + background 0.25s, + transform 0.15s; + } + .btn-primary:hover { + background: #d44a42; + color: #e8ddd0; + transform: translateY(-2px); + } + + .btn-secondary { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.75rem 2rem; + background: transparent; + color: #d4a84b; + font-weight: 600; + font-size: 1rem; + border-radius: 2px; + border: 1px solid #d4a84b; + cursor: pointer; + transition: + background 0.25s, + color 0.25s, + transform 0.15s; + } + .btn-secondary:hover { + background: rgba(212, 168, 75, 0.1); + color: #e8c46a; + transform: translateY(-2px); + } + + @keyframes fadeInDown { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } + + .scroll-indicator { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + display: flex; + flex-direction: column; + align-items: center; + gap: 0.3rem; + color: #6a5a4a; + font-size: 0.75rem; + opacity: 0; + animation: fadeInUp 0.8s ease 1s forwards; + } + + @keyframes watermarkIn { + 0% { + opacity: 0; + top: 30%; + } + 100% { + opacity: 0.3; + top: 15%; + } + } + + @keyframes fadeInUp { + 0% { + opacity: 0; + bottom: 0; + } + 100% { + opacity: 1; + bottom: 2rem; + } + } + + .scroll-indicator .arrow { + width: 20px; + height: 20px; + border-right: 2px solid #6a5a4a; + border-bottom: 2px solid #6a5a4a; + transform: rotate(45deg); + animation: bounceArrow 2s ease-in-out infinite; + } + + @keyframes bounceArrow { + 0%, + 100% { + transform: rotate(45deg) translateY(0); + } + 50% { + transform: rotate(45deg) translateY(6px); + } + } + + .code-demo { + padding: 5rem 1.5rem; + background: #241c16; + } + + .code-demo .code-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3rem; + align-items: center; + } + + .code-demo .code-text h2 { + font-size: 1.75rem; + font-weight: 700; + color: #e8ddd0; + margin-bottom: 1rem; + } + + .code-demo .code-text h2 span { + color: #c43931; + } + + .code-demo .code-text p { + color: #9a8a7a; + font-size: 1rem; + margin-bottom: 1.5rem; + } + + .code-demo .code-text .features-list { + list-style: none; + display: flex; + flex-direction: column; + gap: 0.6rem; + } + + .code-demo .code-text .features-list li { + display: flex; + align-items: flex-start; + gap: 0.6rem; + color: #c0b0a0; + font-size: 0.95rem; + } + + .code-demo .code-text .features-list li::before { + content: "▸"; + color: #d4a84b; + font-weight: 700; + flex-shrink: 0; + } + + .code-block { + background: #241c16; + border: 1px solid #3a2e24; + border-radius: 2px; + padding: 2rem 1.5rem 1.5rem; + overflow-x: auto; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + position: relative; + } + + .code-block pre { + margin: 0; + padding: 0; + background: transparent; + } + + .code-block code { + font-family: + "Cascadia Code", "Fira Code", "JetBrains Mono", "Consolas", + monospace; + font-size: 0.85rem; + line-height: 1.65; + background: transparent !important; + padding: 0 !important; + } + + .code-block::before { + content: "▲ example-basic"; + position: absolute; + top: 0.5rem; + right: 1rem; + font-size: 0.7rem; + color: #6a5a4a; + font-family: "Segoe UI", sans-serif; + letter-spacing: 0.5px; + } + + .features { + padding: 5rem 1.5rem; + } + + .features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1.5rem; + } + + .feature-card { + background: #241c16; + border: 1px solid #3a2e24; + border-radius: 2px; + padding: 1.75rem 1.5rem; + transition: + border-color 0.25s, + transform 0.2s; + } + + .feature-card:hover { + border-color: #c43931; + transform: translateY(-4px); + } + + .feature-card .icon { + font-size: 1.6rem; + margin-bottom: 0.75rem; + display: block; + } + + .feature-card h3 { + font-size: 1.1rem; + font-weight: 700; + color: #e8ddd0; + margin-bottom: 0.5rem; + } + + .feature-card p { + font-size: 0.9rem; + color: #9a8a7a; + line-height: 1.6; + } + + .feature-card a { + font-size: 0.85rem; + font-weight: 600; + } + + .cta-banner { + padding: 4rem 1.5rem; + text-align: center; + background: linear-gradient( + 135deg, + rgba(212, 168, 75, 0.06), + transparent + ); + border-top: 1px solid rgba(212, 168, 75, 0.1); + border-bottom: 1px solid rgba(212, 168, 75, 0.1); + } + + .cta-banner h2 { + font-size: 1.75rem; + font-weight: 700; + color: #e8ddd0; + margin-bottom: 0.75rem; + } + + .cta-banner p { + color: #9a8a7a; + margin-bottom: 1.5rem; + font-size: 1.05rem; + } + + .cta-banner .cta-row { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; + } + + .cta-banner code { + display: inline-block; + background: #241c16; + padding: 0.4rem 1rem; + border-radius: 8px; + font-size: 0.95rem; + color: #d4a84b; + border: 1px solid #3a2e24; + margin-top: 0.5rem; + } + + footer { + padding: 2rem 1.5rem; + text-align: center; + color: #6a5a4a; + font-size: 0.85rem; + border-top: 1px solid #2a1e14; + } + + footer a { + color: #7a6a5a; + } + + footer a:hover { + color: #d4a84b; + } + + /* ── Ink drop effect ── */ + .ink-drop { + position: fixed; + pointer-events: none; + border-radius: 50%; + background: radial-gradient( + circle, + rgba(212, 168, 75, 0.15) 0%, + rgba(196, 57, 49, 0.06) 50%, + transparent 100% + ); + width: 0; + height: 0; + transform: translate(-50%, -50%); + animation: inkSpread 0.9s ease-out forwards; + z-index: 9999; + } + + @keyframes inkSpread { + 0% { + width: 0; + height: 0; + opacity: 1; + } + 100% { + width: 500px; + height: 500px; + opacity: 0; + } + } + + @media (max-width: 768px) { + nav { + padding: 0.6rem 1rem; + } + + nav .nav-links { + gap: 1rem; + font-size: 0.8rem; + } + + nav .nav-links .btn-nav { + padding: 0.25rem 0.75rem; + font-size: 0.75rem; + } + + .hero h1 { + font-size: 2.2rem; + } + + .hero .slogan { + font-size: 1.4rem; + } + + .hero .desc { + font-size: 0.9rem; + } + + .code-demo .code-grid { + grid-template-columns: 1fr; + gap: 2rem; + } + + .code-block { + font-size: 0.75rem; + padding: 1rem; + } + } + + @media (max-width: 480px) { + .hero h1 { + font-size: 1.8rem; + } + + .hero .cta-row { + flex-direction: column; + align-items: center; + } + + .features-grid { + grid-template-columns: 1fr; + } + } + </style> + </head> + <body> + <!-- Navigation --> + <nav> + <a href="#" class="logo" aria-label="Home"> + <img + src="docs/res/icon.png" + alt="Mingling icon" + width="28" + height="28" + /> + Mìng Lìng + </a> + <div class="nav-links"> + <a href="docs/doc.html">Docs</a> + <a href="docs/examples.html">Examples</a> + <a href="https://github.com/catilgrass/mingling" target="_blank" + >GitHub</a + > + <a + href="https://crates.io/crates/mingling" + target="_blank" + class="btn-nav" + >cargo add mingling</a + > + </div> + </nav> + + <!-- Hero --> + <section class="hero"> + <div class="hero-content"> + <img + src="docs/res/icon.png" + alt="" + style=" + position: absolute; + top: 30%; + left: 50%; + transform: translate(-50%, -50%); + width: 600px; + aspect-ratio: 1 / 1; + height: auto; + opacity: 0; + pointer-events: none; + user-select: none; + z-index: -1; + animation: watermarkIn 2.5s ease-out 2s forwards; + " + /> + + <h1>#[Mìng Lìng]</h1> + <p class="slogan" id="typewriter"></p> + + <p class="desc">A <b>proc-macro based</b> Rust CLI framework</p> + + <div class="cta-row"> + <a href="docs/doc.html" class="btn-primary"> + 📖 Read The Docs + </a> + <a + href="https://github.com/catilgrass/mingling" + target="_blank" + class="btn-secondary" + > + GitHub → + </a> + </div> + </div> + + <div class="scroll-indicator"> + <span>scroll</span> + <div class="arrow"></div> + </div> + </section> + + <!-- Code Demo --> + <section class="code-demo"> + <div class="container code-grid"> + <div class="code-text"> + <h2> + Dispatch, Parse<br /> + Then <span>Render</span> + </h2> + <p> + A proc-macro & type-system CLI framework for + building complex command-line programs with many + subcommands. + </p> + <ul class="features-list"> + <li> + Separation of concerns: parsing, logic, rendering + </li> + <li> + Compile-time prefix-tree routing + <a + href="docs/example-viewer.html?name=example-dispatch-tree" + >(optional)</a + > + </li> + <li> + Dynamic shell completion out of the box + <a + href="docs/example-viewer.html?name=example-completion" + >(optional)</a + > + </li> + </ul> + </div> + + <div class="code-block"> + <pre><code class="language-rust"> +use mingling::prelude::*; + +dispatcher!("greet", CMDGreet => EntryGreet); + +fn main() { + let mut program = ThisProgram::new(); + program.with_dispatcher(CMDGreet); + program.exec_and_exit(); +} + +pack!(ResultGreeting = String); + +#[chain] +fn handle_greet(args: EntryGreet) -> Next { + let name = + args.pick_or((), "World").unpack(); + ResultGreeting::new(name) +} + +#[renderer] +fn render_greeting(greeting: ResultGreeting) { + r_println!("Hello, {}!", *greeting); +} + +gen_program!(); + </code></pre> + </div> + </div> + </section> + + <!-- Features --> + <section class="features"> + <div class="container"> + <h2 class="section-title"> + <span>Mìng Lìng</span> — Build Complex CLIs, For You! + </h2> + + <div class="features-grid"> + <div class="feature-card"> + <span class="icon">🧩</span> + <h3>Separation of Concerns</h3> + <p> + Decouple parsing, business logic, rendering, help + text, and completion — each is just a function with + the right attribute macro. + </p> + </div> + + <div class="feature-card"> + <span class="icon">⚡</span> + <h3>Blazing Dispatch</h3> + <p> + With the <code>dispatch_tree</code> feature, your + subcommand structure is hardened into a prefix tree + at compile time. O(len) lookup. + </p> + </div> + + <div class="feature-card"> + <span class="icon">🔄</span> + <h3>Dynamic Completion</h3> + <p> + Enable <code>comp</code> and get smart, + context-aware shell completions for bash, zsh, fish, + and pwsh — no manual registration. + </p> + </div> + + <div class="feature-card"> + <span class="icon">📦</span> + <h3>Lightweight & Modular</h3> + <p> + Minimal core dependencies. Pull in advanced features + (REPL, structured output, Clap binding) only when + you need them via feature flags. + </p> + </div> + + <div class="feature-card"> + <span class="icon">📤</span> + <h3>Structured Output</h3> + <p> + Add <code>general_renderer</code> and your program + gains <code>--json</code> / + <code>--yaml</code> flags automatically. Great for + scripting and pipe workflows. + </p> + </div> + + <div class="feature-card"> + <span class="icon">🔁</span> + <h3>REPL Mode</h3> + <p> + Call <code>program.exec_repl()</code> and your CLI + becomes an interactive shell — perfect for debugging + and exploration. + </p> + </div> + </div> + </div> + </section> + + <!-- CTA Banner --> + <section class="cta-banner"> + <h2>Ready to command your CLI?</h2> + <p> + Add Mingling to your project in one line, or dive straight into + the docs. + </p> + <code>cargo add mingling</code> + <div class="cta-row" style="margin-top: 1.5rem"> + <a href="docs/doc.html" class="btn-primary"> + 📖 Read The Docs + </a> + <a + href="https://github.com/catilgrass/mingling" + target="_blank" + class="btn-secondary" + > + GitHub → + </a> + </div> + </section> + + <!-- Footer --> + <script src="docs/scripts/highlight/highlight.min.js"></script> + <script src="docs/scripts/highlight/rust.min.js"></script> + <script> + hljs.highlightAll(); + </script> + + <script> + (function () { + var text = '"Macro magician in your CLI."'; + var el = document.getElementById("typewriter"); + var i = 0; + var timer = null; + + function type() { + if (i < text.length) { + el.innerHTML = + text.substring(0, i + 1) + + '<span class="cursor"></span>'; + i++; + var delay = + text[i - 1] === "." || text[i - 1] === "," + ? 200 + : 55; + timer = setTimeout(type, delay); + } else { + el.innerHTML = text + '<span class="cursor"></span>'; + } + } + + // Start typing after page settles + setTimeout(type, 2000); + })(); + </script> + + <script> + document.addEventListener("click", function (e) { + var drop = document.createElement("div"); + drop.className = "ink-drop"; + drop.style.left = e.clientX + "px"; + drop.style.top = e.clientY + "px"; + document.body.appendChild(drop); + setTimeout(function () { + drop.remove(); + }, 1000); + }); + </script> + + <footer> + <p> + Built With ❤️ by + <a href="https://github.com/Weicao-CatilGrass" target="_blank" + >Weicao-CatilGrass</a + > + · Licensed under + <a href="LICENSE-MIT" target="_blank">MIT</a> / + <a href="LICENSE-APACHE" target="_blank">Apache-2.0</a> + </p> + </footer> + </body> +</html> diff --git a/mingling_core/src/comp.rs b/mingling_core/src/comp.rs index 4f3890a..1769a5c 100644 --- a/mingling_core/src/comp.rs +++ b/mingling_core/src/comp.rs @@ -155,7 +155,7 @@ where let cmd_nodes: Vec<String> = this::<P>() .get_nodes() .into_iter() - .filter(|(s, _)| s != "__comp") + .filter(|(s, _)| !s.starts_with('_')) .map(|(s, _)| s) .collect(); debug!("cmd_nodes: {:?}", cmd_nodes); diff --git a/mingling_core/src/program/config.rs b/mingling_core/src/program/config.rs index 5c104ab..42603a5 100644 --- a/mingling_core/src/program/config.rs +++ b/mingling_core/src/program/config.rs @@ -10,6 +10,33 @@ pub struct ProgramStdoutSetting { /// Silence panic messages pub silence_panic: bool, + /// Verbose output: provide detailed information + /// + /// **NOTE**: Convention only, not a configuration + pub verbose: bool, + + /// Quiet mode: suppress status messages, show only errors and results + /// + /// **NOTE**: Convention only, not a configuration + pub quiet: bool, + + /// Debug mode: output internal state and detailed diagnostics + /// + /// **NOTE**: Convention only, not a configuration + pub debug: bool, + + /// Enable colored output + /// + /// **NOTE**: Convention only, not a configuration + pub color: bool, + + /// Show progress indicators (e.g. progress bars, spinners) + /// + /// Automatically disabled when stdout is not a tty. + /// + /// **NOTE**: Convention only, not a configuration + pub progress: bool, + #[cfg(feature = "clap")] /// Behavior when Clap Dispatcher outputs help information pub clap_help_print_behaviour: ClapHelpPrintBehaviour, @@ -32,6 +59,11 @@ impl Default for ProgramStdoutSetting { error_output: true, render_output: true, silence_panic: false, + verbose: false, + quiet: false, + debug: false, + color: true, + progress: true, #[cfg(feature = "clap")] clap_help_print_behaviour: ClapHelpPrintBehaviour::default(), } @@ -44,19 +76,45 @@ pub struct ProgramUserContext { /// View help information instead of running the command pub help: bool, + /// Execute hooks during the program lifecycle + pub run_hook: bool, + /// Skip user confirmation step + /// + /// **NOTE**: Convention only, not a configuration pub confirm: bool, - /// Execute hooks during the program lifecycle - pub run_hook: bool, + /// Dry-run mode: simulate actions without making changes + /// + /// **NOTE**: Convention only, not a configuration + pub dry_run: bool, + + /// Force execution, skipping safety checks + /// + /// **NOTE**: Convention only, not a configuration + pub force: bool, + + /// Whether the program is running in an interactive terminal (has a tty) + /// + /// **NOTE**: Convention only, not a configuration + pub interactive: bool, + + /// Assume "yes" for all confirmation prompts + /// + /// **NOTE**: Convention only, not a configuration + pub assume_yes: bool, } impl Default for ProgramUserContext { fn default() -> Self { Self { help: false, - confirm: false, run_hook: true, + confirm: false, + dry_run: false, + force: false, + interactive: false, + assume_yes: false, } } } diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index d7ee8e8..033c5a3 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -71,7 +71,7 @@ where /// /// **Note:** When the `async` feature is enabled, panic unwinding is not supported. /// Any panics during command execution will result in an abort rather than being caught and handled gracefully. - pub async fn exec_repl(self) { + pub async fn exec_repl(mut self) { // Inject default REPL resource self.with_resource(REPL::default()); |
