fix(ui): design critique overhaul — a11y, honest metrics, i18n repair (critique 2026-08-30)
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m51s

P0 a11y: keyboard-accessible dropzone (role/tabIndex/Enter-Space), ARIA
combobox + listbox pattern for language selector, role=switch on glossary
toggle, role=status live region on notifications, aria-labels on password
toggles, visible-on-focus close buttons, RTL logical positioning (start-*).

Trust: third-party Memento promo removed from translate page, sidebar and
all 13 locales; fabricated stats (99.9%, Turbo, computed layout-integrity
bars) replaced with real measurements incl. API estimated remaining time;
silent download failure now surfaces an error notification.

Honesty: fake 100-byte file injections removed (format chips are now
informational); cancel-that-doesn't renamed 'Back to start' with hint;
Enterprise contact placeholder replaced with contact@wordly.art.

i18n: t() no longer returns raw keys (empty string + defaultValue support,
~30 dead || fallbacks now work); ~170 new keys EN+FR across new reviews/
teams namespaces, glossaries context tab, translate monitor, settings,
services, pricing, landing, fileUploader; split-key italic titles replace
lastIndexOf() surgery (zh/ja-safe); key-audit script added 0 missing.

Flow: active job persisted across refresh with polling resume (24h TTL);
client-side recent-jobs history with review links; review page linked from
complete state; settings/services added to dashboard nav; Business/
Enterprise regain glossary access (tier gate unified).

Typeset (sober-tool direction): 7.5-9px labels raised to 10-12px, /30
opacity to /45-/55, uppercase tracking reduced, trust footer legible,
country flags removed from language switcher, localized dates.

Cleanup: 5 orphaned translate components, dead site header/footer,
fossil tailwind.config.js, PipelineStepper, duplicate pill+H1 titles,
two-step confirm for cache clear, dead landing footer links.

Verified: next build exit 0, vitest 9/9, eslint 64 errors = HEAD
(no regression, -3 warnings), detector 4 -> 3 findings.
This commit is contained in:
2026-08-30 21:44:53 +02:00
parent 1a67241ad5
commit 50047ea8a2
79 changed files with 878 additions and 1590 deletions

View File

@@ -18,7 +18,6 @@ export function DashboardSidebar() {
const { t } = useI18n();
const isPro = ['pro', 'business', 'enterprise'].includes(user?.tier ?? '');
const isPaid = !!user?.tier && user.tier !== 'free';
const navItems = isPro ? baseNavItems : baseNavItems.filter(item => !item.proOnly);
return (
@@ -69,29 +68,6 @@ export function DashboardSidebar() {
</div>
)}
{/* Memento promo section — hidden for paying users */}
{!isPaid && (
<a
href={t('memento.url', { defaultValue: 'https://memento-note.com/' })}
target="_blank"
rel="noopener noreferrer"
className="block px-6 py-4"
>
<div className="bg-brand-muted/50 dark:bg-[#1f1f1f]/50 rounded-3xl p-6 border border-black/5 dark:border-white/5 group cursor-pointer hover:bg-brand-dark dark:hover:bg-brand-accent transition-all duration-500">
<div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 bg-brand-dark group-hover:bg-brand-accent rounded-lg flex items-center justify-center text-white text-xs font-black shadow-sm transition-all group-hover:rotate-12">M</div>
<span className="text-[10px] font-black uppercase tracking-widest text-brand-dark group-hover:text-white dark:text-white transition-colors">{t('memento.title')}</span>
</div>
<p className="text-[9px] text-brand-dark/40 group-hover:text-white/60 font-medium leading-relaxed mb-6">
{t('memento.slogan').substring(0, 80)}...
</p>
<button className="w-full py-2.5 bg-brand-dark group-hover:bg-white text-white group-hover:text-brand-dark dark:bg-[#272727] rounded-xl text-[8px] font-black uppercase tracking-widest shadow-sm transition-all">
{t('memento.ctaFree')}
</button>
</div>
</a>
)}
{/* User section */}
<div className="border-t border-black/5 dark:border-white/5">
{!isLoading && user && (
@@ -110,7 +86,7 @@ export function DashboardSidebar() {
</div>
</div>
<div className="flex items-center gap-2 mb-3">
<span className="px-1.5 py-0 rounded-full border border-brand-accent/30 text-brand-accent text-[7px] font-black uppercase">
<span className="px-2.5 py-0.5 rounded-full border border-brand-accent/30 text-brand-accent text-[10px] font-black uppercase">
{translateTier(t, user.tier)}
</span>
</div>