Swadhin Biswas

[email protected]
2026-03-08 03:15:14 +0600 committed NaN years ago
5a2b5ab
commit 5a2b5ab
3 files changed
+275 -124
▼.github/workflows/publish.yml
+0-36
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 &mdash; the easiest way to install.</p>
1072
+ <p>Recommended &mdash; 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
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
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>&copy; <script>document.write(new Date().getFullYear())</script> Swadhin Biswas. Released under the MIT License.</p>
1143
+ <p>&copy; <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
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
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