feat: WCAG AA accessibility, code splitting, responsive ads layout

- Add React.lazy code splitting for all 15 tool pages
- Fix WCAG AA contrast issues (304 text color fixes)
- Add ARIA labels and aria-expanded to navigation buttons
- Add aria-live for error announcements in tools
- Implement responsive ad layout:
  - Desktop (≥1280px): Right sidebar with 3 ad units
  - Tablet (1024-1279px): Bottom section with 3 horizontal units
  - Mobile (<1024px): Fixed bottom banner
- Add TabletAdSection component for tablet ad placement
- Integrate Onidel affiliate partnership
- Update all Adsterra domains to solutionbiologyisle.com
- Add release notes for 2026-02-18 updates
This commit is contained in:
dwindown
2026-02-18 18:57:31 +07:00
parent 9dc3285adb
commit 3a475e9df2
41 changed files with 391 additions and 318 deletions

View File

@@ -172,7 +172,7 @@ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru
{url && !isLoading && (
<button
onClick={clearUrl}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 transition-colors"
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-600 hover:text-gray-600 dark:text-gray-600 dark:hover:text-gray-300 transition-colors"
>
<X className="h-4 w-4" />
</button>
@@ -208,7 +208,7 @@ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru
{CONTENT_TYPE_INFO[urlResult.contentType].label}
</span>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400 mb-2">
<div className="text-sm text-gray-600 dark:text-gray-600 mb-2">
{CONTENT_TYPE_INFO[urlResult.contentType].description}
</div>
{urlResult.title && (
@@ -216,7 +216,7 @@ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru
{urlResult.title}
</div>
)}
<div className="text-xs text-gray-500 dark:text-gray-400">
<div className="text-xs text-gray-600 dark:text-gray-600">
Article: {urlResult.metrics.articleWordCount} words
Total: {urlResult.metrics.totalWordCount} words
Ratio: {Math.round(urlResult.metrics.contentRatio * 100)}%
@@ -336,28 +336,28 @@ Typing time: ${getTypingTime()}` : ''}`;
<div className="text-2xl font-bold text-primary-600 dark:text-primary-400">
{formatNumber(stats.characters)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Characters</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Characters</div>
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
<div className="text-2xl font-bold text-primary-600 dark:text-primary-400">
{formatNumber(stats.charactersNoSpaces)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Characters (no spaces)</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Characters (no spaces)</div>
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
<div className="text-2xl font-bold text-green-600 dark:text-green-400">
{formatNumber(stats.words)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Words</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Words</div>
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
<div className="text-2xl font-bold text-blue-600 dark:text-blue-400">
{formatNumber(stats.lines)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Lines</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Lines</div>
</div>
</div>
@@ -369,14 +369,14 @@ Typing time: ${getTypingTime()}` : ''}`;
<div className="text-xl font-bold text-purple-600 dark:text-purple-400">
{formatNumber(stats.sentences)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Sentences</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Sentences</div>
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
<div className="text-xl font-bold text-orange-600 dark:text-orange-400">
{formatNumber(stats.paragraphs)}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Paragraphs</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Paragraphs</div>
</div>
</div>
@@ -384,7 +384,7 @@ Typing time: ${getTypingTime()}` : ''}`;
<div className="text-xl font-bold text-red-600 dark:text-red-400">
{formatNumber(stats.bytes)} bytes
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">Size (UTF-8 encoding)</div>
<div className="text-sm text-gray-600 dark:text-gray-600">Size (UTF-8 encoding)</div>
</div>
{/* Reading & Typing Time */}