feat(ui): unified docs folder, fixed dark mode callouts, and replaced emojis with Lucide SVGs

Swadhin Biswas committed 7 months ago
0f649a1
1 parent 4f7778a
commit 0f649a1
5 files changed
+627 -578
β–Ό.github/workflows/deploy-pages.yml
+8-6
32
32
- name: Setup Pages
33
33
uses: actions/configure-pages@v4
34
34
35
+ - name: Build site
36
+ run: |
37
+ mkdir public
38
+ cp index.html public/
39
+ cp logo.svg public/
40
+ cp -r docs public/
41
+
35
42
- name: Upload artifact
36
43
uses: actions/upload-pages-artifact@v3
37
44
with:
38
- # Upload root files and docs folder
39
- path: '.'
40
- pattern: |
41
- index.html
42
- logo.svg
43
- docs/**
45
+ path: './public'
44
46
45
47
- name: Deploy to GitHub Pages
46
48
id: deployment
47
49
β–Όdocs-site/index.html β†’ docs/index.html
+84-78
9
9
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
10
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
11
11
<link rel="stylesheet" href="styles.css">
12
+ <!-- Lucide Icons -->
13
+ <script src="https://unpkg.com/lucide@latest"></script>
12
14
</head>
13
15
<body>
14
16
<div class="paper-texture"></div>
192
194
<span class="breadcrumb-sep">/</span>
193
195
<span class="current">Quick Start</span>
194
196
</nav>
195
- <h1>πŸš€ Quick Start</h1>
197
+ <h1><i data-lucide="rocket" class="icon-inline"></i> Quick Start</h1>
196
198
<p class="section-description">Get OpenGrammar up and running in 5 minutes!</p>
197
199
</div>
198
200
199
201
<div class="content-body">
200
202
<div class="callout callout-primary">
201
- <div class="callout-icon">⚑</div>
203
+ <div class="callout-icon"><i data-lucide="zap" class="icon-inline"></i></div>
202
204
<div class="callout-content">
203
205
<strong>5-Minute Setup</strong>
204
206
<p>Follow these steps to get OpenGrammar running quickly. You'll need an API key for the best experience.</p>
216
218
</ol>
217
219
218
220
<div class="callout callout-success">
219
- <div class="callout-icon">βœ…</div>
221
+ <div class="callout-icon"><i data-lucide="check-circle-2" class="icon-inline"></i></div>
220
222
<div class="callout-content">
221
223
<strong>Free Tier:</strong> 100 requests/day - enough for most users!
222
224
</div>
265
267
<li>Enable <strong>Developer mode</strong> (toggle in top-right)</li>
266
268
<li>Click <strong>Load unpacked</strong></li>
267
269
<li>Select the <code>opengrammar/extension/dist</code> folder</li>
268
- <li>βœ… Extension loaded! You'll see the OpenGrammar icon</li>
270
+ <li><i data-lucide="check-circle-2" class="icon-inline"></i> Extension loaded! You'll see the OpenGrammar icon</li>
269
271
</ol>
270
272
</div>
271
273
<div class="tab-pane" id="brave">
275
277
<li>Enable <strong>Developer mode</strong> (top-right)</li>
276
278
<li>Click <strong>Load unpacked</strong></li>
277
279
<li>Select <code>opengrammar/extension/dist</code> folder</li>
278
- <li>βœ… Extension loaded!</li>
280
+ <li><i data-lucide="check-circle-2" class="icon-inline"></i> Extension loaded!</li>
279
281
</ol>
280
282
</div>
281
283
<div class="tab-pane" id="edge">
285
287
<li>Enable <strong>Developer mode</strong> (left sidebar)</li>
286
288
<li>Click <strong>Load unpacked</strong></li>
287
289
<li>Select <code>opengrammar/extension/dist</code> folder</li>
288
- <li>βœ… Extension loaded!</li>
290
+ <li><i data-lucide="check-circle-2" class="icon-inline"></i> Extension loaded!</li>
289
291
</ol>
290
292
</div>
291
293
<div class="tab-pane" id="firefox">
292
294
<h4>Mozilla Firefox</h4>
293
295
<div class="callout callout-warning">
294
- <div class="callout-icon">⚠️</div>
296
+ <div class="callout-icon"><i data-lucide="alert-triangle" class="icon-inline"></i>️</div>
295
297
<div class="callout-content">
296
298
<strong>Note:</strong> Firefox support is temporary. The extension must be reloaded each time you restart Firefox.
297
299
</div>
301
303
<li>Click <strong>Load Temporary Add-on</strong></li>
302
304
<li>Navigate to <code>opengrammar/extension/dist</code></li>
303
305
<li>Select <code>manifest.json</code></li>
304
- <li>βœ… Extension loaded!</li>
306
+ <li><i data-lucide="check-circle-2" class="icon-inline"></i> Extension loaded!</li>
305
307
</ol>
306
308
</div>
307
309
</div>
328
330
329
331
<div class="feature-grid">
330
332
<div class="feature-card">
331
- <div class="feature-icon">πŸ“š</div>
333
+ <div class="feature-icon"><i data-lucide="library" class="icon-inline"></i></div>
332
334
<h4>Read Next</h4>
333
335
<ul class="link-list">
334
336
<li><a href="#backend-deployment">Backend Deployment</a></li>
377
379
<span class="breadcrumb-sep">/</span>
378
380
<span class="current">Browser Extension</span>
379
381
</nav>
380
- <h1>🌐 Browser Extension Setup</h1>
382
+ <h1><i data-lucide="globe" class="icon-inline"></i> Browser Extension Setup</h1>
381
383
<p class="section-description">Install and configure OpenGrammar on Chrome, Brave, Edge, and Firefox.</p>
382
384
</div>
383
385
384
386
<div class="content-body">
385
- <h2>πŸ“‹ Supported Browsers</h2>
387
+ <h2><i data-lucide="clipboard-list" class="icon-inline"></i> Supported Browsers</h2>
386
388
387
389
<div class="table-wrapper">
388
390
<table class="data-table">
397
399
<tr>
398
400
<td><strong>Google Chrome</strong></td>
399
401
<td>88+</td>
400
- <td><span class="status-badge success">βœ… Fully Supported</span></td>
402
+ <td><span class="status-badge success"><i data-lucide="check-circle-2" class="icon-inline"></i> Fully Supported</span></td>
401
403
</tr>
402
404
<tr>
403
405
<td><strong>Brave</strong></td>
404
406
<td>1.20+</td>
405
- <td><span class="status-badge success">βœ… Fully Supported</span></td>
407
+ <td><span class="status-badge success"><i data-lucide="check-circle-2" class="icon-inline"></i> Fully Supported</span></td>
406
408
</tr>
407
409
<tr>
408
410
<td><strong>Microsoft Edge</strong></td>
409
411
<td>88+</td>
410
- <td><span class="status-badge success">βœ… Fully Supported</span></td>
412
+ <td><span class="status-badge success"><i data-lucide="check-circle-2" class="icon-inline"></i> Fully Supported</span></td>
411
413
</tr>
412
414
<tr>
413
415
<td><strong>Mozilla Firefox</strong></td>
414
416
<td>90+</td>
415
- <td><span class="status-badge warning">βœ… Supported (Temporary)</span></td>
417
+ <td><span class="status-badge warning"><i data-lucide="check-circle-2" class="icon-inline"></i> Supported (Temporary)</span></td>
416
418
</tr>
417
419
<tr>
418
420
<td><strong>Opera</strong></td>
419
421
<td>74+</td>
420
- <td><span class="status-badge success">βœ… Supported</span></td>
422
+ <td><span class="status-badge success"><i data-lucide="check-circle-2" class="icon-inline"></i> Supported</span></td>
421
423
</tr>
422
424
<tr>
423
425
<td><strong>Vivaldi</strong></td>
424
426
<td>3.6+</td>
425
- <td><span class="status-badge success">βœ… Supported</span></td>
427
+ <td><span class="status-badge success"><i data-lucide="check-circle-2" class="icon-inline"></i> Supported</span></td>
426
428
</tr>
427
429
</tbody>
428
430
</table>
429
431
</div>
430
432
431
- <h2>πŸ”§ Installation - Chrome</h2>
433
+ <h2><i data-lucide="wrench" class="icon-inline"></i> Installation - Chrome</h2>
432
434
433
435
<h3>Step 1: Build the Extension</h3>
434
436
<div class="code-block">
462
464
<li>Click <strong>Select</strong></li>
463
465
</ol>
464
466
<div class="callout callout-success">
465
- <div class="callout-icon">βœ…</div>
467
+ <div class="callout-icon"><i data-lucide="check-circle-2" class="icon-inline"></i></div>
466
468
<div class="callout-content">
467
469
<strong>Extension loaded!</strong> You'll see the OpenGrammar icon in your toolbar.
468
470
</div>
469
471
</div>
470
472
471
- <h2>βš™οΈ Initial Configuration</h2>
473
+ <h2><i data-lucide="settings" class="icon-inline"></i> Initial Configuration</h2>
472
474
473
475
<h3>Step 1: Open Settings</h3>
474
476
<ol>
490
492
<h3>Step 3: Configure AI Provider</h3>
491
493
<div class="provider-cards">
492
494
<div class="provider-card">
493
- <div class="provider-icon">⚑</div>
495
+ <div class="provider-icon"><i data-lucide="zap" class="icon-inline"></i></div>
494
496
<h4>Groq (Free)</h4>
495
497
<p>100 requests/day free</p>
496
498
<code>llama-3.1-70b-versatile</code>
497
499
</div>
498
500
<div class="provider-card">
499
- <div class="provider-icon">🟒</div>
501
+ <div class="provider-icon"><i data-lucide="circle-dot" class="icon-inline"></i></div>
500
502
<h4>OpenAI</h4>
501
503
<p>Best quality</p>
502
504
<code>gpt-4o-mini</code>
503
505
</div>
504
506
<div class="provider-card">
505
- <div class="provider-icon">πŸ¦™</div>
507
+ <div class="provider-icon"><i data-lucide="bot" class="icon-inline"></i></div>
506
508
<h4>Ollama</h4>
507
509
<p>Local & offline</p>
508
510
<code>qwen2.5:1.5b</code>
509
511
</div>
510
512
</div>
511
513
512
- <h2>🎨 User Interface</h2>
514
+ <h2><i data-lucide="palette" class="icon-inline"></i> User Interface</h2>
513
515
514
516
<h3>Color-Coded Underlines</h3>
515
517
<div class="color-guide">
563
565
<span class="breadcrumb-sep">/</span>
564
566
<span class="current">What is OpenGrammar?</span>
565
567
</nav>
566
- <h1>πŸ“– What is OpenGrammar?</h1>
568
+ <h1><i data-lucide="book-open" class="icon-inline"></i> What is OpenGrammar?</h1>
567
569
<p class="section-description">Your privacy-first, open-source writing assistant</p>
568
570
</div>
569
571
575
577
</div>
576
578
</div>
577
579
578
- <h2>🌟 Key Features</h2>
580
+ <h2><i data-lucide="star" class="icon-inline"></i> Key Features</h2>
579
581
580
582
<div class="feature-grid-2">
581
583
<div class="feature-box">
582
- <div class="feature-box-icon">πŸ”’</div>
584
+ <div class="feature-box-icon"><i data-lucide="lock" class="icon-inline"></i></div>
583
585
<h3>Zero Cost Option</h3>
584
586
<p>The core engine runs locally in your browser, checking for passive voice, repetition, and readability without needing a server or an internet connection.</p>
585
587
</div>
586
588
<div class="feature-box">
587
- <div class="feature-box-icon">πŸ”‘</div>
589
+ <div class="feature-box-icon"><i data-lucide="key" class="icon-inline"></i></div>
588
590
<h3>Bring Your Own AI</h3>
589
591
<p>Just paste in your own API key (like OpenAI, Groq, or OpenRouter). You pay only fractions of a cent for what you actually use, directly to the AI provider.</p>
590
592
</div>
591
593
<div class="feature-box">
592
- <div class="feature-box-icon">πŸ›‘οΈ</div>
594
+ <div class="feature-box-icon"><i data-lucide="shield" class="icon-inline"></i></div>
593
595
<h3>Absolute Privacy</h3>
594
596
<p>We don't have a database. We don't have user accounts. Your API key never leaves your browser. If you use the AI features, your text is sent securely to a stateless edge function, processed, and immediately forgotten.</p>
595
597
</div>
596
598
<div class="feature-box">
597
- <div class="feature-box-icon">πŸ“¦</div>
599
+ <div class="feature-box-icon"><i data-lucide="package" class="icon-inline"></i></div>
598
600
<h3>Open Source & Self-Hosted</h3>
599
601
<p>You can deploy the backend to Cloudflare Workers or Vercel Edge for free in one command. You own the infrastructure.</p>
600
602
</div>
601
603
</div>
602
604
603
- <h2>✨ Features</h2>
605
+ <h2><i data-lucide="sparkles" class="icon-inline"></i> Features</h2>
604
606
605
607
<ul class="feature-list">
606
608
<li>
672
674
<span class="breadcrumb-sep">/</span>
673
675
<span class="current">Backend Deployment</span>
674
676
</nav>
675
- <h1>🌐 Backend Deployment</h1>
677
+ <h1><i data-lucide="globe" class="icon-inline"></i> Backend Deployment</h1>
676
678
<p class="section-description">Deploy OpenGrammar backend to production with any of these platforms.</p>
677
679
</div>
678
680
<div class="content-body">
679
681
<div class="callout callout-info">
680
- <div class="callout-icon">πŸ“‹</div>
682
+ <div class="callout-icon"><i data-lucide="clipboard-list" class="icon-inline"></i></div>
681
683
<div class="callout-content">
682
684
<strong>Deployment Options Comparison</strong>
683
685
<p>Choose the platform that best fits your needs.</p>
729
731
</table>
730
732
</div>
731
733
732
- <h2>☁️ Cloudflare Workers (Recommended)</h2>
734
+ <h2><i data-lucide="cloud" class="icon-inline"></i> Cloudflare Workers (Recommended)</h2>
733
735
734
736
<h3>Prerequisites</h3>
735
737
<ul>
781
783
<pre><code>Deployed https://opengrammar.yourname.workers.dev</code></pre>
782
784
</div>
783
785
784
- <h2>β–² Vercel</h2>
786
+ <h2><i data-lucide="triangle" class="icon-inline"></i> Vercel</h2>
785
787
786
788
<h3>Step 1: Install Vercel CLI</h3>
787
789
<div class="code-block">
794
796
vercel --prod</code></pre>
795
797
</div>
796
798
797
- <h2>🐳 Docker Self-Hosting</h2>
799
+ <h2><i data-lucide="container" class="icon-inline"></i> Docker Self-Hosting</h2>
798
800
799
801
<h3>Option 1: Docker Compose</h3>
800
802
<div class="code-block">
833
835
<span class="breadcrumb-sep">/</span>
834
836
<span class="current">Docker Self-Hosting</span>
835
837
</nav>
836
- <h1>🐳 Docker Self-Hosting</h1>
838
+ <h1><i data-lucide="container" class="icon-inline"></i> Docker Self-Hosting</h1>
837
839
<p class="section-description">Run OpenGrammar locally with Docker and optional local LLM support (Ollama).</p>
838
840
</div>
839
841
<div class="content-body">
840
842
<div class="callout callout-primary">
841
- <div class="callout-icon">🎯</div>
843
+ <div class="callout-icon"><i data-lucide="target" class="icon-inline"></i></div>
842
844
<div class="callout-content">
843
845
<strong>Why Self-Host with Docker?</strong>
844
846
<ul>
851
853
</div>
852
854
</div>
853
855
854
- <h2>πŸš€ Quick Start</h2>
856
+ <h2><i data-lucide="rocket" class="icon-inline"></i> Quick Start</h2>
855
857
856
858
<h3>Option 1: Backend Only (Use Cloud APIs)</h3>
857
859
<div class="code-block">
883
885
docker-compose --profile local-llm up -d</code></pre>
884
886
</div>
885
887
886
- <h2>πŸ€– Local LLM Setup with Ollama</h2>
888
+ <h2><i data-lucide="cpu" class="icon-inline"></i> Local LLM Setup with Ollama</h2>
887
889
888
890
<h3>Step 1: Start Ollama Container</h3>
889
891
<div class="code-block">
905
907
exit</code></pre>
906
908
</div>
907
909
908
- <h2>🎯 Model Recommendations</h2>
910
+ <h2><i data-lucide="target" class="icon-inline"></i> Model Recommendations</h2>
909
911
910
912
<div class="table-wrapper">
911
913
<table class="data-table">
924
926
<td><strong>qwen2.5:0.5b</strong></td>
925
927
<td>400MB</td>
926
928
<td>1GB</td>
927
- <td>⚑⚑⚑⚑⚑</td>
929
+ <td><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></td>
928
930
<td>⭐⭐⭐</td>
929
931
<td>Fast basic checks</td>
930
932
</tr>
932
934
<td><strong>qwen2.5:1.5b</strong></td>
933
935
<td>1GB</td>
934
936
<td>2GB</td>
935
- <td>⚑⚑⚑⚑</td>
937
+ <td><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></td>
936
938
<td>⭐⭐⭐⭐</td>
937
939
<td>Balanced</td>
938
940
</tr>
940
942
<td><strong>phi4-mini:3.8b</strong></td>
941
943
<td>2.5GB</td>
942
944
<td>4GB</td>
943
- <td>⚑⚑⚑</td>
945
+ <td><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></td>
944
946
<td>⭐⭐⭐⭐⭐</td>
945
947
<td>Best quality</td>
946
948
</tr>
948
950
<td><strong>llama3.2:3b</strong></td>
949
951
<td>2GB</td>
950
952
<td>3GB</td>
951
- <td>⚑⚑⚑⚑</td>
953
+ <td><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></td>
952
954
<td>⭐⭐⭐⭐</td>
953
955
<td>Good balance</td>
954
956
</tr>
982
984
<span class="breadcrumb-sep">/</span>
983
985
<span class="current">AI Providers</span>
984
986
</nav>
985
- <h1>πŸ€– AI Provider Setup</h1>
987
+ <h1><i data-lucide="cpu" class="icon-inline"></i> AI Provider Setup</h1>
986
988
<p class="section-description">Configure AI providers for advanced grammar checking and tone rewriting.</p>
987
989
</div>
988
990
<div class="content-body">
989
- <h2>πŸ“‹ Overview</h2>
991
+ <h2><i data-lucide="clipboard-list" class="icon-inline"></i> Overview</h2>
990
992
<p>OpenGrammar supports <strong>6 AI providers</strong>, giving you flexibility in cost, quality, and privacy.</p>
991
993
992
994
<div class="provider-comparison">
993
995
<div class="provider-card-large">
994
996
<div class="provider-header">
995
- <span class="provider-icon">⚑</span>
997
+ <span class="provider-icon"><i data-lucide="zap" class="icon-inline"></i></span>
996
998
<h3>Groq</h3>
997
999
</div>
998
1000
<div class="provider-stats">
999
- <div class="stat"><span>Speed:</span> ⚑⚑⚑</div>
1001
+ <div class="stat"><span>Speed:</span> <i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></div>
1000
1002
<div class="stat"><span>Quality:</span> ⭐⭐⭐⭐</div>
1001
1003
<div class="stat"><span>Cost:</span> Free tier</div>
1002
1004
</div>
1004
1006
</div>
1005
1007
<div class="provider-card-large">
1006
1008
<div class="provider-header">
1007
- <span class="provider-icon">🟒</span>
1009
+ <span class="provider-icon"><i data-lucide="circle-dot" class="icon-inline"></i></span>
1008
1010
<h3>OpenAI</h3>
1009
1011
</div>
1010
1012
<div class="provider-stats">
1011
- <div class="stat"><span>Speed:</span> ⚑⚑</div>
1013
+ <div class="stat"><span>Speed:</span> <i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></div>
1012
1014
<div class="stat"><span>Quality:</span> ⭐⭐⭐⭐⭐</div>
1013
1015
<div class="stat"><span>Cost:</span> $$</div>
1014
1016
</div>
1016
1018
</div>
1017
1019
<div class="provider-card-large">
1018
1020
<div class="provider-header">
1019
- <span class="provider-icon">πŸ¦™</span>
1021
+ <span class="provider-icon"><i data-lucide="bot" class="icon-inline"></i></span>
1020
1022
<h3>Ollama</h3>
1021
1023
</div>
1022
1024
<div class="provider-stats">
1023
- <div class="stat"><span>Speed:</span> ⚑⚑⚑</div>
1025
+ <div class="stat"><span>Speed:</span> <i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i><i data-lucide="zap" class="icon-inline"></i></div>
1024
1026
<div class="stat"><span>Quality:</span> ⭐⭐⭐</div>
1025
1027
<div class="stat"><span>Cost:</span> Free</div>
1026
1028
</div>
1028
1030
</div>
1029
1031
</div>
1030
1032
1031
- <h2>⚑ Groq (Recommended - Free)</h2>
1033
+ <h2><i data-lucide="zap" class="icon-inline"></i> Groq (Recommended - Free)</h2>
1032
1034
1033
1035
<h3>Step 1: Create Account</h3>
1034
1036
<ol>
1080
1082
<span class="breadcrumb-sep">/</span>
1081
1083
<span class="current">Using OpenGrammar</span>
1082
1084
</nav>
1083
- <h1>πŸ“– Using OpenGrammar</h1>
1085
+ <h1><i data-lucide="book-open" class="icon-inline"></i> Using OpenGrammar</h1>
1084
1086
<p class="section-description">Complete user guide to all features and functionality.</p>
1085
1087
</div>
1086
1088
<div class="content-body">
1087
- <h2>✍️ Grammar Checking</h2>
1089
+ <h2><i data-lucide="pen-tool" class="icon-inline"></i> Grammar Checking</h2>
1088
1090
1089
1091
<h3>Color-Coded Underlines</h3>
1090
1092
<div class="color-guide">
1119
1121
<li><strong>Apply Changes</strong> - Click Apply, Ignore, or Add to Dictionary</li>
1120
1122
</ol>
1121
1123
1122
- <h2>🎨 Tone Rewriting</h2>
1124
+ <h2><i data-lucide="palette" class="icon-inline"></i> Tone Rewriting</h2>
1123
1125
1124
1126
<h3>Available Tones</h3>
1125
1127
<div class="tone-grid">
1126
1128
<div class="tone-card">
1127
- <span class="tone-emoji">🎩</span>
1129
+ <span class="tone-emoji"><i data-lucide="briefcase" class="icon-inline"></i></span>
1128
1130
<h4>Formal</h4>
1129
1131
<p>Business, academic</p>
1130
1132
</div>
1131
1133
<div class="tone-card">
1132
- <span class="tone-emoji">😊</span>
1134
+ <span class="tone-emoji"><i data-lucide="smile" class="icon-inline"></i></span>
1133
1135
<h4>Casual</h4>
1134
1136
<p>Friends, chat</p>
1135
1137
</div>
1136
1138
<div class="tone-card">
1137
- <span class="tone-emoji">πŸ’Ό</span>
1139
+ <span class="tone-emoji"><i data-lucide="briefcase" class="icon-inline"></i></span>
1138
1140
<h4>Professional</h4>
1139
1141
<p>Work emails</p>
1140
1142
</div>
1141
1143
<div class="tone-card">
1142
- <span class="tone-emoji">πŸ€—</span>
1144
+ <span class="tone-emoji"><i data-lucide="heart-handshake" class="icon-inline"></i></span>
1143
1145
<h4>Friendly</h4>
1144
1146
<p>Social media</p>
1145
1147
</div>
1146
1148
<div class="tone-card">
1147
- <span class="tone-emoji">⚑</span>
1149
+ <span class="tone-emoji"><i data-lucide="zap" class="icon-inline"></i></span>
1148
1150
<h4>Concise</h4>
1149
1151
<p>Quick messages</p>
1150
1152
</div>
1151
1153
<div class="tone-card">
1152
- <span class="tone-emoji">πŸ“š</span>
1154
+ <span class="tone-emoji"><i data-lucide="library" class="icon-inline"></i></span>
1153
1155
<h4>Detailed</h4>
1154
1156
<p>Explanations</p>
1155
1157
</div>
1156
1158
<div class="tone-card">
1157
- <span class="tone-emoji">πŸ’ͺ</span>
1159
+ <span class="tone-emoji"><i data-lucide="dumbbell" class="icon-inline"></i></span>
1158
1160
<h4>Persuasive</h4>
1159
1161
<p>Sales, pitches</p>
1160
1162
</div>
1161
1163
<div class="tone-card">
1162
- <span class="tone-emoji">😐</span>
1164
+ <span class="tone-emoji"><i data-lucide="meh" class="icon-inline"></i></span>
1163
1165
<h4>Neutral</h4>
1164
1166
<p>General use</p>
1165
1167
</div>
1192
1194
<span class="breadcrumb-sep">/</span>
1193
1195
<span class="current">Tone Rewriting</span>
1194
1196
</nav>
1195
- <h1>🎨 Tone Rewriting</h1>
1197
+ <h1><i data-lucide="palette" class="icon-inline"></i> Tone Rewriting</h1>
1196
1198
<p class="section-description">Master the art of rewriting text in different tones.</p>
1197
1199
</div>
1198
1200
<div class="content-body">
1199
- <h2>🎭 Available Tones</h2>
1201
+ <h2><i data-lucide="smile-plus" class="icon-inline"></i> Available Tones</h2>
1200
1202
1201
1203
<div class="tone-detail-grid">
1202
1204
<div class="tone-detail-card">
1203
1205
<div class="tone-detail-header">
1204
- <span class="tone-detail-icon">🎩</span>
1206
+ <span class="tone-detail-icon"><i data-lucide="briefcase" class="icon-inline"></i></span>
1205
1207
<h3>Formal</h3>
1206
1208
</div>
1207
1209
<p class="tone-detail-use">Use for: Academic writing, business proposals, official communications</p>
1219
1221
1220
1222
<div class="tone-detail-card">
1221
1223
<div class="tone-detail-header">
1222
- <span class="tone-detail-icon">😊</span>
1224
+ <span class="tone-detail-icon"><i data-lucide="smile" class="icon-inline"></i></span>
1223
1225
<h3>Casual</h3>
1224
1226
</div>
1225
1227
<p class="tone-detail-use">Use for: Social media, text messages, informal emails</p>
1237
1239
1238
1240
<div class="tone-detail-card">
1239
1241
<div class="tone-detail-header">
1240
- <span class="tone-detail-icon">πŸ’Ό</span>
1242
+ <span class="tone-detail-icon"><i data-lucide="briefcase" class="icon-inline"></i></span>
1241
1243
<h3>Professional</h3>
1242
1244
</div>
1243
1245
<p class="tone-detail-use">Use for: Work emails, business communication, reports</p>
1254
1256
</div>
1255
1257
</div>
1256
1258
1257
- <h2>πŸš€ How to Use</h2>
1259
+ <h2><i data-lucide="rocket" class="icon-inline"></i> How to Use</h2>
1258
1260
1259
1261
<h3>Method 1: Right-Click Menu</h3>
1260
1262
<ol>
1299
1301
<span class="breadcrumb-sep">/</span>
1300
1302
<span class="current">Writing Statistics</span>
1301
1303
</nav>
1302
- <h1>πŸ“Š Writing Statistics</h1>
1304
+ <h1><i data-lucide="bar-chart-2" class="icon-inline"></i> Writing Statistics</h1>
1303
1305
<p class="section-description">Analyze and improve your writing with detailed statistics.</p>
1304
1306
</div>
1305
1307
<div class="content-body">
1306
- <h2>πŸ“ˆ Available Metrics</h2>
1308
+ <h2><i data-lucide="trending-up" class="icon-inline"></i> Available Metrics</h2>
1307
1309
1308
1310
<h3>Readability Scores</h3>
1309
1311
1435
1437
<span class="breadcrumb-sep">/</span>
1436
1438
<span class="current">Troubleshooting</span>
1437
1439
</nav>
1438
- <h1>πŸ”§ Troubleshooting</h1>
1440
+ <h1><i data-lucide="wrench" class="icon-inline"></i> Troubleshooting</h1>
1439
1441
<p class="section-description">Solve common OpenGrammar issues with this comprehensive guide.</p>
1440
1442
</div>
1441
1443
<div class="content-body">
1442
- <h2>πŸ” Common Issues</h2>
1444
+ <h2><i data-lucide="search" class="icon-inline"></i> Common Issues</h2>
1443
1445
1444
1446
<h3>No Grammar Highlights</h3>
1445
1447
<div class="troubleshoot-card">
1521
1523
<span class="breadcrumb-sep">/</span>
1522
1524
<span class="current">FAQ</span>
1523
1525
</nav>
1524
- <h1>❓ Frequently Asked Questions</h1>
1526
+ <h1><i data-lucide="help-circle" class="icon-inline"></i> Frequently Asked Questions</h1>
1525
1527
<p class="section-description">Common questions about OpenGrammar.</p>
1526
1528
</div>
1527
1529
<div class="content-body">
1613
1615
<span class="breadcrumb-sep">/</span>
1614
1616
<span class="current">API Reference</span>
1615
1617
</nav>
1616
- <h1>πŸ“š API Reference</h1>
1618
+ <h1><i data-lucide="library" class="icon-inline"></i> API Reference</h1>
1617
1619
<p class="section-description">Backend API documentation for developers.</p>
1618
1620
</div>
1619
1621
<div class="content-body">
1758
1760
1759
1761
<footer class="content-footer">
1760
1762
<div class="footer-content">
1761
- <p>Built with ❀️ by <a href="https://github.com/swadhinbiswas" target="_blank">Swadhin Biswas</a></p>
1763
+ <p>Built with <i data-lucide="heart" class="icon-inline"></i>️ by <a href="https://github.com/swadhinbiswas" target="_blank">Swadhin Biswas</a></p>
1762
1764
<p>OpenGrammar is licensed under <a href="https://opensource.org/licenses/Apache-2.0" target="_blank">Apache 2.0</a></p>
1763
1765
</div>
1764
1766
</footer>
1765
1767
</main>
1766
1768
1767
1769
<script src="script.js"></script>
1770
+
1771
+<script>
1772
+ lucide.createIcons();
1773
+</script>
1768
1774
</body>
1769
1775
</html>
1770
1776
β–Όdocs-site/script.js β†’ docs/script.js
+0-0
0
0
β–Όdocs-site/styles.css β†’ docs/styles.css
+22-0
93
93
--paper-border: #2A2D35;
94
94
--paper-text: #E8E6E3;
95
95
--paper-text-muted: #9CA3AF;
96
+
97
+ /* Semantic Colors Overrides for Dark Mode */
98
+ --primary-50: rgba(79, 102, 240, 0.1);
99
+ --primary-100: rgba(79, 102, 240, 0.2);
100
+ --amber-50: rgba(245, 158, 11, 0.1);
101
+ --amber-100: rgba(245, 158, 11, 0.2);
102
+ --red-50: rgba(239, 68, 68, 0.1);
103
+ --red-100: rgba(239, 68, 68, 0.2);
104
+ --green-50: rgba(34, 197, 94, 0.1);
105
+ --green-100: rgba(34, 197, 94, 0.2);
106
+ --blue-50: rgba(59, 130, 246, 0.1);
107
+ --blue-100: rgba(59, 130, 246, 0.2);
108
+ --purple-50: rgba(139, 92, 246, 0.1);
109
+ --purple-100: rgba(139, 92, 246, 0.2);
96
110
}
97
111
98
112
/* Reset & Base */
102
116
padding: 0;
103
117
}
104
118
119
+.icon-inline {
120
+ display: inline-block;
121
+ vertical-align: middle;
122
+ width: 1.25em;
123
+ height: 1.25em;
124
+ margin-top: -0.2em;
125
+}
126
+
105
127
html {
106
128
scroll-behavior: smooth;
107
129
-webkit-font-smoothing: antialiased;
108
130
β–Όindex.html
+513-494
1
1
<!DOCTYPE html>
2
-<html lang="en" class="scroll-smooth">
2
+<html lang="en">
3
3
<head>
4
4
<meta charset="UTF-8">
5
5
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>OpenGrammar | The Free, Privacy-First Grammarly Alternative</title>
7
- <meta name="description" content="OpenGrammar is a powerful, open-source, and self-hostable browser extension for grammar, spelling, and tone adjustments. Complete privacy and zero monthly fees.">
8
- <meta name="keywords" content="OpenGrammar, Grammarly alternative, open source grammar checker, privacy writing assistant, AI writer">
6
+ <title>OpenGrammar β€” The Free, Privacy-First Writing Assistant</title>
7
+ <meta name="description" content="OpenGrammar is a powerful, open-source browser extension for grammar, spelling, and tone adjustments. Complete privacy. Zero monthly fees. Self-hostable.">
8
+ <meta name="keywords" content="OpenGrammar, Grammarly alternative, open source grammar checker, privacy writing assistant, AI grammar">
9
9
<meta name="author" content="Swadhin Biswas">
10
-
11
- <!-- Open Graph / Social Media -->
12
- <meta property="og:title" content="OpenGrammar | Privacy-First Writing Assistant">
13
- <meta property="og:description" content="Take back your privacy. OpenGrammar offers local grammar checking and bring-your-own-AI capabilities with zero monthly fees.">
10
+ <meta property="og:title" content="OpenGrammar β€” Privacy-First Writing Assistant">
11
+ <meta property="og:description" content="Free, open-source Grammarly alternative. Local grammar checking + bring-your-own AI. Zero subscriptions.">
14
12
<meta property="og:type" content="website">
15
13
<meta property="og:image" content="https://raw.githubusercontent.com/swadhinbiswas/opengrammar/main/logo.svg">
16
-
17
- <!-- Tailwind CSS -->
18
- <script src="https://cdn.tailwindcss.com"></script>
19
- <script>
20
- tailwind.config = {
21
- darkMode: 'class',
22
- theme: {
23
- extend: {
24
- colors: {
25
- primary: {
26
- 50: '#eff6ff',
27
- 100: '#dbeafe',
28
- 200: '#bfdbfe',
29
- 300: '#93c5fd',
30
- 400: '#60a5fa',
31
- 500: '#3b82f6',
32
- 600: '#2563eb',
33
- 700: '#1d4ed8',
34
- 800: '#1e40af',
35
- 900: '#1e3a8a',
36
- },
37
- dark: {
38
- 50: '#f8fafc',
39
- 100: '#f1f5f9',
40
- 200: '#e2e8f0',
41
- 300: '#cbd5e1',
42
- 400: '#94a3b8',
43
- 500: '#64748b',
44
- 600: '#475569',
45
- 700: '#334155',
46
- 800: '#1e293b',
47
- 900: '#0f172a',
48
- }
49
- }
50
- }
51
- }
52
- }
53
- </script>
14
+ <link rel="icon" href="logo.svg" type="image/svg+xml">
15
+ <link rel="preconnect" href="https://fonts.googleapis.com">
16
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
54
18
<style>
55
- .gradient-text {
56
- background-clip: text;
57
- -webkit-background-clip: text;
58
- -webkit-text-fill-color: transparent;
59
- background-image: linear-gradient(90deg, #3B82F6, #8B5CF6);
60
- }
61
- .dark .gradient-text {
62
- background-image: linear-gradient(90deg, #60A5FA, #A78BFA);
63
- }
64
- .hero-pattern {
65
- background-color: #f8fafc;
66
- background-image: radial-gradient(#cbd5e1 1px, transparent 1px);
67
- background-size: 20px 20px;
68
- }
69
- .dark .hero-pattern {
70
- background-color: #0f172a;
71
- background-image: radial-gradient(#334155 1px, transparent 1px);
72
- }
73
- /* Smooth transitions */
74
- * {
75
- transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
76
- }
77
- /* Custom scrollbar */
78
- ::-webkit-scrollbar {
79
- width: 10px;
80
- }
81
- ::-webkit-scrollbar-track {
82
- background: #f1f5f9;
83
- }
84
- .dark ::-webkit-scrollbar-track {
85
- background: #1e293b;
86
- }
87
- ::-webkit-scrollbar-thumb {
88
- background: #94a3b8;
89
- border-radius: 5px;
90
- }
91
- ::-webkit-scrollbar-thumb:hover {
92
- background: #64748b;
93
- }
19
+/* ========== RESET & TOKENS ========== */
20
+*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
21
+:root{
22
+ --bg:#fdfbf7;--bg2:#f4f1eb;--bg3:#eae7e0;
23
+ --fg:#1a1816;--fg2:#4a4640;--fg3:#7a756e;
24
+ --primary:#4f46e5;--primary-l:#818cf8;--primary-d:#3730a3;
25
+ --accent:#7c3aed;--accent-l:#a78bfa;
26
+ --green:#059669;--green-bg:#ecfdf5;
27
+ --red:#dc2626;--red-bg:#fef2f2;
28
+ --amber:#d97706;--amber-bg:#fffbeb;
29
+ --blue:#2563eb;--blue-bg:#eff6ff;
30
+ --border:#e5e1d8;--card-bg:rgba(255,255,255,.72);
31
+ --radius:16px;--radius-sm:10px;
32
+ --font:'Inter',system-ui,sans-serif;--mono:'JetBrains Mono',monospace;
33
+ --shadow:0 4px 24px rgba(0,0,0,.06);
34
+ --shadow-lg:0 20px 60px rgba(0,0,0,.1);
35
+ --transition:.3s cubic-bezier(.4,0,.2,1);
36
+ --nav-h:72px;
37
+}
38
+[data-theme="dark"]{
39
+ --bg:#0c0a14;--bg2:#14111f;--bg3:#1e1a2e;
40
+ --fg:#eae8f0;--fg2:#b0adb8;--fg3:#76737e;
41
+ --border:#2a2640;--card-bg:rgba(20,17,31,.72);
42
+ --shadow:0 4px 24px rgba(0,0,0,.3);
43
+ --shadow-lg:0 20px 60px rgba(0,0,0,.4);
44
+ --primary:#818cf8;--primary-l:#a5b4fc;--primary-d:#6366f1;
45
+ --accent:#a78bfa;--accent-l:#c4b5fd;
46
+ --green:#34d399;--green-bg:rgba(5,150,105,.12);
47
+ --red:#f87171;--red-bg:rgba(220,38,38,.12);
48
+ --amber:#fbbf24;--amber-bg:rgba(217,119,6,.12);
49
+ --blue:#60a5fa;--blue-bg:rgba(37,99,235,.12);
50
+}
51
+html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased}
52
+body{font-family:var(--font);color:var(--fg);background:var(--bg);overflow-x:hidden;line-height:1.6}
53
+a{color:inherit;text-decoration:none}
54
+img{display:block;max-width:100%}
55
+button{font-family:inherit;cursor:pointer}
56
+
57
+/* ========== UTILITIES ========== */
58
+.container{max-width:1200px;margin:0 auto;padding:0 24px}
59
+.icon-inline {display: inline-block; vertical-align: middle; width: 1.25em; height: 1.25em; margin-top: -0.2em;}
60
+.gradient-text{background:linear-gradient(135deg,var(--primary),var(--accent));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
61
+.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
62
+
63
+/* ========== ANIMATED BACKGROUND ========== */
64
+.hero-bg{position:absolute;inset:0;overflow:hidden;z-index:0;pointer-events:none}
65
+.hero-bg .orb{position:absolute;border-radius:50%;filter:blur(80px);opacity:.35;animation:float 20s ease-in-out infinite}
66
+[data-theme="dark"] .hero-bg .orb{opacity:.2}
67
+.orb-1{width:600px;height:600px;background:var(--primary);top:-200px;left:-100px;animation-delay:0s}
68
+.orb-2{width:500px;height:500px;background:var(--accent);top:100px;right:-150px;animation-delay:-7s}
69
+.orb-3{width:400px;height:400px;background:#06b6d4;bottom:-100px;left:30%;animation-delay:-14s}
70
+@keyframes float{0%,100%{transform:translate(0,0) scale(1)}33%{transform:translate(30px,-40px) scale(1.05)}66%{transform:translate(-20px,30px) scale(.95)}}
71
+
72
+/* ========== GRID PATTERN ========== */
73
+.grid-pattern{position:absolute;inset:0;background-image:
74
+ linear-gradient(var(--border) 1px,transparent 1px),
75
+ linear-gradient(90deg,var(--border) 1px,transparent 1px);
76
+ background-size:64px 64px;opacity:.35;pointer-events:none;mask-image:radial-gradient(ellipse 60% 50% at 50% 0%,#000 70%,transparent 100%)}
77
+[data-theme="dark"] .grid-pattern{opacity:.15}
78
+
79
+/* ========== NAVBAR ========== */
80
+.navbar{position:fixed;top:0;left:0;right:0;height:var(--nav-h);z-index:1000;
81
+ background:rgba(253,251,247,.8);backdrop-filter:blur(16px) saturate(180%);
82
+ border-bottom:1px solid var(--border);transition:background var(--transition)}
83
+[data-theme="dark"] .navbar{background:rgba(12,10,20,.8)}
84
+.navbar .container{display:flex;align-items:center;height:100%;gap:32px}
85
+.nav-logo{display:flex;align-items:center;gap:10px;font-weight:800;font-size:18px;letter-spacing:-.02em}
86
+.nav-logo img{width:32px;height:32px}
87
+.nav-links{display:flex;gap:6px;margin-left:auto}
88
+.nav-links a{padding:8px 16px;border-radius:var(--radius-sm);font-size:14px;font-weight:500;color:var(--fg2);transition:all var(--transition)}
89
+.nav-links a:hover{color:var(--fg);background:var(--bg2)}
90
+.nav-actions{display:flex;align-items:center;gap:10px}
91
+.btn{display:inline-flex;align-items:center;gap:8px;padding:10px 22px;border-radius:var(--radius-sm);font-weight:600;font-size:14px;border:none;transition:all var(--transition)}
92
+.btn-primary{background:var(--primary);color:#fff;box-shadow:0 4px 16px rgba(79,70,229,.3)}
93
+.btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(79,70,229,.4)}
94
+.btn-ghost{background:transparent;border:1px solid var(--border);color:var(--fg)}
95
+.btn-ghost:hover{background:var(--bg2);border-color:var(--fg3)}
96
+.theme-btn{width:40px;height:40px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg2);display:flex;align-items:center;justify-content:center;color:var(--fg2);transition:all var(--transition)}
97
+.theme-btn:hover{color:var(--fg);border-color:var(--fg3)}
98
+.theme-btn svg{width:18px;height:18px}
99
+.sun-icon{display:none}
100
+[data-theme="dark"] .moon-icon{display:none}
101
+[data-theme="dark"] .sun-icon{display:block}
102
+.mobile-toggle{display:none;width:40px;height:40px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg2);align-items:center;justify-content:center;color:var(--fg2)}
103
+.mobile-toggle svg{width:20px;height:20px}
104
+
105
+/* ========== HERO ========== */
106
+.hero{position:relative;padding:calc(var(--nav-h) + 80px) 0 100px;text-align:center;overflow:hidden;min-height:90vh;display:flex;align-items:center}
107
+.hero-content{position:relative;z-index:1}
108
+.hero-badge{display:inline-flex;align-items:center;gap:8px;padding:6px 16px 6px 8px;border-radius:999px;background:var(--card-bg);border:1px solid var(--border);backdrop-filter:blur(8px);font-size:13px;font-weight:600;color:var(--fg2);margin-bottom:32px}
109
+.hero-badge .dot{width:8px;height:8px;border-radius:50%;background:var(--green);animation:pulse 2s ease-in-out infinite}
110
+@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.8)}}
111
+.hero h1{font-size:clamp(40px,6vw,76px);font-weight:900;line-height:1.08;letter-spacing:-.03em;margin-bottom:24px;max-width:800px;margin-inline:auto}
112
+.hero p{font-size:clamp(16px,2vw,20px);color:var(--fg2);max-width:600px;margin:0 auto 40px;line-height:1.7}
113
+.hero-buttons{display:flex;gap:14px;justify-content:center;flex-wrap:wrap}
114
+.hero-buttons .btn{padding:14px 28px;font-size:16px;border-radius:12px}
115
+
116
+/* ========== LIVE DEMO MOCKUP ========== */
117
+.demo-section{position:relative;z-index:1;max-width:860px;margin:-20px auto 0;perspective:1200px}
118
+.demo-card{background:var(--card-bg);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow-lg);overflow:hidden;transform:rotateX(2deg);transition:transform .6s ease}
119
+.demo-card:hover{transform:rotateX(0deg)}
120
+.demo-bar{display:flex;align-items:center;gap:8px;padding:14px 20px;background:var(--bg2);border-bottom:1px solid var(--border)}
121
+.demo-dot{width:12px;height:12px;border-radius:50%}
122
+.demo-dot.r{background:#f87171}.demo-dot.y{background:#fbbf24}.demo-dot.g{background:#34d399}
123
+.demo-bar span{margin-left:auto;font-size:12px;color:var(--fg3);font-family:var(--mono)}
124
+.demo-body{padding:32px 40px;font-size:17px;line-height:1.9;color:var(--fg)}
125
+.demo-body .err{border-bottom:2.5px wavy var(--red);padding-bottom:2px;cursor:pointer;position:relative}
126
+.demo-body .warn{border-bottom:2.5px wavy var(--amber);padding-bottom:2px;cursor:pointer}
127
+.demo-body .style-h{border-bottom:2.5px wavy var(--blue);padding-bottom:2px;cursor:pointer}
128
+.demo-tooltip{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:12px 16px;box-shadow:var(--shadow-lg);white-space:nowrap;font-size:13px;opacity:0;pointer-events:none;transition:opacity .2s}
129
+.err:hover .demo-tooltip{opacity:1}
130
+.demo-tooltip strong{color:var(--red);display:block;font-size:12px;margin-bottom:4px}
131
+.demo-badge-row{display:flex;gap:12px;padding:16px 40px;border-top:1px solid var(--border);background:var(--bg2)}
132
+.demo-badge-row .dbadge{display:flex;align-items:center;gap:6px;padding:5px 12px;border-radius:999px;font-size:12px;font-weight:600}
133
+.dbadge.red{background:var(--red-bg);color:var(--red)}
134
+.dbadge.amber{background:var(--amber-bg);color:var(--amber)}
135
+.dbadge.blue{background:var(--blue-bg);color:var(--blue)}
136
+
137
+/* ========== SECTION COMMON ========== */
138
+section{padding:100px 0}
139
+.section-label{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--primary);margin-bottom:16px}
140
+.section-title{font-size:clamp(28px,4vw,44px);font-weight:800;letter-spacing:-.02em;line-height:1.15;margin-bottom:16px}
141
+.section-desc{font-size:17px;color:var(--fg2);max-width:560px;line-height:1.7}
142
+.section-desc.center{margin-inline:auto;text-align:center}
143
+.section-header{text-align:center;margin-bottom:64px}
144
+
145
+/* ========== FEATURES ========== */
146
+.features-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
147
+.feature-card{padding:32px;border-radius:var(--radius);border:1px solid var(--border);background:var(--card-bg);backdrop-filter:blur(10px);transition:all var(--transition)}
148
+.feature-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg);border-color:var(--primary-l)}
149
+.feature-icon{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:22px;margin-bottom:20px}
150
+.feature-icon.privacy{background:var(--green-bg);color:var(--green)}
151
+.feature-icon.ai{background:rgba(124,58,237,.12);color:var(--accent)}
152
+.feature-icon.self-host{background:var(--blue-bg);color:var(--blue)}
153
+.feature-icon.rules{background:var(--amber-bg);color:var(--amber)}
154
+.feature-icon.rewrite{background:rgba(79,70,229,.1);color:var(--primary)}
155
+.feature-icon.stats{background:rgba(6,182,212,.1);color:#0891b2}
156
+.feature-card h3{font-size:18px;font-weight:700;margin-bottom:10px}
157
+.feature-card p{font-size:15px;color:var(--fg2);line-height:1.65}
158
+
159
+/* ========== HOW IT WORKS ========== */
160
+.how-grid{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
161
+.how-steps{display:flex;flex-direction:column;gap:28px}
162
+.how-step{display:flex;gap:20px;align-items:flex-start}
163
+.step-num{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:16px;color:#fff;flex-shrink:0}
164
+.step-num.s1{background:linear-gradient(135deg,var(--primary),var(--accent))}
165
+.step-num.s2{background:linear-gradient(135deg,var(--accent),#ec4899)}
166
+.step-num.s3{background:linear-gradient(135deg,#06b6d4,var(--green))}
167
+.how-step h4{font-size:17px;font-weight:700;margin-bottom:4px}
168
+.how-step p{font-size:15px;color:var(--fg2);line-height:1.6}
169
+.how-visual{background:var(--card-bg);backdrop-filter:blur(10px);border:1px solid var(--border);border-radius:var(--radius);padding:32px;box-shadow:var(--shadow)}
170
+.stat-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px}
171
+.stat-box{padding:20px;border-radius:var(--radius-sm);background:var(--bg2);border:1px solid var(--border)}
172
+.stat-box .label{font-size:12px;color:var(--fg3);font-weight:600;text-transform:uppercase;letter-spacing:.04em;margin-bottom:6px}
173
+.stat-box .value{font-size:28px;font-weight:800}
174
+.stat-box .value.purple{color:var(--accent)}
175
+.stat-box .value.blue{color:var(--blue)}
176
+.progress-bar{margin-top:8px}
177
+.progress-bar .bar-label{display:flex;justify-content:space-between;font-size:13px;font-weight:600;margin-bottom:6px}
178
+.progress-bar .bar-track{height:8px;border-radius:99px;background:var(--bg3)}
179
+.progress-bar .bar-fill{height:100%;border-radius:99px;background:linear-gradient(90deg,var(--green),#34d399);transition:width 1s ease}
180
+
181
+/* ========== PROVIDERS ========== */
182
+.providers-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
183
+.provider-card{padding:28px;border-radius:var(--radius);border:1px solid var(--border);background:var(--card-bg);backdrop-filter:blur(10px);transition:all var(--transition)}
184
+.provider-card:hover{transform:translateY(-3px);box-shadow:var(--shadow)}
185
+.provider-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
186
+.provider-head h3{font-size:18px;font-weight:700}
187
+.provider-tag{padding:4px 12px;border-radius:999px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}
188
+.provider-tag.free{background:var(--green-bg);color:var(--green)}
189
+.provider-tag.quality{background:var(--blue-bg);color:var(--blue)}
190
+.provider-tag.private{background:rgba(124,58,237,.12);color:var(--accent)}
191
+.provider-card .desc{font-size:14px;color:var(--fg2);margin-bottom:16px}
192
+.check-list{list-style:none;display:flex;flex-direction:column;gap:8px}
193
+.check-list li{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--fg2)}
194
+.check-list li::before{content:"<i data-lucide="check" class="icon-inline"></i>";width:20px;height:20px;border-radius:50%;background:var(--green-bg);color:var(--green);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;flex-shrink:0}
195
+
196
+/* ========== COMPARISON TABLE ========== */
197
+.compare{background:var(--bg2);border-top:1px solid var(--border);border-bottom:1px solid var(--border)}
198
+.compare-table{width:100%;border-collapse:collapse;border-radius:var(--radius);overflow:hidden;border:1px solid var(--border);background:var(--card-bg);backdrop-filter:blur(10px)}
199
+.compare-table th,.compare-table td{padding:16px 24px;text-align:left;border-bottom:1px solid var(--border);font-size:15px}
200
+.compare-table thead th{background:var(--bg2);font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:.05em;color:var(--fg3)}
201
+.compare-table tr:last-child td{border-bottom:none}
202
+.compare-table .yes{color:var(--green);font-weight:600}
203
+.compare-table .no{color:var(--red);font-weight:600}
204
+.compare-table .highlight-col{background:rgba(79,70,229,.04)}
205
+[data-theme="dark"] .compare-table .highlight-col{background:rgba(129,140,248,.06)}
206
+
207
+/* ========== GET STARTED ========== */
208
+.get-started{text-align:center}
209
+.terminal{max-width:680px;margin:0 auto;background:var(--bg3);border-radius:var(--radius);overflow:hidden;text-align:left;border:1px solid var(--border);box-shadow:var(--shadow-lg)}
210
+[data-theme="dark"] .terminal{background:#1a1726}
211
+.terminal-bar{display:flex;gap:8px;padding:14px 20px;background:var(--bg2);border-bottom:1px solid var(--border)}
212
+.terminal pre{padding:24px;font-family:var(--mono);font-size:14px;line-height:1.8;overflow-x:auto;color:var(--fg)}
213
+.terminal .comment{color:var(--fg3)}
214
+.terminal .cmd{color:var(--primary-l)}
215
+.cta-buttons{display:flex;gap:14px;justify-content:center;margin-top:40px;flex-wrap:wrap}
216
+
217
+/* ========== FOOTER ========== */
218
+.footer{background:var(--bg2);border-top:1px solid var(--border);padding:64px 0 32px}
219
+.footer-grid{display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:48px;margin-bottom:48px}
220
+.footer-brand p{color:var(--fg2);font-size:14px;margin-top:12px;max-width:280px;line-height:1.6}
221
+.footer-col h4{font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--fg3);margin-bottom:16px}
222
+.footer-col a{display:block;font-size:14px;color:var(--fg2);padding:4px 0;transition:color var(--transition)}
223
+.footer-col a:hover{color:var(--primary)}
224
+.footer-bottom{display:flex;justify-content:space-between;align-items:center;padding-top:32px;border-top:1px solid var(--border);font-size:13px;color:var(--fg3)}
225
+.footer-bottom-links{display:flex;gap:24px}
226
+.footer-bottom-links a{color:var(--fg3);transition:color var(--transition)}
227
+.footer-bottom-links a:hover{color:var(--fg)}
228
+
229
+/* ========== RESPONSIVE ========== */
230
+@media(max-width:1024px){
231
+ .features-grid,.providers-grid{grid-template-columns:repeat(2,1fr)}
232
+ .how-grid{grid-template-columns:1fr;gap:40px}
233
+ .footer-grid{grid-template-columns:1fr 1fr}
234
+}
235
+@media(max-width:768px){
236
+ .nav-links{display:none}
237
+ .mobile-toggle{display:flex}
238
+ .features-grid,.providers-grid{grid-template-columns:1fr}
239
+ .hero{padding-top:calc(var(--nav-h) + 48px);padding-bottom:64px;min-height:auto}
240
+ .demo-body{padding:24px}
241
+ .demo-badge-row{padding:12px 24px;flex-wrap:wrap}
242
+ .compare-table{font-size:13px}
243
+ .compare-table th,.compare-table td{padding:12px 14px}
244
+ .footer-grid{grid-template-columns:1fr}
245
+ section{padding:64px 0}
246
+ .section-title{font-size:28px}
247
+ .container{padding:0 16px}
248
+ .content-wrapper{padding:24px}
249
+ .hero-buttons .btn{width:100%}
250
+}
251
+
252
+/* ========== MOBILE MENU ========== */
253
+.mobile-menu{display:none;position:fixed;top:var(--nav-h);left:0;right:0;background:var(--bg);border-bottom:1px solid var(--border);padding:16px 24px;z-index:999;flex-direction:column;gap:8px}
254
+.mobile-menu.open{display:flex}
255
+.mobile-menu a{padding:12px 16px;border-radius:var(--radius-sm);font-size:15px;font-weight:500;color:var(--fg2);transition:all var(--transition)}
256
+.mobile-menu a:hover{background:var(--bg2);color:var(--fg)}
257
+
258
+/* ========== ANIMATIONS ========== */
259
+.fade-in{opacity:0;transform:translateY(24px);transition:opacity .6s ease,transform .6s ease}
260
+.fade-in.visible{opacity:1;transform:translateY(0)}
94
261
</style>
262
+ <!-- Lucide Icons -->
263
+ <script src="https://unpkg.com/lucide@latest"></script>
95
264
</head>
96
-<body class="font-sans antialiased text-gray-900 bg-white dark:bg-dark-900 dark:text-gray-100">
97
-
98
- <!-- Navigation -->
99
- <nav class="fixed w-full z-50 bg-white/80 dark:bg-dark-800/80 backdrop-blur-md border-b border-gray-100 dark:border-dark-700">
100
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
101
- <div class="flex justify-between items-center h-16">
102
- <div class="flex items-center gap-2">
103
- <img src="logo.svg" alt="OpenGrammar Logo" class="h-8 w-8">
104
- <span class="font-bold text-xl tracking-tight text-gray-900 dark:text-gray-100">OpenGrammar</span>
105
- </div>
106
- <div class="hidden md:flex space-x-8 items-center">
107
- <a href="#features" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition">Features</a>
108
- <a href="#how-it-works" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition">How it Works</a>
109
- <a href="#providers" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition">AI Providers</a>
110
- <a href="#docs" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition">Docs</a>
111
- <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition">GitHub</a>
112
-
113
- <!-- Dark Mode Toggle -->
114
- <button id="theme-toggle" class="p-2 rounded-lg bg-gray-100 dark:bg-dark-700 hover:bg-gray-200 dark:hover:bg-dark-600 transition" aria-label="Toggle dark mode">
115
- <!-- Sun icon -->
116
- <svg id="theme-toggle-light-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
117
- <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path>
118
- </svg>
119
- <!-- Moon icon -->
120
- <svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
121
- <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
122
- </svg>
123
- </button>
124
-
125
- <a href="#get-started" class="bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-600 text-white px-5 py-2 rounded-full font-medium transition shadow-lg shadow-primary-500/30">Get Started</a>
126
- </div>
127
-
128
- <!-- Mobile menu button -->
129
- <div class="md:hidden flex items-center gap-4">
130
- <button id="mobile-theme-toggle" class="p-2 rounded-lg bg-gray-100 dark:bg-dark-700 hover:bg-gray-200 dark:hover:bg-dark-600 transition" aria-label="Toggle dark mode">
131
- <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
132
- <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
133
- </svg>
134
- </button>
135
- <button id="mobile-menu-button" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400">
136
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
137
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
138
- </svg>
139
- </button>
140
- </div>
265
+<body>
266
+ <!-- Navbar -->
267
+ <nav class="navbar" id="navbar">
268
+ <div class="container">
269
+ <a href="#" class="nav-logo">
270
+ <img src="logo.svg" alt="OpenGrammar Logo">
271
+ <span>OpenGrammar</span>
272
+ </a>
273
+ <div class="nav-links">
274
+ <a href="#features">Features</a>
275
+ <a href="#how-it-works">How it Works</a>
276
+ <a href="#providers">Providers</a>
277
+ <a href="#comparison">Compare</a>
278
+ <a href="docs/index.html">Docs</a>
279
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank">GitHub</a>
141
280
</div>
142
- </div>
143
-
144
- <!-- Mobile menu -->
145
- <div id="mobile-menu" class="hidden md:hidden bg-white dark:bg-dark-800 border-t border-gray-100 dark:border-dark-700">
146
- <div class="px-4 py-4 space-y-4">
147
- <a href="#features" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium">Features</a>
148
- <a href="#how-it-works" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium">How it Works</a>
149
- <a href="#providers" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium">AI Providers</a>
150
- <a href="#docs" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium">Docs</a>
151
- <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 font-medium">GitHub</a>
152
- <a href="#get-started" class="block bg-primary-600 hover:bg-primary-700 text-white px-5 py-3 rounded-full font-medium text-center">Get Started</a>
281
+ <div class="nav-actions">
282
+ <button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
283
+ <svg class="moon-icon" viewBox="0 0 20 20" fill="currentColor"><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/></svg>
284
+ <svg class="sun-icon" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"/></svg>
285
+ </button>
286
+ <a href="#get-started" class="btn btn-primary">Get Started</a>
153
287
</div>
288
+ <button class="mobile-toggle" id="mobileToggle" aria-label="Menu">
289
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
290
+ </button>
154
291
</div>
155
292
</nav>
293
+ <div class="mobile-menu" id="mobileMenu">
294
+ <a href="#features">Features</a>
295
+ <a href="#how-it-works">How it Works</a>
296
+ <a href="#providers">Providers</a>
297
+ <a href="#comparison">Compare</a>
298
+ <a href="docs/index.html">Docs</a>
299
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank">GitHub</a>
300
+ <a href="#get-started" class="btn btn-primary" style="text-align:center;margin-top:8px">Get Started</a>
301
+ </div>
156
302
157
- <!-- Hero Section -->
158
- <section class="hero-pattern pt-32 pb-20 lg:pt-48 lg:pb-32 overflow-hidden">
159
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
160
- <div class="text-center max-w-3xl mx-auto">
161
- <div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary-50 dark:bg-primary-900/30 border border-primary-100 dark:border-primary-800 text-primary-600 dark:text-primary-400 text-sm font-semibold mb-6">
162
- <span class="flex h-2 w-2 rounded-full bg-primary-600"></span>
163
- v2.1 Now Available
164
- </div>
165
- <h1 class="text-5xl md:text-7xl font-extrabold tracking-tight mb-6 leading-tight">
166
- Write with confidence.<br>
167
- <span class="gradient-text">Keep your privacy.</span>
168
- </h1>
169
- <p class="text-xl text-gray-600 dark:text-gray-300 mb-10 leading-relaxed">
170
- OpenGrammar is the free, open-source Grammarly alternative. Run local rule-based checks offline, or plug in your own AI API key for advanced edits without paying monthly subscriptions.
171
- </p>
172
- <div class="flex flex-col sm:flex-row justify-center gap-4">
173
- <a href="#get-started" class="bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-600 text-white px-8 py-4 rounded-full font-bold text-lg transition shadow-xl shadow-primary-600/20 flex items-center justify-center gap-2">
174
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
175
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
176
- </svg>
177
- Download Extension
178
- </a>
179
- <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="bg-white dark:bg-dark-800 hover:bg-gray-50 dark:hover:bg-dark-700 text-gray-800 dark:text-gray-200 border border-gray-200 dark:border-dark-600 px-8 py-4 rounded-full font-bold text-lg transition shadow-sm flex items-center justify-center gap-2">
180
- <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
181
- <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path>
182
- </svg>
183
- View Source
184
- </a>
185
- </div>
303
+ <!-- Hero -->
304
+ <section class="hero">
305
+ <div class="hero-bg">
306
+ <div class="orb orb-1"></div>
307
+ <div class="orb orb-2"></div>
308
+ <div class="orb orb-3"></div>
309
+ <div class="grid-pattern"></div>
310
+ </div>
311
+ <div class="container hero-content">
312
+ <div class="hero-badge"><span class="dot"></span> v2.1 β€” Open Source & Free Forever</div>
313
+ <h1>Write with clarity.<br><span class="gradient-text">Own your privacy.</span></h1>
314
+ <p>OpenGrammar is the free, open-source Grammarly alternative. 40+ grammar rules run offline. Plug in your AI API key for advanced edits β€” no subscriptions, no data harvesting.</p>
315
+ <div class="hero-buttons">
316
+ <a href="#get-started" class="btn btn-primary">
317
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
318
+ Download Extension
319
+ </a>
320
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="btn btn-ghost">
321
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/></svg>
322
+ Star on GitHub
323
+ </a>
186
324
</div>
187
325
188
- <!-- Mockup image -->
189
- <div class="mt-16 relative max-w-5xl mx-auto rounded-xl shadow-2xl overflow-hidden border border-gray-200 dark:border-dark-700">
190
- <div class="bg-gray-100 dark:bg-dark-800 px-4 py-3 border-b border-gray-200 dark:border-dark-700 flex items-center gap-2">
191
- <div class="w-3 h-3 rounded-full bg-red-400"></div>
192
- <div class="w-3 h-3 rounded-full bg-yellow-400"></div>
193
- <div class="w-3 h-3 rounded-full bg-green-400"></div>
194
- </div>
195
- <div class="bg-white dark:bg-dark-900 p-8">
196
- <p class="text-lg text-gray-700 dark:text-gray-300 leading-relaxed font-serif">
197
- Most popular grammar assistants require you to send every keystroke to their servers and <span class="border-b-2 border-red-400 pb-1 cursor-pointer hover:bg-red-50 dark:hover:bg-red-900/20 relative group">charge a hefty monthly fee<div class="absolute bottom-full left-0 mb-2 hidden group-hover:block w-48 bg-white dark:bg-dark-800 border shadow-lg rounded p-2 text-sm z-10"><span class="block text-red-600 dark:text-red-400 font-bold mb-1">ClichΓ©</span>Consider "are expensive" instead.</div></span> for advanced features. OpenGrammar changes that. The core engine runs locally in your browser, checking for passive voice and <span class="border-b-2 border-blue-400 pb-1 cursor-pointer hover:bg-blue-50 dark:hover:bg-blue-900/20 relative group">repetition<div class="absolute bottom-full left-0 mb-2 hidden group-hover:block w-48 bg-white dark:bg-dark-800 border shadow-lg rounded p-2 text-sm z-10"><span class="block text-blue-600 dark:text-blue-400 font-bold mb-1">Repetition</span>You used this word 3 times recently.</div></span> without needing a server.
198
- </p>
326
+ <!-- Live Demo -->
327
+ <div class="demo-section" style="margin-top:56px">
328
+ <div class="demo-card">
329
+ <div class="demo-bar">
330
+ <div class="demo-dot r"></div><div class="demo-dot y"></div><div class="demo-dot g"></div>
331
+ <span>compose β€” Gmail</span>
332
+ </div>
333
+ <div class="demo-body">
334
+ Most popular grammar assistants require you to send every keystroke to their servers and <span class="err">charge a hefty monthly fee<span class="demo-tooltip"><strong><i data-lucide="alert-circle" class="icon-inline"></i> ClichΓ© Detected</strong>Consider "are expensive" instead.</span></span> for advanced features. OpenGrammar changes that. The core engine runs locally in your browser, checking for <span class="style-h">passive voice</span> and <span class="warn">repetition</span> without needing a server.
335
+ </div>
336
+ <div class="demo-badge-row">
337
+ <span class="dbadge red">● 1 Grammar</span>
338
+ <span class="dbadge amber">● 1 Clarity</span>
339
+ <span class="dbadge blue">● 1 Style</span>
340
+ </div>
199
341
</div>
200
342
</div>
201
343
</div>
202
344
</section>
203
345
204
346
<!-- Features -->
205
- <section id="features" class="py-20 bg-white dark:bg-dark-900">
206
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
207
- <div class="text-center mb-16">
208
- <h2 class="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Everything you need, nothing you don't.</h2>
209
- <p class="text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">Designed for developers, writers, and privacy advocates who want complete control over their writing environment.</p>
347
+ <section id="features" style="background:var(--bg2);border-top:1px solid var(--border)">
348
+ <div class="container">
349
+ <div class="section-header fade-in">
350
+ <div class="section-label"><i data-lucide="sparkles" class="icon-inline"></i> Features</div>
351
+ <h2 class="section-title">Everything you need.<br>Nothing you don't.</h2>
352
+ <p class="section-desc center">Built for developers, writers, and privacy advocates who want complete control over their writing tools.</p>
210
353
</div>
211
-
212
- <div class="grid md:grid-cols-3 gap-10">
213
- <!-- Feature 1 -->
214
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
215
- <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded-xl flex items-center justify-center mb-6">
216
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
217
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
218
- </svg>
219
- </div>
220
- <h3 class="text-xl font-bold mb-3">Absolute Privacy</h3>
221
- <p class="text-gray-600 dark:text-gray-300">No databases, no user accounts. The local engine runs offline. AI requests are sent to a stateless edge function and immediately forgotten.</p>
354
+ <div class="features-grid">
355
+ <div class="feature-card fade-in">
356
+ <div class="feature-icon privacy"><i data-lucide="lock" class="icon-inline"></i></div>
357
+ <h3>Absolute Privacy</h3>
358
+ <p>No databases, no accounts, no tracking. The local engine runs fully offline. AI requests use a stateless edge function β€” text is never stored.</p>
222
359
</div>
223
- <!-- Feature 2 -->
224
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
225
- <div class="w-12 h-12 bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-xl flex items-center justify-center mb-6">
226
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
227
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
228
- </svg>
229
- </div>
230
- <h3 class="text-xl font-bold mb-3">Bring Your Own AI</h3>
231
- <p class="text-gray-600 dark:text-gray-300">Paste in your API key for OpenAI, Groq, OpenRouter, or Together. Pay fractions of a cent per month directly to the provider instead of a $12/mo subscription.</p>
360
+ <div class="feature-card fade-in">
361
+ <div class="feature-icon ai"><i data-lucide="key" class="icon-inline"></i></div>
362
+ <h3>Bring Your Own AI</h3>
363
+ <p>Paste your API key for OpenAI, Groq, OpenRouter, Together, or Ollama. Pay fractions of a cent β€” directly to the provider.</p>
232
364
</div>
233
- <!-- Feature 3 -->
234
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
235
- <div class="w-12 h-12 bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400 rounded-xl flex items-center justify-center mb-6">
236
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
237
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
238
- </svg>
239
- </div>
240
- <h3 class="text-xl font-bold mb-3">Self-Hostable Backend</h3>
241
- <p class="text-gray-600 dark:text-gray-300">Don't want to use our proxy? Deploy your own Cloudflare Worker or Vercel Edge function in a single command. You own the infrastructure.</p>
365
+ <div class="feature-card fade-in">
366
+ <div class="feature-icon self-host"><i data-lucide="shield" class="icon-inline"></i></div>
367
+ <h3>Self-Hostable Backend</h3>
368
+ <p>Deploy to Cloudflare Workers, Vercel Edge, Railway, Render, or Docker. One command. You own the infrastructure.</p>
242
369
</div>
243
- <!-- Feature 4 -->
244
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
245
- <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-xl flex items-center justify-center mb-6">
246
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
247
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
248
- </svg>
249
- </div>
250
- <h3 class="text-xl font-bold mb-3">40+ Grammar Rules</h3>
251
- <p class="text-gray-600 dark:text-gray-300">Offline grammar checking with rules for passive voice, repetition, spelling, punctuation, clichΓ©s, redundant phrases, and more.</p>
370
+ <div class="feature-card fade-in">
371
+ <div class="feature-icon rules"><i data-lucide="file-text" class="icon-inline"></i></div>
372
+ <h3>40+ Grammar Rules</h3>
373
+ <p>Offline checking for passive voice, repetition, spelling, punctuation, clichΓ©s, redundant phrases, double negatives, and more.</p>
252
374
</div>
253
- <!-- Feature 5 -->
254
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
255
- <div class="w-12 h-12 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-xl flex items-center justify-center mb-6">
256
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
257
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path>
258
- </svg>
259
- </div>
260
- <h3 class="text-xl font-bold mb-3">Tone Rewriting</h3>
261
- <p class="text-gray-600 dark:text-gray-300">Rewrite text in 8 different tones: Formal, Casual, Professional, Friendly, Concise, Detailed, Persuasive, and Neutral.</p>
375
+ <div class="feature-card fade-in">
376
+ <div class="feature-icon rewrite"><i data-lucide="palette" class="icon-inline"></i></div>
377
+ <h3>Tone Rewriting</h3>
378
+ <p>Rewrite text in 8 tones β€” Formal, Casual, Professional, Friendly, Concise, Detailed, Persuasive, and Neutral. Right-click or Ctrl+Shift+R.</p>
262
379
</div>
263
- <!-- Feature 6 -->
264
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 hover:shadow-xl transition duration-300 bg-gray-50 dark:bg-dark-800">
265
- <div class="w-12 h-12 bg-teal-100 dark:bg-teal-900/30 text-teal-600 dark:text-teal-400 rounded-xl flex items-center justify-center mb-6">
266
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
267
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
268
- </svg>
269
- </div>
270
- <h3 class="text-xl font-bold mb-3">Writing Statistics</h3>
271
- <p class="text-gray-600 dark:text-gray-300">Get insights into your writing with readability scores, reading time, vocabulary diversity, and detailed analytics.</p>
380
+ <div class="feature-card fade-in">
381
+ <div class="feature-icon stats"><i data-lucide="bar-chart-2" class="icon-inline"></i></div>
382
+ <h3>Writing Statistics</h3>
383
+ <p>Readability scores (Flesch, ARI), reading/speaking time, vocabulary diversity, and detailed analytics for every document.</p>
272
384
</div>
273
385
</div>
274
386
</div>
275
387
</section>
276
388
277
389
<!-- How it Works -->
278
- <section id="how-it-works" class="py-20 bg-gray-50 dark:bg-dark-800 border-t border-b border-gray-200 dark:border-dark-700">
279
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
280
- <div class="flex flex-col lg:flex-row items-center gap-16">
281
- <div class="lg:w-1/2">
282
- <h2 class="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-6">Dual-Engine Architecture</h2>
283
- <div class="space-y-6">
284
- <div class="flex gap-4">
285
- <div class="flex-shrink-0 w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-900/30 flex items-center justify-center text-primary-600 dark:text-primary-400 font-bold">1</div>
286
- <div>
287
- <h4 class="text-lg font-bold">Local Rules Engine</h4>
288
- <p class="text-gray-600 dark:text-gray-300">Checks for passive voice, repeated words, and overly long sentences right in your browser. Fast, free, and completely offline.</p>
289
- </div>
390
+ <section id="how-it-works">
391
+ <div class="container">
392
+ <div class="how-grid">
393
+ <div class="fade-in">
394
+ <div class="section-label"><i data-lucide="sparkles" class="icon-inline"></i> Architecture</div>
395
+ <h2 class="section-title">Dual-engine.<br>Maximum power.</h2>
396
+ <p class="section-desc" style="margin-bottom:40px">Two engines work in parallel β€” fast local rules plus context-aware AI β€” then merge and rank results into a single clean list.</p>
397
+ <div class="how-steps">
398
+ <div class="how-step">
399
+ <div class="step-num s1">1</div>
400
+ <div><h4>Local Rules Engine</h4><p>40+ regex rules run instantly in your browser. Passive voice, spelling, punctuation, clichΓ©s β€” all offline, all free.</p></div>
290
401
</div>
291
- <div class="flex gap-4">
292
- <div class="flex-shrink-0 w-10 h-10 rounded-full bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center text-purple-600 dark:text-purple-400 font-bold">2</div>
293
- <div>
294
- <h4 class="text-lg font-bold">AI Processing</h4>
295
- <p class="text-gray-600 dark:text-gray-300">For complex grammar, tone rewriting, and clarity suggestions, text is sent securely to an LLM using your personal API key.</p>
296
- </div>
402
+ <div class="how-step">
403
+ <div class="step-num s2">2</div>
404
+ <div><h4>AI Processing</h4><p>For complex grammar and context-aware suggestions, text is sent to your chosen LLM via a stateless edge function.</p></div>
297
405
</div>
298
- <div class="flex gap-4">
299
- <div class="flex-shrink-0 w-10 h-10 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center text-green-600 dark:text-green-400 font-bold">3</div>
300
- <div>
301
- <h4 class="text-lg font-bold">Contextual UI</h4>
302
- <p class="text-gray-600 dark:text-gray-300">See red, yellow, and blue underlines as you type. Click to accept suggestions, ignore them, or add words to your custom dictionary.</p>
303
- </div>
406
+ <div class="how-step">
407
+ <div class="step-num s3">3</div>
408
+ <div><h4>Smart UI</h4><p>Red, amber, and blue wavy underlines appear as you type. Click to apply, ignore, or add to your dictionary.</p></div>
304
409
</div>
305
410
</div>
306
411
</div>
307
- <div class="lg:w-1/2">
308
- <div class="bg-white dark:bg-dark-900 p-6 rounded-2xl shadow-xl border border-gray-100 dark:border-dark-700">
309
- <div class="flex justify-between items-center mb-6 border-b pb-4 border-gray-200 dark:border-dark-700">
310
- <h3 class="font-bold text-gray-800 dark:text-gray-200">Writing Statistics</h3>
311
- <span class="text-sm text-gray-500 dark:text-gray-400">Document Analysis</span>
312
- </div>
313
- <div class="grid grid-cols-2 gap-4 mb-6">
314
- <div class="bg-primary-50 dark:bg-primary-900/20 p-4 rounded-lg">
315
- <div class="text-sm text-gray-500 dark:text-gray-400 mb-1">Words</div>
316
- <div class="text-2xl font-bold text-primary-700 dark:text-primary-400">1,248</div>
317
- </div>
318
- <div class="bg-purple-50 dark:bg-purple-900/20 p-4 rounded-lg">
319
- <div class="text-sm text-gray-500 dark:text-gray-400 mb-1">Reading Time</div>
320
- <div class="text-2xl font-bold text-purple-700 dark:text-purple-400">4 min</div>
321
- </div>
322
- </div>
323
- <div class="mb-4">
324
- <div class="flex justify-between text-sm mb-1">
325
- <span class="font-medium text-gray-700 dark:text-gray-300">Readability Score</span>
326
- <span class="text-green-600 dark:text-green-400 font-bold">Excellent (78)</span>
327
- </div>
328
- <div class="w-full bg-gray-200 dark:bg-dark-700 rounded-full h-2">
329
- <div class="bg-green-500 h-2 rounded-full" style="width: 78%"></div>
330
- </div>
331
- </div>
412
+ <div class="how-visual fade-in">
413
+ <h3 style="font-weight:700;margin-bottom:20px">Writing Statistics</h3>
414
+ <div class="stat-row">
415
+ <div class="stat-box"><div class="label">Words</div><div class="value purple">1,248</div></div>
416
+ <div class="stat-box"><div class="label">Reading Time</div><div class="value blue">4 min</div></div>
417
+ </div>
418
+ <div class="progress-bar">
419
+ <div class="bar-label"><span>Readability Score</span><span style="color:var(--green);font-weight:700">Excellent (78)</span></div>
420
+ <div class="bar-track"><div class="bar-fill" style="width:78%"></div></div>
421
+ </div>
422
+ <div class="progress-bar" style="margin-top:16px">
423
+ <div class="bar-label"><span>Vocabulary Diversity</span><span style="color:var(--accent);font-weight:700">43%</span></div>
424
+ <div class="bar-track"><div class="bar-fill" style="width:43%;background:linear-gradient(90deg,var(--primary),var(--accent))"></div></div>
332
425
</div>
333
426
</div>
334
427
</div>
336
429
</section>
337
430
338
431
<!-- AI Providers -->
339
- <section id="providers" class="py-20 bg-white dark:bg-dark-900">
340
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
341
- <div class="text-center mb-16">
342
- <h2 class="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Choose Your AI Provider</h2>
343
- <p class="text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">OpenGrammar supports multiple AI providers, giving you flexibility in cost, quality, and privacy.</p>
432
+ <section id="providers" style="background:var(--bg2);border-top:1px solid var(--border);border-bottom:1px solid var(--border)">
433
+ <div class="container">
434
+ <div class="section-header fade-in">
435
+ <div class="section-label"><i data-lucide="sparkles" class="icon-inline"></i> AI Providers</div>
436
+ <h2 class="section-title">Choose your engine.</h2>
437
+ <p class="section-desc center">6 supported providers. From free to premium. From cloud to fully local.</p>
344
438
</div>
345
-
346
- <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
347
- <!-- Groq -->
348
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 bg-gray-50 dark:bg-dark-800 hover:shadow-lg transition">
349
- <div class="flex items-center justify-between mb-4">
350
- <h3 class="text-xl font-bold">Groq</h3>
351
- <span class="px-3 py-1 bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400 text-sm font-semibold rounded-full">Recommended</span>
352
- </div>
353
- <p class="text-gray-600 dark:text-gray-300 mb-4">Fastest inference with free tier</p>
354
- <div class="space-y-2 mb-4">
355
- <div class="flex items-center gap-2 text-sm">
356
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
357
- <span>100 requests/day free</span>
358
- </div>
359
- <div class="flex items-center gap-2 text-sm">
360
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
361
- <span>Llama 3.1 70B</span>
362
- </div>
363
- <div class="flex items-center gap-2 text-sm">
364
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
365
- <span>~200ms response</span>
366
- </div>
367
- </div>
368
- <a href="docs/07-ai-providers.md#groq" class="text-primary-600 dark:text-primary-400 font-medium hover:underline inline-flex items-center gap-1">
369
- Learn more <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
370
- </a>
439
+ <div class="providers-grid">
440
+ <div class="provider-card fade-in">
441
+ <div class="provider-head"><h3><i data-lucide="zap" class="icon-inline"></i> Groq</h3><span class="provider-tag free">Free Tier</span></div>
442
+ <p class="desc">Fastest inference with LPU technology. 100 free requests/day.</p>
443
+ <ul class="check-list"><li>~200ms response</li><li>Llama 3.1 70B</li><li>No credit card</li></ul>
371
444
</div>
372
-
373
- <!-- OpenAI -->
374
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 bg-gray-50 dark:bg-dark-800 hover:shadow-lg transition">
375
- <div class="flex items-center justify-between mb-4">
376
- <h3 class="text-xl font-bold">OpenAI</h3>
377
- </div>
378
- <p class="text-gray-600 dark:text-gray-300 mb-4">Best quality grammar checking</p>
379
- <div class="space-y-2 mb-4">
380
- <div class="flex items-center gap-2 text-sm">
381
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
382
- <span>GPT-4o-mini</span>
383
- </div>
384
- <div class="flex items-center gap-2 text-sm">
385
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
386
- <span>95% accuracy</span>
387
- </div>
388
- <div class="flex items-center gap-2 text-sm">
389
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
390
- <span>~$0.15/1K requests</span>
391
- </div>
392
- </div>
393
- <a href="docs/07-ai-providers.md#openai" class="text-primary-600 dark:text-primary-400 font-medium hover:underline inline-flex items-center gap-1">
394
- Learn more <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
395
- </a>
445
+ <div class="provider-card fade-in">
446
+ <div class="provider-head"><h3><i data-lucide="circle-dot" class="icon-inline"></i> OpenAI</h3><span class="provider-tag quality">Best Quality</span></div>
447
+ <p class="desc">GPT-4o-mini for highest accuracy. ~$0.15/1K requests.</p>
448
+ <ul class="check-list"><li>95% accuracy</li><li>Context-aware</li><li>Most reliable</li></ul>
396
449
</div>
397
-
398
- <!-- Ollama -->
399
- <div class="p-6 rounded-2xl border border-gray-100 dark:border-dark-700 bg-gray-50 dark:bg-dark-800 hover:shadow-lg transition">
400
- <div class="flex items-center justify-between mb-4">
401
- <h3 class="text-xl font-bold">Ollama</h3>
402
- <span class="px-3 py-1 bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 text-sm font-semibold rounded-full">Privacy</span>
403
- </div>
404
- <p class="text-gray-600 dark:text-gray-300 mb-4">100% local & offline</p>
405
- <div class="space-y-2 mb-4">
406
- <div class="flex items-center gap-2 text-sm">
407
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
408
- <span>Complete privacy</span>
409
- </div>
410
- <div class="flex items-center gap-2 text-sm">
411
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
412
- <span>Free (your hardware)</span>
413
- </div>
414
- <div class="flex items-center gap-2 text-sm">
415
- <svg class="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
416
- <span>Works offline</span>
417
- </div>
418
- </div>
419
- <a href="docs/07-ai-providers.md#ollama" class="text-primary-600 dark:text-primary-400 font-medium hover:underline inline-flex items-center gap-1">
420
- Learn more <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
421
- </a>
450
+ <div class="provider-card fade-in">
451
+ <div class="provider-head"><h3><i data-lucide="bot" class="icon-inline"></i> Ollama</h3><span class="provider-tag private">100% Local</span></div>
452
+ <p class="desc">Run models on your own hardware. Complete privacy, works offline.</p>
453
+ <ul class="check-list"><li>Zero data leaves</li><li>Free forever</li><li>No internet needed</li></ul>
422
454
</div>
423
455
</div>
456
+ <p style="text-align:center;margin-top:32px">
457
+ <a href="docs/index.html#ai-providers" style="color:var(--primary);font-weight:600;font-size:15px">View all 6 providers β€” OpenRouter, Together AI, Custom β†’</a>
458
+ </p>
459
+ </div>
460
+ </section>
424
461
425
- <div class="mt-12 text-center">
426
- <a href="docs/07-ai-providers.md" class="text-primary-600 dark:text-primary-400 font-bold hover:underline inline-flex items-center gap-2 text-lg">
427
- View all 6 providers <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path></svg>
428
- </a>
462
+ <!-- Comparison -->
463
+ <section id="comparison" class="compare">
464
+ <div class="container">
465
+ <div class="section-header fade-in">
466
+ <div class="section-label"><i data-lucide="sparkles" class="icon-inline"></i> Comparison</div>
467
+ <h2 class="section-title">How we stack up.</h2>
468
+ </div>
469
+ <div style="overflow-x:auto" class="fade-in">
470
+ <table class="compare-table">
471
+ <thead><tr><th>Feature</th><th>Grammarly</th><th class="highlight-col">OpenGrammar</th><th>LanguageTool</th></tr></thead>
472
+ <tbody>
473
+ <tr><td><strong>Price</strong></td><td>$12/mo</td><td class="highlight-col yes">Free</td><td>$4.99/mo</td></tr>
474
+ <tr><td><strong>Open Source</strong></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i> Apache 2.0</td><td>Partial</td></tr>
475
+ <tr><td><strong>Self-Hostable</strong></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i> Docker / CF Workers</td><td class="no"><i data-lucide="x" class="icon-inline"></i></td></tr>
476
+ <tr><td><strong>Offline Mode</strong></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i> 40+ rules</td><td>Partial</td></tr>
477
+ <tr><td><strong>BYOK (Own AI Key)</strong></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i> 6 providers</td><td class="no"><i data-lucide="x" class="icon-inline"></i></td></tr>
478
+ <tr><td><strong>Local LLM (Ollama)</strong></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i></td><td class="no"><i data-lucide="x" class="icon-inline"></i></td></tr>
479
+ <tr><td><strong>Tone Rewriting</strong></td><td class="yes"><i data-lucide="check" class="icon-inline"></i> (Premium)</td><td class="highlight-col yes"><i data-lucide="check" class="icon-inline"></i> 8 tones</td><td class="no"><i data-lucide="x" class="icon-inline"></i></td></tr>
480
+ <tr><td><strong>Data Stored on Server</strong></td><td class="no"><i data-lucide="check" class="icon-inline"></i> Yes</td><td class="highlight-col yes"><i data-lucide="x" class="icon-inline"></i> Stateless</td><td><i data-lucide="check" class="icon-inline"></i> Yes</td></tr>
481
+ </tbody>
482
+ </table>
429
483
</div>
430
484
</div>
431
485
</section>
432
486
433
- <!-- Getting Started -->
434
- <section id="get-started" class="py-20 bg-gray-50 dark:bg-dark-800 border-t border-gray-200 dark:border-dark-700">
435
- <div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
436
- <h2 class="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-6">Ready to take back control?</h2>
437
- <p class="text-xl text-gray-600 dark:text-gray-300 mb-10">Start writing better today without sacrificing your privacy or your wallet.</p>
487
+ <!-- Get Started -->
488
+ <section id="get-started" class="get-started">
489
+ <div class="container">
490
+ <div class="section-header fade-in">
491
+ <div class="section-label"><i data-lucide="sparkles" class="icon-inline"></i> Get Started</div>
492
+ <h2 class="section-title">Ready in 5 minutes.</h2>
493
+ <p class="section-desc center">Clone, build, load. That's it.</p>
494
+ </div>
495
+ <div class="terminal fade-in">
496
+ <div class="terminal-bar"><div class="demo-dot r"></div><div class="demo-dot y"></div><div class="demo-dot g"></div></div>
497
+ <pre><span class="comment"># 1. Clone the repository</span>
498
+<span class="cmd">git clone</span> https://github.com/swadhinbiswas/opengrammar.git
438
499
439
- <div class="bg-gray-900 dark:bg-dark-900 rounded-2xl text-left p-6 shadow-2xl text-gray-300 font-mono text-sm overflow-x-auto mx-auto max-w-2xl">
440
- <div class="flex gap-2 mb-4">
441
- <div class="w-3 h-3 rounded-full bg-red-500"></div>
442
- <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
443
- <div class="w-3 h-3 rounded-full bg-green-500"></div>
444
- </div>
445
- <p><span class="text-blue-400"># 1. Clone the repository</span></p>
446
- <p class="mb-4 text-white">git clone https://github.com/swadhinbiswas/opengrammar.git</p>
500
+<span class="comment"># 2. Build the extension</span>
501
+<span class="cmd">cd</span> opengrammar/opengrammar/extension
502
+<span class="cmd">bun install</span> && <span class="cmd">bun run build</span>
447
503
448
- <p><span class="text-blue-400"># 2. Build the extension</span></p>
449
- <p class="text-white">cd opengrammar/opengrammar/extension</p>
450
- <p class="text-white">bun install</p>
451
- <p class="mb-4 text-white">bun run build</p>
504
+<span class="comment"># 3. Load in chrome://extensions β†’ Load Unpacked β†’ dist/</span>
452
505
453
- <p><span class="text-blue-400"># 3. Load unpacked in Chrome</span></p>
454
- <p class="text-gray-400">Go to chrome://extensions, enable Developer Mode, and select the dist/ folder.</p>
506
+<span class="comment"># 4. (Optional) Start local backend</span>
507
+<span class="cmd">cd</span> ../backend && <span class="cmd">bun run dev</span>
508
+<span class="comment"># <i data-lucide="check" class="icon-inline"></i> Running at http://localhost:8787</span></pre>
455
509
</div>
456
-
457
- <div class="mt-10 flex flex-col sm:flex-row gap-4 justify-center">
458
- <a href="docs/01-quick-start.md" class="bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-600 text-white px-8 py-4 rounded-full font-bold text-lg transition shadow-lg inline-flex items-center justify-center gap-2">
459
- Quick Start Guide <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path></svg>
510
+ <div class="cta-buttons fade-in">
511
+ <a href="docs/index.html#quick-start" class="btn btn-primary" style="padding:16px 32px;font-size:16px;border-radius:12px">
512
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
513
+ Read Full Documentation
460
514
</a>
461
- <a href="docs/00-index.md" class="bg-white dark:bg-dark-700 hover:bg-gray-50 dark:hover:bg-dark-600 text-gray-800 dark:text-gray-200 border border-gray-200 dark:border-dark-600 px-8 py-4 rounded-full font-bold text-lg transition shadow-sm inline-flex items-center justify-center gap-2">
462
- Full Documentation <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg>
515
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="btn btn-ghost" style="padding:16px 32px;font-size:16px;border-radius:12px">
516
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/></svg>
517
+ View Source Code
463
518
</a>
464
519
</div>
465
520
</div>
466
521
</section>
467
522
468
523
<!-- Footer -->
469
- <footer id="docs" class="bg-gray-900 dark:bg-dark-950 py-12 border-t border-gray-800 dark:border-dark-800">
470
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
471
- <div class="grid md:grid-cols-4 gap-8 mb-8">
472
- <div class="col-span-1">
473
- <div class="flex items-center gap-2 mb-4">
474
- <img src="logo.svg" alt="OpenGrammar Logo" class="h-6 w-6 opacity-80">
475
- <span class="text-xl font-bold text-white opacity-90">OpenGrammar</span>
476
- </div>
477
- <p class="text-gray-400 text-sm">
478
- Your privacy-first, open-source writing assistant.
479
- </p>
524
+ <footer class="footer">
525
+ <div class="container">
526
+ <div class="footer-grid">
527
+ <div class="footer-brand">
528
+ <a href="#" class="nav-logo"><img src="logo.svg" alt="OpenGrammar"><span>OpenGrammar</span></a>
529
+ <p>Your privacy-first, open-source writing assistant. Free forever under Apache 2.0.</p>
480
530
</div>
481
-
482
- <div>
483
- <h4 class="font-bold text-white mb-4">Documentation</h4>
484
- <ul class="space-y-2 text-sm">
485
- <li><a href="docs/01-quick-start.md" class="text-gray-400 hover:text-white transition">Quick Start</a></li>
486
- <li><a href="docs/04-browser-extension-setup.md" class="text-gray-400 hover:text-white transition">Browser Setup</a></li>
487
- <li><a href="docs/05-backend-deployment.md" class="text-gray-400 hover:text-white transition">Deployment</a></li>
488
- <li><a href="docs/07-ai-providers.md" class="text-gray-400 hover:text-white transition">AI Providers</a></li>
489
- </ul>
531
+ <div class="footer-col">
532
+ <h4>Documentation</h4>
533
+ <a href="docs/index.html#quick-start">Quick Start</a>
534
+ <a href="docs/index.html#browser-setup">Browser Setup</a>
535
+ <a href="docs/index.html#backend-deployment">Deployment</a>
536
+ <a href="docs/index.html#ai-providers">AI Providers</a>
537
+ <a href="docs/index.html#api-reference">API Reference</a>
490
538
</div>
491
-
492
- <div>
493
- <h4 class="font-bold text-white mb-4">Resources</h4>
494
- <ul class="space-y-2 text-sm">
495
- <li><a href="docs/09-using-opengrammar.md" class="text-gray-400 hover:text-white transition">User Guide</a></li>
496
- <li><a href="docs/10-tone-rewriting.md" class="text-gray-400 hover:text-white transition">Tone Rewriting</a></li>
497
- <li><a href="docs/18-troubleshooting.md" class="text-gray-400 hover:text-white transition">Troubleshooting</a></li>
498
- <li><a href="docs/19-faq.md" class="text-gray-400 hover:text-white transition">FAQ</a></li>
499
- </ul>
539
+ <div class="footer-col">
540
+ <h4>Guides</h4>
541
+ <a href="docs/index.html#using-opengrammar">User Guide</a>
542
+ <a href="docs/index.html#tone-rewriting">Tone Rewriting</a>
543
+ <a href="docs/index.html#writing-statistics">Writing Statistics</a>
544
+ <a href="docs/index.html#keyboard-shortcuts">Keyboard Shortcuts</a>
545
+ <a href="docs/index.html#faq">FAQ</a>
500
546
</div>
501
-
502
- <div>
503
- <h4 class="font-bold text-white mb-4">Community</h4>
504
- <ul class="space-y-2 text-sm">
505
- <li><a href="https://github.com/swadhinbiswas/opengrammar" class="text-gray-400 hover:text-white transition">GitHub</a></li>
506
- <li><a href="https://github.com/swadhinbiswas/opengrammar/discussions" class="text-gray-400 hover:text-white transition">Discussions</a></li>
507
- <li><a href="https://github.com/swadhinbiswas/opengrammar/issues" class="text-gray-400 hover:text-white transition">Issues</a></li>
508
- <li><a href="../ROADMAP.md" class="text-gray-400 hover:text-white transition">Roadmap</a></li>
509
- </ul>
547
+ <div class="footer-col">
548
+ <h4>Community</h4>
549
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank">GitHub</a>
550
+ <a href="https://github.com/swadhinbiswas/opengrammar/discussions" target="_blank">Discussions</a>
551
+ <a href="https://github.com/swadhinbiswas/opengrammar/issues" target="_blank">Issues</a>
552
+ <a href="ROADMAP.md">Roadmap</a>
510
553
</div>
511
554
</div>
512
-
513
- <div class="border-t border-gray-800 dark:border-dark-800 pt-8 flex flex-col md:flex-row justify-between items-center">
514
- <p class="text-gray-500 text-sm text-center md:text-left">
515
- Released under the Apache 2.0 License. Open-source and free forever.
516
- </p>
517
- <div class="mt-4 md:mt-0 flex gap-6">
518
- <a href="https://github.com/swadhinbiswas/opengrammar" class="text-gray-400 hover:text-white transition">GitHub</a>
519
- <a href="https://github.com/swadhinbiswas/opengrammar/discussions" class="text-gray-400 hover:text-white transition">Community</a>
520
- <a href="docs/00-index.md" class="text-gray-400 hover:text-white transition">Docs</a>
555
+ <div class="footer-bottom">
556
+ <span>Β© 2026 OpenGrammar. Released under the Apache 2.0 License.</span>
557
+ <div class="footer-bottom-links">
558
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank">GitHub</a>
559
+ <a href="docs/index.html">Docs</a>
560
+ <a href="https://github.com/swadhinbiswas/opengrammar/discussions" target="_blank">Community</a>
521
561
</div>
522
562
</div>
523
563
</div>
524
564
</footer>
525
565
526
- <!-- Theme Toggle Script -->
527
566
<script>
528
- // Check for saved theme preference or default to system preference
529
- const theme = localStorage.getItem('theme') ||
530
- (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
531
-
532
- if (theme === 'dark') {
533
- document.documentElement.classList.add('dark');
534
- }
535
-
536
- function updateThemeIcons() {
537
- const isDark = document.documentElement.classList.contains('dark');
538
- const lightIcon = document.getElementById('theme-toggle-light-icon');
539
- const darkIcon = document.getElementById('theme-toggle-dark-icon');
540
-
541
- if (isDark) {
542
- lightIcon.classList.remove('hidden');
543
- darkIcon.classList.add('hidden');
544
- } else {
545
- lightIcon.classList.add('hidden');
546
- darkIcon.classList.remove('hidden');
547
- }
548
- }
549
-
550
- // Initialize icons
551
- updateThemeIcons();
552
-
553
- // Desktop theme toggle
554
- document.getElementById('theme-toggle').addEventListener('click', function() {
555
- document.documentElement.classList.toggle('dark');
556
- const isDark = document.documentElement.classList.contains('dark');
557
- localStorage.setItem('theme', isDark ? 'dark' : 'light');
558
- updateThemeIcons();
559
- });
560
-
561
- // Mobile theme toggle
562
- document.getElementById('mobile-theme-toggle').addEventListener('click', function() {
563
- document.documentElement.classList.toggle('dark');
564
- const isDark = document.documentElement.classList.contains('dark');
565
- localStorage.setItem('theme', isDark ? 'dark' : 'light');
566
- updateThemeIcons();
567
- });
568
-
569
- // Mobile menu toggle
570
- document.getElementById('mobile-menu-button').addEventListener('click', function() {
571
- const menu = document.getElementById('mobile-menu');
572
- menu.classList.toggle('hidden');
573
- });
567
+ // Theme Toggle
568
+ const html = document.documentElement;
569
+ const saved = localStorage.getItem('og-theme') || (window.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light');
570
+ html.dataset.theme = saved;
571
+ document.getElementById('themeToggle').addEventListener('click', () => {
572
+ const next = html.dataset.theme === 'dark' ? 'light' : 'dark';
573
+ html.dataset.theme = next;
574
+ localStorage.setItem('og-theme', next);
575
+ });
576
+
577
+ // Mobile menu
578
+ document.getElementById('mobileToggle').addEventListener('click', () => {
579
+ document.getElementById('mobileMenu').classList.toggle('open');
580
+ });
581
+ document.querySelectorAll('.mobile-menu a').forEach(a => {
582
+ a.addEventListener('click', () => document.getElementById('mobileMenu').classList.remove('open'));
583
+ });
584
+
585
+ // Scroll animations
586
+ const observer = new IntersectionObserver((entries) => {
587
+ entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); observer.unobserve(e.target); }});
588
+ }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
589
+ document.querySelectorAll('.fade-in').forEach(el => observer.observe(el));
574
590
</script>
575
591
592
+<script>
593
+ lucide.createIcons();
594
+</script>
576
595
</body>
577
596
</html>
578
597