From 26fcb28c740a6a117b3dbb7e26846a9987eacf6b Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 16 Aug 2026 07:38:47 +0800 Subject: feat: redesign landing page with scroll snap and interactive elements Implement a modern scroll-snapping layout with dashed golden grid lines, terminal emulator block, code carousel, and cursor glow effect. Restructure code demo grids for better visual hierarchy and add line highlighting animations. --- index.html | 1186 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 1039 insertions(+), 147 deletions(-) (limited to 'index.html') diff --git a/index.html b/index.html index 2f6aa4f..dd43c3c 100644 --- a/index.html +++ b/index.html @@ -26,6 +26,15 @@ html { scroll-behavior: smooth; + scroll-snap-type: y mandatory; + } + + .hero, + .code-demo, + .code-demo-mirror { + scroll-snap-align: start; + scroll-snap-stop: always; + min-height: 100vh; } body { @@ -38,6 +47,69 @@ overflow-x: hidden; } + /* Dashed lines along the container (1080px) edges, excluding hero */ + body > section:not(.hero) { + position: relative; + } + + body > section:not(.hero)::before, + body > section:not(.hero)::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + width: 1px; + background: repeating-linear-gradient( + to bottom, + rgba(212, 168, 75, 0.25) 0, + rgba(212, 168, 75, 0.25) 4px, + transparent 4px, + transparent 9px + ); + pointer-events: none; + z-index: 49; + } + + body > section:not(.hero)::before { + left: max(0px, calc(50% - 540px)); + } + + body > section:not(.hero)::after { + right: max(0px, calc(50% - 540px)); + } + + /* Diamond markers at line intersections */ + .line-diamond { + position: absolute; + top: -4px; + width: 8px; + height: 8px; + background: rgba(212, 168, 75, 0.25); + transform: rotate(45deg); + pointer-events: none; + z-index: 50; + } + + .line-diamond.left { + left: calc(max(0px, calc(50% - 540px)) - 4px); + } + + .line-diamond.right { + right: calc(max(0px, calc(50% - 540px)) - 4px); + } + + /* Horizontal dashed dividers between pages (border-image, same style as vertical lines) */ + body > section + section, + body > footer { + border-top: 1px solid rgba(212, 168, 75, 0.25); + border-image: repeating-linear-gradient( + to right, + rgba(212, 168, 75, 0.25) 0 4px, + transparent 4px 9px + ) + 1; + } + a { color: #d4a84b; text-decoration: none; @@ -55,7 +127,7 @@ .container { max-width: 1080px; margin: 0 auto; - padding: 0 1.5rem; + position: relative; } .section-title { @@ -149,7 +221,7 @@ .hero::before { content: ""; position: absolute; - top: 20%; + top: 26%; left: 50%; width: 600px; height: 600px; @@ -162,6 +234,41 @@ pointer-events: none; } + /* Tiled grid background (field grid) */ + .hero::after { + content: ""; + position: absolute; + inset: 0; + background-image: + linear-gradient( + to right, + rgba(212, 168, 75, 0.03) 1px, + transparent 1px + ), + linear-gradient( + to bottom, + rgba(212, 168, 75, 0.03) 1px, + transparent 1px + ), + linear-gradient( + to right, + rgba(212, 168, 75, 0.015) 1px, + transparent 1px + ), + linear-gradient( + to bottom, + rgba(212, 168, 75, 0.015) 1px, + transparent 1px + ); + background-size: + 40px 40px, + 40px 40px, + 20px 20px, + 20px 20px; + pointer-events: none; + z-index: 0; + } + .hero-content { display: flex; flex-direction: column; @@ -171,6 +278,7 @@ max-width: 820px; position: relative; z-index: 1; + margin-top: 3rem; } .hero h1 { @@ -305,11 +413,11 @@ @keyframes watermarkIn { 0% { opacity: 0; - top: 30%; + top: 36%; } 100% { opacity: 0.3; - top: 15%; + top: 21%; } } @@ -346,13 +454,46 @@ .code-demo { padding: 5rem 1.5rem; background: #241c16; + display: flex; + align-items: center; + justify-content: center; } .code-demo .code-grid { display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; - align-items: center; + grid-template-columns: 60fr 40fr; + grid-template-rows: 6fr 4fr; + gap: 2rem; + align-items: stretch; + } + + .code-demo .code-grid > .code-block { + grid-row: span 2; + } + + .code-demo-mirror { + background-color: #1a1410; + padding-top: calc(5rem + 1.75rem); + } + + .code-demo-mirror .code-grid { + grid-template-columns: 38fr 62fr; + grid-template-rows: 5fr 5fr; + grid-template-areas: + "text code" + "term code"; + } + + .code-demo-mirror .code-grid > .code-text { + grid-area: text; + } + + .code-demo-mirror .code-grid > .terminal-block { + grid-area: term; + } + + .code-demo-mirror .code-grid > .code-block { + grid-area: code; } .code-demo .code-text h2 { @@ -372,11 +513,26 @@ margin-bottom: 1.5rem; } + .code-demo .code-text .star { + color: #c43931; + margin-right: 0.5rem; + } + + .code-demo .code-text p b { + color: #e8ddd0; + font-weight: 700; + } + + .code-demo .code-text .hl-word { + color: #c43931; + font-weight: 700; + } + .code-demo .code-text .features-list { list-style: none; display: flex; flex-direction: column; - gap: 0.6rem; + gap: 0.25rem; } .code-demo .code-text .features-list li { @@ -394,13 +550,127 @@ flex-shrink: 0; } + .code-demo .example-link { + display: inline-block; + margin-top: 1.5rem; + padding: 0.5rem 1.25rem; + border: 1px solid #d4a84b; + border-radius: 2.5px; + color: #d4a84b; + font-size: 0.9rem; + font-weight: 600; + font-family: "Segoe UI", sans-serif; + transition: + background 0.2s, + color 0.2s; + } + + .code-demo .example-link:hover { + background: #d4a84b; + color: #1a1410; + } + + .terminal-block { + background: #000; + border: 1px solid #3a2e24; + border-radius: 2.5px; + padding: 1rem 1.25rem; + overflow: hidden; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); + position: relative; + } + + .terminal-block pre { + margin: 0; + font-family: "JetBrains Mono", "Noto Serif SC", monospace; + font-size: 1.33rem; + line-height: 1.6; + color: #d0d0d0; + white-space: pre; + position: relative; + } + + .term-cursor { + display: inline-block; + width: 0.6em; + height: 1.15em; + background: #d0d0d0; + vertical-align: text-bottom; + margin-left: 1px; + animation: termBlink 1s steps(1) infinite; + } + + .term-cmd { + color: #7ec699; + } + + .term-arg { + color: #d4a84b; + } + + .term-prompt { + color: #6a5a4a; + } + + .term-out { + color: #d0d0d0; + } + + @keyframes termBlink { + 50% { + opacity: 0; + } + } + + .term-suggest { + position: absolute; + left: 0; + right: 0; + bottom: 0; + background: rgba(212, 168, 75, 0.07); + border-top: 1px solid rgba(212, 168, 75, 0.3); + padding: 0.4rem 1.25rem; + font-family: "JetBrains Mono", "Noto Serif SC", monospace; + font-size: 1.33rem; + line-height: 1.5; + white-space: pre; + display: none; + pointer-events: none; + } + + .term-suggest .sug-cmd { + color: #7ec699; + } + + .term-suggest .sug-arg { + color: #d4a84b; + } + + .term-suggest .sug-desc { + color: #6a5a4a; + font-size: 0.9rem; + } + + .term-suggest .sug-active { + background: rgba(212, 168, 75, 0.18); + border-radius: 2px; + padding: 0 0.35rem; + margin: 0 -0.35rem; + color: #fff; + } + + .term-suggest .sug-active .sug-arg, + .term-suggest .sug-active .sug-cmd { + color: #ffd97a; + } + .code-block { background: #241c16; border: 1px solid #3a2e24; - border-radius: 2px; - padding: 2rem 1.5rem 1.5rem; + border-radius: 2.5px; + padding: 2.5rem 1.875rem 1.875rem; overflow-x: auto; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); position: relative; } @@ -408,26 +678,44 @@ margin: 0; padding: 0; background: transparent; + min-height: 440px; + position: relative; } .code-block code { font-family: "JetBrains Mono", "Noto Serif SC", monospace; font-variant-ligatures: contextual; - font-size: 0.85rem; + font-size: 1.0625rem; line-height: 1.65; background: transparent !important; padding: 0 !important; } + .code-line-highlight { + position: absolute; + left: 0; + right: 0; + height: 28px; + background: rgba(255, 255, 255, 0.1); + border-left: 2px solid rgba(255, 255, 255, 0.45); + pointer-events: none; + opacity: 0; + transition: + opacity 0.15s ease, + top 0.08s ease; + z-index: 3; + } + .code-block::before { - content: "▲ example-basic"; + content: "▲ main.rs"; position: absolute; - top: 0.5rem; - right: 1rem; - font-size: 0.7rem; + top: 0.625rem; + right: 1.25rem; + font-size: 0.875rem; color: #6a5a4a; font-family: "Segoe UI", sans-serif; letter-spacing: 0.5px; + z-index: 2; } .features { @@ -487,8 +775,10 @@ 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); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .cta-banner h2 { @@ -524,12 +814,88 @@ margin-top: 0.5rem; } + .feature-carousel { + position: relative; + max-width: 540px; + margin: 2.5rem auto 0; + display: flex; + align-items: center; + gap: 1rem; + } + + .carousel-viewport { + flex: 1; + overflow: hidden; + } + + .carousel-track { + display: flex; + transition: transform 0.4s ease; + } + + .carousel-track > .carousel-code { + flex: 0 0 100%; + margin: 0; + text-align: left; + background: #0f0b08; + border: 1px solid #3a2e24; + border-radius: 2.5px; + padding: 0; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); + overflow: hidden; + position: relative; + box-sizing: border-box; + aspect-ratio: 16 / 9; + } + + .carousel-track > .carousel-code code { + font-family: "JetBrains Mono", "Noto Serif SC", monospace; + font-size: 0.95rem; + line-height: 1.6; + background: transparent !important; + padding: 1.5rem !important; + margin: 0; + display: block; + border: none; + border-radius: 0; + } + + .carousel-track > .carousel-code .code-line-highlight { + left: 1.5rem; + right: 1.5rem; + } + + .carousel-arrow { + background: transparent; + border: 1px solid rgba(212, 168, 75, 0.4); + color: #d4a84b; + font-size: 1.5rem; + width: 2.4rem; + height: 2.4rem; + border-radius: 50%; + cursor: pointer; + flex-shrink: 0; + line-height: 1; + padding: 0; + transition: + background 0.2s, + color 0.2s; + } + + .carousel-arrow:hover { + background: #d4a84b; + color: #1a1410; + } + footer { padding: 2rem 1.5rem; text-align: center; color: #6a5a4a; font-size: 0.85rem; border-top: 1px solid #2a1e14; + display: flex; + align-items: center; + justify-content: center; } footer a { @@ -558,6 +924,28 @@ z-index: 9999; } + /* ── Cursor glow dot ── */ + .cursor-dot { + position: fixed; + pointer-events: none; + border-radius: 50%; + width: 400px; + height: 400px; + background: radial-gradient( + circle, + rgba(212, 168, 75, 0.06) 0%, + rgba(212, 168, 75, 0.02) 45%, + transparent 70% + ); + transform: translate(-50%, -50%); + z-index: 10000; + opacity: 0; + transition: + opacity 0.3s ease, + left 0.12s ease-out, + top 0.12s ease-out; + } + @keyframes inkSpread { 0% { width: 0; @@ -572,6 +960,16 @@ } @media (max-width: 768px) { + html { + scroll-snap-type: none; + } + + .hero, + .code-demo, + .code-demo-mirror { + min-height: auto; + } + nav { padding: 0.6rem 1rem; } @@ -603,9 +1001,23 @@ gap: 2rem; } + .code-demo .code-grid > .code-block { + grid-row: auto; + } + + .code-demo-mirror .code-grid { + grid-template-columns: 1fr; + grid-template-rows: auto auto auto; + grid-template-areas: + "code" + "text" + "term"; + } + .code-block { font-size: 0.75rem; padding: 1rem; + transform: none; } } @@ -618,10 +1030,6 @@ flex-direction: column; align-items: center; } - - .features-grid { - grid-template-columns: 1fr; - } } @@ -662,7 +1070,7 @@ alt="" style=" position: absolute; - top: 30%; + top: 36%; left: 50%; transform: translate(-50%, -50%); width: 600px; @@ -679,12 +1087,13 @@
A proc-macro based Rust CLI framework
++ A state-driven and data-driven CLI workflow + orchestration framework +
+#[derive(Grouped)]
+pub struct ResultHello(String);
+
+#[command]
+pub fn hello(args: Entry) -> ResultHello {
+ let name = args
+ .pick_or(&arg![String], || "World".into())
+ .unwrap();
+ ResultHello(name)
+}
+
+#[renderer(buffer)]
+pub fn render_hello(hello: ResultHello) {
+ r_println!("Hello, {}", hello.0);
+}
+
+
- A proc-macro & type-system CLI framework for
- building complex command-line programs with many
- subcommands.
+ ✦ Command is just a
+ Function,
+ ✦ Renderer is just a
+ Function,
+ ✦ Mingling wires them
+ together
+ ✦ with no builder boilerplate.
#[command] turns a function into a
+ subcommand
#[renderer] — output, decoupled from
+ logic
pick / pick_or — typed args via
+ arg-picker
~# my-cli hello
+Hello, World!
+~# my-cli hello Mingling
+Hello, Mingling!
+
-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)
+#[command(entry = EntryHello)]
+pub fn hello() { /* ... */ }
+
+#[command]
+pub fn bye() { /* ... */ }
+
+#[completion(EntryHello)]
+pub fn complete_hello(ctx: &ShellContext) -> Suggest {
+ if ctx.previous_word == "hello" {
+ suggest! {
+ "Alice": "The Sender",
+ "Bob": "The Receiver",
+ }
+ } else {
+ suggest! {}
+ }
}
-
-#[renderer]
-fn render_greet(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
-}
-
-gen_program!();
- Decouple parsing, business logic, rendering, help - text, and completion — each is just a function with - the right attribute macro. -
-
- With the dispatch_tree feature, your
- subcommand structure is hardened into a prefix tree
- at compile time. O(len) lookup.
-
- Enable comp and get smart,
- context-aware shell completions for bash, zsh, fish,
- and pwsh — no manual registration.
-
- Minimal core dependencies. Pull in advanced features - (REPL, structured output, Clap binding) only when - you need them via feature flags. -
-
- Add general_renderer and your program
- gains --json /
- --yaml flags automatically. Great for
- scripting and pipe workflows.
-
+ ✦ hello offers Alice
+ & Bob,
+ ✦ bye gets a friendly
+ farewell,
+ ✦ Mingling completes by
+ context —
+ ✦ suggestions born at runtime.
+
- Call program.exec_repl() and your CLI
- becomes an interactive shell — perfect for debugging
- and exploration.
-