5a2b5ab
commit 5a2b5ab
3 files changed
+275 -124
Showing 3 changed files+275-124
▼.github/workflows/publish.yml
+0-36
| @@ -1,36 +0,0 @@ | ||
1 | -name: Publish to crates.io | |
2 | - | |
3 | -on: | |
4 | - push: | |
5 | - tags: | |
6 | - - 'v*' | |
7 | - | |
8 | -jobs: | |
9 | - publish: | |
10 | - name: Publish | |
11 | - runs-on: ubuntu-latest | |
12 | - steps: | |
13 | - - uses: actions/checkout@v4 | |
14 | - | |
15 | - - uses: dtolnay/rust-toolchain@stable | |
16 | - | |
17 | - - name: Verify version matches tag | |
18 | - run: | | |
19 | - tag="${GITHUB_REF##*/}" | |
20 | - version="v$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')" | |
21 | - if [[ "$tag" != "$version" ]]; then | |
22 | - echo "Tag $tag does not match Cargo.toml version $version" | |
23 | - exit 1 | |
24 | - fi | |
25 | - | |
26 | - - name: Run checks before publish | |
27 | - run: | | |
28 | - cargo fmt --all -- --check | |
29 | - cargo clippy --all-targets -- -D warnings | |
30 | - cargo test --verbose | |
31 | - | |
32 | - - name: Dry run | |
33 | - run: cargo publish --dry-run | |
34 | - | |
35 | - - name: Publish to crates.io | |
36 | - run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
37 | 0 | |
▼.github/workflows/release.yml
+40-4
| @@ -9,9 +9,45 @@ env: | ||
9 | 9 | CARGO_TERM_COLOR: always |
10 | 10 | |
11 | 11 | jobs: |
12 | + # Run all checks before building/publishing | |
13 | + checks: | |
14 | + name: Pre-release Checks | |
15 | + runs-on: ubuntu-latest | |
16 | + steps: | |
17 | + - uses: actions/checkout@v4 | |
18 | + - uses: dtolnay/rust-toolchain@stable | |
19 | + with: | |
20 | + components: rustfmt, clippy | |
21 | + - uses: Swatinem/rust-cache@v2 | |
22 | + - name: Verify version matches tag | |
23 | + run: | | |
24 | + tag="${GITHUB_REF##*/}" | |
25 | + version="v$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')" | |
26 | + if [[ "$tag" != "$version" ]]; then | |
27 | + echo "::error::Tag $tag does not match Cargo.toml version $version" | |
28 | + exit 1 | |
29 | + fi | |
30 | + - run: cargo fmt --all -- --check | |
31 | + - run: cargo clippy --all-targets -- -D warnings | |
32 | + - run: cargo test --verbose | |
33 | + - run: cargo publish --dry-run | |
34 | + | |
35 | + # Publish to crates.io | |
36 | + publish: | |
37 | + name: Publish to crates.io | |
38 | + needs: checks | |
39 | + runs-on: ubuntu-latest | |
40 | + steps: | |
41 | + - uses: actions/checkout@v4 | |
42 | + - uses: dtolnay/rust-toolchain@stable | |
43 | + - uses: Swatinem/rust-cache@v2 | |
44 | + - name: Publish | |
45 | + run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
46 | + | |
12 | 47 | # Build Rust binaries for multiple platforms |
13 | 48 | build: |
14 | 49 | name: Build (${{ matrix.target }}) |
50 | + needs: checks | |
15 | 51 | runs-on: ${{ matrix.os }} |
16 | 52 | strategy: |
17 | 53 | fail-fast: false |
| @@ -65,10 +101,10 @@ jobs: | ||
65 | 101 | name: ${{ matrix.artifact }} |
66 | 102 | path: dist/${{ matrix.artifact }}.tar.gz* |
67 | 103 | |
68 | - # Create GitHub release with all artifacts | |
104 | + # Create GitHub release with all binary artifacts | |
69 | 105 | release: |
70 | - name: Create Release | |
71 | - needs: build | |
106 | + name: Create GitHub Release | |
107 | + needs: [build, publish] | |
72 | 108 | runs-on: ubuntu-latest |
73 | 109 | permissions: |
74 | 110 | contents: write |
| @@ -105,7 +141,7 @@ jobs: | ||
105 | 141 | cat > /tmp/notes.md << 'NOTES' |
106 | 142 | ## Install |
107 | 143 | |
108 | - ### From crates.io | |
144 | + ### From crates.io (recommended) | |
109 | 145 | ```sh |
110 | 146 | cargo install lsf |
111 | 147 | ``` |
112 | 148 | |
▼index.html
+235-84
| @@ -1,5 +1,5 @@ | ||
1 | 1 | <!DOCTYPE html> |
2 | -<html lang="en"> | |
2 | +<html lang="en" data-theme="dark"> | |
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8"> |
5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| @@ -10,6 +10,7 @@ | ||
10 | 10 | <meta name="keywords" content="ls, terminal, shell, rust, command-line, icons, nerd-fonts, lsf, rust-cli"> |
11 | 11 | <meta name="author" content="Swadhin Biswas"> |
12 | 12 | <meta name="theme-color" content="#6366f1"> |
13 | + <meta name="color-scheme" content="dark light"> | |
13 | 14 | |
14 | 15 | <!-- Open Graph / Facebook --> |
15 | 16 | <meta property="og:type" content="website"> |
| @@ -35,6 +36,15 @@ | ||
35 | 36 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
36 | 37 | <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Fira+Code:wght@400;500;600&display=swap" rel="stylesheet"> |
37 | 38 | |
39 | + <!-- Prevent FOUC: set theme before render --> | |
40 | + <script> | |
41 | + (function() { | |
42 | + var saved = localStorage.getItem('theme'); | |
43 | + var pref = saved || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'); | |
44 | + document.documentElement.setAttribute('data-theme', pref); | |
45 | + })(); | |
46 | + </script> | |
47 | + | |
38 | 48 | <style> |
39 | 49 | * { |
40 | 50 | margin: 0; |
| @@ -42,26 +52,77 @@ | ||
42 | 52 | box-sizing: border-box; |
43 | 53 | } |
44 | 54 | |
55 | + /* ===== Theme Variables ===== */ | |
45 | 56 | :root { |
46 | - --primary: #6366f1; | |
47 | - --primary-light: #818cf8; | |
48 | - --primary-dark: #4f46e5; | |
49 | - --secondary: #ec4899; | |
50 | - --accent: #f59e0b; | |
51 | - --success: #10b981; | |
52 | - --danger: #ef4444; | |
53 | - --dark: #0f172a; | |
54 | - --dark-2: #1e293b; | |
55 | - --light: #f8fafc; | |
57 | + --primary: #818cf8; | |
58 | + --primary-light: #a5b4fc; | |
59 | + --primary-dark: #6366f1; | |
60 | + --secondary: #f472b6; | |
61 | + --accent: #fbbf24; | |
62 | + --success: #34d399; | |
63 | + --danger: #f87171; | |
64 | + --radius: 12px; | |
65 | + --nav-height: 64px; | |
66 | + } | |
67 | + | |
68 | + /* ---------- Dark theme (default) ---------- */ | |
69 | + [data-theme="dark"] { | |
70 | + --bg: #0b0f1a; | |
71 | + --bg-2: #111827; | |
72 | + --bg-card: #1e293b; | |
73 | + --bg-card-hover: #263248; | |
74 | + --surface: #1e293b; | |
75 | + --surface-2: #334155; | |
76 | + --text: #e2e8f0; | |
77 | + --text-secondary: #94a3b8; | |
78 | + --text-muted: #64748b; | |
79 | + --border: #334155; | |
80 | + --border-hover: #4f5d75; | |
81 | + --nav-bg: rgba(11, 15, 26, 0.85); | |
82 | + --code-bg: #0f172a; | |
83 | + --shadow-sm: 0 1px 2px rgba(0,0,0,0.3); | |
84 | + --shadow-md: 0 4px 12px rgba(0,0,0,0.35); | |
85 | + --shadow-lg: 0 10px 30px rgba(0,0,0,0.45); | |
86 | + --shadow-xl: 0 20px 50px rgba(0,0,0,0.55); | |
87 | + --hero-after-bg: var(--bg); | |
88 | + --feature-icon-speed: rgba(124,58,237,0.15); | |
89 | + --feature-icon-icons: rgba(236,72,153,0.15); | |
90 | + --feature-icon-tree: rgba(16,185,129,0.15); | |
91 | + --feature-icon-git: rgba(59,130,246,0.15); | |
92 | + --feature-icon-compat: rgba(245,158,11,0.15); | |
93 | + --feature-icon-zero: rgba(99,102,241,0.15); | |
94 | + --footer-bg: #060911; | |
95 | + --footer-border: #1e293b; | |
96 | + } | |
97 | + | |
98 | + /* ---------- Light theme ---------- */ | |
99 | + [data-theme="light"] { | |
100 | + --bg: #f8fafc; | |
101 | + --bg-2: #f1f5f9; | |
102 | + --bg-card: #ffffff; | |
103 | + --bg-card-hover: #ffffff; | |
104 | + --surface: #ffffff; | |
105 | + --surface-2: #f1f5f9; | |
56 | 106 | --text: #1e293b; |
57 | - --text-light: #64748b; | |
107 | + --text-secondary: #64748b; | |
108 | + --text-muted: #94a3b8; | |
58 | 109 | --border: #e2e8f0; |
59 | - --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); | |
60 | - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1); | |
61 | - --shadow-lg: 0 10px 25px -3px rgba(0, 0, 0, 0.15), 0 4px 6px -4px rgba(0, 0, 0, 0.1); | |
62 | - --shadow-xl: 0 20px 50px -12px rgba(0, 0, 0, 0.25); | |
63 | - --nav-height: 64px; | |
64 | - --radius: 12px; | |
110 | + --border-hover: #cbd5e1; | |
111 | + --nav-bg: rgba(255, 255, 255, 0.85); | |
112 | + --code-bg: #1e293b; | |
113 | + --shadow-sm: 0 1px 2px rgba(0,0,0,0.05); | |
114 | + --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1); | |
115 | + --shadow-lg: 0 10px 25px -3px rgba(0,0,0,0.12), 0 4px 6px -4px rgba(0,0,0,0.08); | |
116 | + --shadow-xl: 0 20px 50px -12px rgba(0,0,0,0.2); | |
117 | + --hero-after-bg: var(--bg); | |
118 | + --feature-icon-speed: #ede9fe; | |
119 | + --feature-icon-icons: #fce7f3; | |
120 | + --feature-icon-tree: #d1fae5; | |
121 | + --feature-icon-git: #dbeafe; | |
122 | + --feature-icon-compat: #fef3c7; | |
123 | + --feature-icon-zero: #e0e7ff; | |
124 | + --footer-bg: #0f172a; | |
125 | + --footer-border: #1e293b; | |
65 | 126 | } |
66 | 127 | |
67 | 128 | html { |
| @@ -72,8 +133,9 @@ | ||
72 | 133 | font-family: 'Inter', system-ui, -apple-system, sans-serif; |
73 | 134 | line-height: 1.6; |
74 | 135 | color: var(--text); |
75 | - background: var(--light); | |
136 | + background: var(--bg); | |
76 | 137 | overflow-x: hidden; |
138 | + transition: background 0.3s, color 0.3s; | |
77 | 139 | } |
78 | 140 | |
79 | 141 | .container { |
| @@ -85,7 +147,7 @@ | ||
85 | 147 | /* ===== Navigation ===== */ |
86 | 148 | nav { |
87 | 149 | height: var(--nav-height); |
88 | - background: rgba(255, 255, 255, 0.85); | |
150 | + background: var(--nav-bg); | |
89 | 151 | backdrop-filter: blur(12px); |
90 | 152 | -webkit-backdrop-filter: blur(12px); |
91 | 153 | position: fixed; |
| @@ -95,6 +157,7 @@ | ||
95 | 157 | border-bottom: 1px solid var(--border); |
96 | 158 | display: flex; |
97 | 159 | align-items: center; |
160 | + transition: background 0.3s, border-color 0.3s; | |
98 | 161 | } |
99 | 162 | |
100 | 163 | nav .container { |
| @@ -127,6 +190,12 @@ | ||
127 | 190 | color: transparent; |
128 | 191 | } |
129 | 192 | |
193 | + .nav-right { | |
194 | + display: flex; | |
195 | + align-items: center; | |
196 | + gap: 1rem; | |
197 | + } | |
198 | + | |
130 | 199 | .nav-links { |
131 | 200 | display: flex; |
132 | 201 | gap: 2rem; |
| @@ -135,7 +204,7 @@ | ||
135 | 204 | |
136 | 205 | .nav-links a { |
137 | 206 | text-decoration: none; |
138 | - color: var(--text-light); | |
207 | + color: var(--text-secondary); | |
139 | 208 | font-weight: 500; |
140 | 209 | font-size: 0.925rem; |
141 | 210 | transition: color 0.2s; |
| @@ -146,7 +215,7 @@ | ||
146 | 215 | } |
147 | 216 | |
148 | 217 | .nav-links .btn-nav { |
149 | - background: var(--primary); | |
218 | + background: var(--primary-dark); | |
150 | 219 | color: white; |
151 | 220 | padding: 0.45rem 1.1rem; |
152 | 221 | border-radius: 8px; |
| @@ -155,11 +224,51 @@ | ||
155 | 224 | } |
156 | 225 | |
157 | 226 | .nav-links .btn-nav:hover { |
158 | - background: var(--primary-dark); | |
227 | + background: var(--primary); | |
159 | 228 | color: white; |
160 | 229 | transform: translateY(-1px); |
161 | 230 | } |
162 | 231 | |
232 | + /* Theme toggle */ | |
233 | + .theme-toggle { | |
234 | + background: var(--surface); | |
235 | + border: 1px solid var(--border); | |
236 | + color: var(--text-secondary); | |
237 | + width: 40px; | |
238 | + height: 40px; | |
239 | + border-radius: 10px; | |
240 | + cursor: pointer; | |
241 | + display: flex; | |
242 | + align-items: center; | |
243 | + justify-content: center; | |
244 | + transition: all 0.2s; | |
245 | + flex-shrink: 0; | |
246 | + } | |
247 | + | |
248 | + .theme-toggle:hover { | |
249 | + background: var(--surface-2); | |
250 | + color: var(--accent); | |
251 | + border-color: var(--border-hover); | |
252 | + } | |
253 | + | |
254 | + .theme-toggle svg { | |
255 | + width: 20px; | |
256 | + height: 20px; | |
257 | + } | |
258 | + | |
259 | + .theme-toggle .icon-sun, | |
260 | + .theme-toggle .icon-moon { | |
261 | + display: none; | |
262 | + } | |
263 | + | |
264 | + [data-theme="dark"] .theme-toggle .icon-sun { | |
265 | + display: block; | |
266 | + } | |
267 | + | |
268 | + [data-theme="light"] .theme-toggle .icon-moon { | |
269 | + display: block; | |
270 | + } | |
271 | + | |
163 | 272 | /* Hamburger menu button */ |
164 | 273 | .hamburger { |
165 | 274 | display: none; |
| @@ -192,7 +301,7 @@ | ||
192 | 301 | |
193 | 302 | /* ===== Hero Section ===== */ |
194 | 303 | header { |
195 | - background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 40%, #7c3aed 70%, var(--secondary) 100%); | |
304 | + background: linear-gradient(135deg, #4f46e5 0%, #6366f1 30%, #7c3aed 60%, #a855f7 80%, #ec4899 100%); | |
196 | 305 | color: white; |
197 | 306 | padding: calc(var(--nav-height) + 80px) 0 100px; |
198 | 307 | text-align: center; |
| @@ -219,8 +328,9 @@ | ||
219 | 328 | left: 0; |
220 | 329 | right: 0; |
221 | 330 | height: 80px; |
222 | - background: var(--light); | |
331 | + background: var(--bg); | |
223 | 332 | clip-path: ellipse(55% 100% at 50% 100%); |
333 | + transition: background 0.3s; | |
224 | 334 | } |
225 | 335 | |
226 | 336 | .hero-content { |
| @@ -304,7 +414,7 @@ | ||
304 | 414 | |
305 | 415 | .btn-white { |
306 | 416 | background: white; |
307 | - color: var(--primary); | |
417 | + color: var(--primary-dark); | |
308 | 418 | box-shadow: var(--shadow-md); |
309 | 419 | } |
310 | 420 | |
| @@ -351,7 +461,7 @@ | ||
351 | 461 | } |
352 | 462 | |
353 | 463 | .section-title p { |
354 | - color: var(--text-light); | |
464 | + color: var(--text-secondary); | |
355 | 465 | font-size: 1.1rem; |
356 | 466 | } |
357 | 467 | |
| @@ -363,7 +473,7 @@ | ||
363 | 473 | } |
364 | 474 | |
365 | 475 | .feature-card { |
366 | - background: white; | |
476 | + background: var(--bg-card); | |
367 | 477 | padding: 2.25rem 1.75rem; |
368 | 478 | border-radius: 16px; |
369 | 479 | border: 1px solid var(--border); |
| @@ -388,6 +498,7 @@ | ||
388 | 498 | transform: translateY(-6px); |
389 | 499 | box-shadow: var(--shadow-lg); |
390 | 500 | border-color: var(--primary-light); |
501 | + background: var(--bg-card-hover); | |
391 | 502 | } |
392 | 503 | |
393 | 504 | .feature-card:hover::before { |
| @@ -405,42 +516,43 @@ | ||
405 | 516 | font-size: 1.5rem; |
406 | 517 | } |
407 | 518 | |
408 | - .feature-icon.speed { background: #ede9fe; } | |
409 | - .feature-icon.icons { background: #fce7f3; } | |
410 | - .feature-icon.tree { background: #d1fae5; } | |
411 | - .feature-icon.git { background: #dbeafe; } | |
412 | - .feature-icon.compat { background: #fef3c7; } | |
413 | - .feature-icon.zero { background: #e0e7ff; } | |
519 | + .feature-icon.speed { background: var(--feature-icon-speed); } | |
520 | + .feature-icon.icons { background: var(--feature-icon-icons); } | |
521 | + .feature-icon.tree { background: var(--feature-icon-tree); } | |
522 | + .feature-icon.git { background: var(--feature-icon-git); } | |
523 | + .feature-icon.compat { background: var(--feature-icon-compat); } | |
524 | + .feature-icon.zero { background: var(--feature-icon-zero); } | |
414 | 525 | |
415 | 526 | .feature-card h3 { |
416 | 527 | font-size: 1.2rem; |
417 | 528 | margin-bottom: 0.6rem; |
418 | - color: var(--dark); | |
529 | + color: var(--text); | |
419 | 530 | font-weight: 700; |
420 | 531 | } |
421 | 532 | |
422 | 533 | .feature-card p { |
423 | - color: var(--text-light); | |
534 | + color: var(--text-secondary); | |
424 | 535 | font-size: 0.925rem; |
425 | 536 | line-height: 1.6; |
426 | 537 | } |
427 | 538 | |
428 | 539 | .feature-card code { |
429 | - background: #f1f5f9; | |
540 | + background: var(--surface-2); | |
430 | 541 | padding: 0.1rem 0.4rem; |
431 | 542 | border-radius: 4px; |
432 | 543 | font-family: 'Fira Code', monospace; |
433 | 544 | font-size: 0.85em; |
434 | - color: var(--primary); | |
545 | + color: var(--primary-light); | |
435 | 546 | } |
436 | 547 | |
437 | 548 | /* ===== Demo Section ===== */ |
438 | 549 | #demo { |
439 | - background: white; | |
550 | + background: var(--bg-2); | |
551 | + transition: background 0.3s; | |
440 | 552 | } |
441 | 553 | |
442 | 554 | .demo-box { |
443 | - background: var(--dark); | |
555 | + background: #0f172a; | |
444 | 556 | border-radius: 16px; |
445 | 557 | overflow: hidden; |
446 | 558 | box-shadow: var(--shadow-xl); |
| @@ -450,7 +562,7 @@ | ||
450 | 562 | } |
451 | 563 | |
452 | 564 | .demo-header { |
453 | - background: var(--dark-2); | |
565 | + background: #1e293b; | |
454 | 566 | padding: 14px 20px; |
455 | 567 | display: flex; |
456 | 568 | align-items: center; |
| @@ -484,9 +596,9 @@ | ||
484 | 596 | overflow-x: auto; |
485 | 597 | } |
486 | 598 | |
487 | - .demo-content .prompt { color: var(--success); font-weight: 600; } | |
599 | + .demo-content .prompt { color: #34d399; font-weight: 600; } | |
488 | 600 | .demo-content .cmd { color: #e2e8f0; } |
489 | - .demo-content .flag { color: var(--accent); } | |
601 | + .demo-content .flag { color: #fbbf24; } | |
490 | 602 | .demo-content .dir { color: #60a5fa; font-weight: 600; } |
491 | 603 | .demo-content .file { color: #94a3b8; } |
492 | 604 | .demo-content .exec { color: #34d399; } |
| @@ -525,15 +637,16 @@ | ||
525 | 637 | } |
526 | 638 | |
527 | 639 | .install-card { |
528 | - background: white; | |
640 | + background: var(--bg-card); | |
529 | 641 | padding: 2rem; |
530 | 642 | border-radius: 16px; |
531 | 643 | border: 1px solid var(--border); |
532 | - transition: box-shadow 0.3s; | |
644 | + transition: all 0.3s; | |
533 | 645 | } |
534 | 646 | |
535 | 647 | .install-card:hover { |
536 | 648 | box-shadow: var(--shadow-md); |
649 | + border-color: var(--border-hover); | |
537 | 650 | } |
538 | 651 | |
539 | 652 | .install-card h3 { |
| @@ -543,16 +656,17 @@ | ||
543 | 656 | gap: 0.5rem; |
544 | 657 | font-size: 1.1rem; |
545 | 658 | font-weight: 700; |
659 | + color: var(--text); | |
546 | 660 | } |
547 | 661 | |
548 | 662 | .install-card > p { |
549 | - color: var(--text-light); | |
663 | + color: var(--text-secondary); | |
550 | 664 | font-size: 0.9rem; |
551 | 665 | margin-bottom: 1rem; |
552 | 666 | } |
553 | 667 | |
554 | 668 | .code-block { |
555 | - background: var(--dark); | |
669 | + background: var(--code-bg); | |
556 | 670 | color: #e2e8f0; |
557 | 671 | padding: 1rem 1.25rem; |
558 | 672 | border-radius: 10px; |
| @@ -612,7 +726,7 @@ | ||
612 | 726 | |
613 | 727 | /* ===== Footer ===== */ |
614 | 728 | footer { |
615 | - background: var(--dark); | |
729 | + background: var(--footer-bg); | |
616 | 730 | color: white; |
617 | 731 | padding: 60px 0 32px; |
618 | 732 | } |
| @@ -676,12 +790,21 @@ | ||
676 | 790 | |
677 | 791 | .copyright { |
678 | 792 | padding-top: 1.5rem; |
679 | - border-top: 1px solid #1e293b; | |
793 | + border-top: 1px solid var(--footer-border); | |
680 | 794 | text-align: center; |
681 | 795 | color: #64748b; |
682 | 796 | font-size: 0.85rem; |
683 | 797 | } |
684 | 798 | |
799 | + .copyright a { | |
800 | + color: var(--primary-light); | |
801 | + text-decoration: none; | |
802 | + } | |
803 | + | |
804 | + .copyright a:hover { | |
805 | + text-decoration: underline; | |
806 | + } | |
807 | + | |
685 | 808 | /* ===== Animations ===== */ |
686 | 809 | @keyframes fadeInDown { |
687 | 810 | from { opacity: 0; transform: translateY(-16px); } |
| @@ -711,7 +834,7 @@ | ||
711 | 834 | top: var(--nav-height); |
712 | 835 | left: 0; |
713 | 836 | right: 0; |
714 | - background: white; | |
837 | + background: var(--bg-card); | |
715 | 838 | flex-direction: column; |
716 | 839 | padding: 1rem 1.5rem 1.5rem; |
717 | 840 | gap: 0.75rem; |
| @@ -776,19 +899,26 @@ | ||
776 | 899 | </svg> |
777 | 900 | <span>ls-f</span> |
778 | 901 | </a> |
779 | - <button class="hamburger" id="hamburger" aria-label="Toggle navigation"> | |
780 | - <span></span> | |
781 | - <span></span> | |
782 | - <span></span> | |
783 | - </button> | |
784 | - <div class="nav-links" id="nav-links"> | |
785 | - <a href="#features">Features</a> | |
786 | - <a href="#demo">Demo</a> | |
787 | - <a href="#installation">Install</a> | |
788 | - <a href="https://github.com/swadhinbiswas/ls-f" class="btn-nav"> | |
789 | - <svg viewBox="0 0 16 16" fill="currentColor" style="width:16px;height:16px;vertical-align:middle;margin-right:4px"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg> | |
790 | - GitHub | |
791 | - </a> | |
902 | + <div class="nav-right"> | |
903 | + <button class="hamburger" id="hamburger" aria-label="Toggle navigation"> | |
904 | + <span></span> | |
905 | + <span></span> | |
906 | + <span></span> | |
907 | + </button> | |
908 | + <div class="nav-links" id="nav-links"> | |
909 | + <a href="#features">Features</a> | |
910 | + <a href="#demo">Demo</a> | |
911 | + <a href="#installation">Install</a> | |
912 | + <a href="https://crates.io/crates/lsf">crates.io</a> | |
913 | + <a href="https://github.com/swadhinbiswas/ls-f" class="btn-nav"> | |
914 | + <svg viewBox="0 0 16 16" fill="currentColor" style="width:16px;height:16px;vertical-align:middle;margin-right:4px"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg> | |
915 | + GitHub | |
916 | + </a> | |
917 | + </div> | |
918 | + <button class="theme-toggle" id="theme-toggle" aria-label="Toggle dark/light theme"> | |
919 | + <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg> | |
920 | + <svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg> | |
921 | + </button> | |
792 | 922 | </div> |
793 | 923 | </div> |
794 | 924 | </nav> |
| @@ -939,22 +1069,22 @@ | ||
939 | 1069 | <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--primary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0022 16z"/></svg> |
940 | 1070 | Via Cargo |
941 | 1071 | </h3> |
942 | - <p>Recommended — the easiest way to install.</p> | |
1072 | + <p>Recommended — install from crates.io.</p> | |
943 | 1073 | <div class="code-block" id="code-cargo"> |
944 | 1074 | <button class="copy-btn" onclick="copyCode('code-cargo')" aria-label="Copy to clipboard"> |
945 | 1075 | <svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg> |
946 | 1076 | Copy |
947 | 1077 | </button> |
948 | - <code>cargo install --path .</code> | |
1078 | + <code>cargo install lsf</code> | |
949 | 1079 | </div> |
950 | 1080 | </div> |
951 | 1081 | |
952 | 1082 | <div class="install-card"> |
953 | 1083 | <h3> |
954 | - <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg> | |
1084 | + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--text-secondary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg> | |
955 | 1085 | From Source |
956 | 1086 | </h3> |
957 | - <p>Build and install to your system bin directory.</p> | |
1087 | + <p>Clone and build locally.</p> | |
958 | 1088 | <div class="code-block" id="code-source"> |
959 | 1089 | <button class="copy-btn" onclick="copyCode('code-source')" aria-label="Copy to clipboard"> |
960 | 1090 | <svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg> |
| @@ -962,7 +1092,7 @@ | ||
962 | 1092 | </button> |
963 | 1093 | <code>git clone https://github.com/swadhinbiswas/ls-f.git |
964 | 1094 | cd ls-f |
965 | -make install</code> | |
1095 | +cargo install --path .</code> | |
966 | 1096 | </div> |
967 | 1097 | </div> |
968 | 1098 | </div> |
| @@ -1002,32 +1132,53 @@ make install</code> | ||
1002 | 1132 | <h4>Community</h4> |
1003 | 1133 | <ul> |
1004 | 1134 | <li><a href="https://github.com/swadhinbiswas/ls-f">GitHub</a></li> |
1135 | + <li><a href="https://crates.io/crates/lsf">crates.io</a></li> | |
1005 | 1136 | <li><a href="https://github.com/swadhinbiswas/ls-f/issues">Issues</a></li> |
1006 | - <li><a href="https://github.com/swadhinbiswas/ls-f/pulls">Pull Requests</a></li> | |
1007 | 1137 | <li><a href="https://github.com/swadhinbiswas/ls-f/blob/main/CONTRIBUTING.md">Contributing</a></li> |
1008 | 1138 | </ul> |
1009 | 1139 | </div> |
1010 | 1140 | </div> |
1011 | 1141 | |
1012 | 1142 | <div class="copyright"> |
1013 | - <p>© <script>document.write(new Date().getFullYear())</script> Swadhin Biswas. Released under the MIT License.</p> | |
1143 | + <p>© <script>document.write(new Date().getFullYear())</script> Swadhin Biswas. Released under the <a href="https://github.com/swadhinbiswas/ls-f/blob/main/LICENSE">MIT License</a>.</p> | |
1014 | 1144 | </div> |
1015 | 1145 | </div> |
1016 | 1146 | </footer> |
1017 | 1147 | |
1018 | 1148 | <script> |
1149 | + // Theme toggle | |
1150 | + const themeToggle = document.getElementById('theme-toggle'); | |
1151 | + | |
1152 | + themeToggle.addEventListener('click', function() { | |
1153 | + const current = document.documentElement.getAttribute('data-theme'); | |
1154 | + const next = current === 'dark' ? 'light' : 'dark'; | |
1155 | + document.documentElement.setAttribute('data-theme', next); | |
1156 | + localStorage.setItem('theme', next); | |
1157 | + // Update meta theme-color | |
1158 | + document.querySelector('meta[name="theme-color"]').setAttribute('content', | |
1159 | + next === 'dark' ? '#0b0f1a' : '#6366f1' | |
1160 | + ); | |
1161 | + }); | |
1162 | + | |
1163 | + // Listen for system preference changes | |
1164 | + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) { | |
1165 | + if (!localStorage.getItem('theme')) { | |
1166 | + document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light'); | |
1167 | + } | |
1168 | + }); | |
1169 | + | |
1019 | 1170 | // Mobile hamburger menu toggle |
1020 | 1171 | const hamburger = document.getElementById('hamburger'); |
1021 | 1172 | const navLinks = document.getElementById('nav-links'); |
1022 | 1173 | |
1023 | - hamburger.addEventListener('click', () => { | |
1174 | + hamburger.addEventListener('click', function() { | |
1024 | 1175 | hamburger.classList.toggle('active'); |
1025 | 1176 | navLinks.classList.toggle('open'); |
1026 | 1177 | }); |
1027 | 1178 | |
1028 | 1179 | // Close menu when a link is clicked |
1029 | - navLinks.querySelectorAll('a').forEach(link => { | |
1030 | - link.addEventListener('click', () => { | |
1180 | + navLinks.querySelectorAll('a').forEach(function(link) { | |
1181 | + link.addEventListener('click', function() { | |
1031 | 1182 | hamburger.classList.remove('active'); |
1032 | 1183 | navLinks.classList.remove('open'); |
1033 | 1184 | }); |
| @@ -1035,14 +1186,14 @@ make install</code> | ||
1035 | 1186 | |
1036 | 1187 | // Copy to clipboard |
1037 | 1188 | function copyCode(blockId) { |
1038 | - const block = document.getElementById(blockId); | |
1039 | - const code = block.querySelector('code').textContent; | |
1040 | - const btn = block.querySelector('.copy-btn'); | |
1189 | + var block = document.getElementById(blockId); | |
1190 | + var code = block.querySelector('code').textContent; | |
1191 | + var btn = block.querySelector('.copy-btn'); | |
1041 | 1192 | |
1042 | - navigator.clipboard.writeText(code.trim()).then(() => { | |
1193 | + navigator.clipboard.writeText(code.trim()).then(function() { | |
1043 | 1194 | btn.classList.add('copied'); |
1044 | 1195 | btn.innerHTML = '<svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg> Copied!'; |
1045 | - setTimeout(() => { | |
1196 | + setTimeout(function() { | |
1046 | 1197 | btn.classList.remove('copied'); |
1047 | 1198 | btn.innerHTML = '<svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg> Copy'; |
1048 | 1199 | }, 2000); |
| @@ -1050,14 +1201,14 @@ make install</code> | ||
1050 | 1201 | } |
1051 | 1202 | |
1052 | 1203 | // Smooth scroll for anchor links |
1053 | - document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
1054 | - anchor.addEventListener('click', function (e) { | |
1055 | - const target = document.querySelector(this.getAttribute('href')); | |
1204 | + document.querySelectorAll('a[href^="#"]').forEach(function(anchor) { | |
1205 | + anchor.addEventListener('click', function(e) { | |
1206 | + var target = document.querySelector(this.getAttribute('href')); | |
1056 | 1207 | if (target) { |
1057 | 1208 | e.preventDefault(); |
1058 | - const offset = 80; // nav height + padding | |
1059 | - const top = target.getBoundingClientRect().top + window.pageYOffset - offset; | |
1060 | - window.scrollTo({ top, behavior: 'smooth' }); | |
1209 | + var offset = 80; | |
1210 | + var top = target.getBoundingClientRect().top + window.pageYOffset - offset; | |
1211 | + window.scrollTo({ top: top, behavior: 'smooth' }); | |
1061 | 1212 | } |
1062 | 1213 | }); |
1063 | 1214 | }); |
1064 | 1215 | |