From 88a3574be82358d45d08cebe3cb3dd807b118aa2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:04:49 +0000 Subject: [PATCH] [jules] style: Consistent hover/focus states across all buttons Adds `focus-visible` states to Button, Input password toggle, Modal close, and Toast close buttons. This ensures consistent keyboard accessibility focus rings across both Glassmorphism and Neobrutalism themes. Updates .Jules tracking files. Co-authored-by: Devasy23 <110348311+Devasy23@users.noreply.github.com> --- .Jules/changelog.md | 7 +++++++ .Jules/todo.md | 5 +++-- web/components/ui/Button.tsx | 8 ++++---- web/components/ui/Input.tsx | 6 +++--- web/components/ui/Modal.tsx | 2 +- web/components/ui/Toast.tsx | 2 +- 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/.Jules/changelog.md b/.Jules/changelog.md index 11fc864e..b331c603 100644 --- a/.Jules/changelog.md +++ b/.Jules/changelog.md @@ -7,6 +7,13 @@ ## [Unreleased] ### Added +- **Consistent Hover & Focus States:** Added cohesive `focus-visible` states across main interactive web components for better keyboard accessibility. + - **Features:** + - Explicit dual-theme ring styling (e.g. `focus-visible:ring-black` vs `focus-visible:ring-white/50`). + - Handled target elements: `Button`, `Input` (password toggle), `Modal` (close icon), `Toast` (close icon). + - Ensures mouse clicks do not trigger focus rings, preserving visual elegance while fully supporting keyboard power users. + - **Technical:** Modified `Button.tsx`, `Input.tsx`, `Modal.tsx`, `Toast.tsx` with specific tailwind states (`focus-visible:ring-2`, `focus-visible:ring-offset-2`, etc). + - **Password Strength Meter:** Added a visual password strength indicator to the signup form. - **Features:** - Real-time strength calculation (Length, Uppercase, Lowercase, Number, Symbol). diff --git a/.Jules/todo.md b/.Jules/todo.md index ebb0c7a5..3caebfef 100644 --- a/.Jules/todo.md +++ b/.Jules/todo.md @@ -78,8 +78,9 @@ ### Web -- [ ] **[style]** Consistent hover/focus states across all buttons - - Files: `web/components/ui/Button.tsx`, usage across pages +- [x] **[style]** Consistent hover/focus states across all buttons + - Completed: 2026-04-09 + - Files: `web/components/ui/Button.tsx`, `web/components/ui/Input.tsx`, `web/components/ui/Modal.tsx`, `web/components/ui/Toast.tsx` - Context: Ensure all buttons have proper hover + focus-visible styles - Impact: Professional feel, keyboard users know where they are - Size: ~35 lines diff --git a/web/components/ui/Button.tsx b/web/components/ui/Button.tsx index f80c514c..57e063a0 100644 --- a/web/components/ui/Button.tsx +++ b/web/components/ui/Button.tsx @@ -20,7 +20,7 @@ export const Button: React.FC = ({ }) => { const { style } = useTheme(); - const baseStyles = "transition-all duration-200 font-bold flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"; + const baseStyles = "transition-all duration-200 font-bold flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"; const sizeStyles = { sm: "px-3 py-1.5 text-sm", @@ -31,16 +31,16 @@ export const Button: React.FC = ({ let themeStyles = ""; if (style === THEMES.NEOBRUTALISM) { - themeStyles = "border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] active:translate-x-[4px] active:translate-y-[4px] active:shadow-none rounded-none uppercase tracking-wider font-mono"; + themeStyles = "border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] active:translate-x-[4px] active:translate-y-[4px] active:shadow-none rounded-none uppercase tracking-wider font-mono focus-visible:ring-black dark:focus-visible:ring-white focus-visible:ring-offset-white dark:focus-visible:ring-offset-zinc-900"; if (variant === 'primary') themeStyles += " bg-neo-main text-white"; if (variant === 'secondary') themeStyles += " bg-neo-second text-black"; if (variant === 'danger') themeStyles += " bg-red-500 text-white"; - if (variant === 'ghost') themeStyles += " bg-transparent border-transparent shadow-none hover:bg-gray-200 hover:shadow-none hover:translate-x-0 hover:translate-y-0 active:translate-x-0 active:translate-y-0"; + if (variant === 'ghost') themeStyles += " bg-transparent border-transparent shadow-none hover:bg-gray-200 dark:hover:bg-gray-800 hover:shadow-none hover:translate-x-0 hover:translate-y-0 active:translate-x-0 active:translate-y-0 focus-visible:ring-offset-transparent"; } else { // Glassmorphism - themeStyles = "rounded-xl backdrop-blur-md border border-white/20 shadow-lg hover:shadow-xl active:scale-95"; + themeStyles = "rounded-xl backdrop-blur-md border border-white/20 shadow-lg hover:shadow-xl active:scale-95 focus-visible:ring-white/50 focus-visible:ring-offset-transparent"; if (variant === 'primary') themeStyles += " bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-blue-500/30"; if (variant === 'secondary') themeStyles += " bg-white/10 text-white hover:bg-white/20"; diff --git a/web/components/ui/Input.tsx b/web/components/ui/Input.tsx index 80e7fff2..87e2a036 100644 --- a/web/components/ui/Input.tsx +++ b/web/components/ui/Input.tsx @@ -46,10 +46,10 @@ export const Input: React.FC = ({ label, error, className = '', type diff --git a/web/components/ui/Toast.tsx b/web/components/ui/Toast.tsx index 056ebb8d..950addb9 100644 --- a/web/components/ui/Toast.tsx +++ b/web/components/ui/Toast.tsx @@ -57,7 +57,7 @@ const ToastItem: React.FC<{ toast: Toast }> = ({ toast }) => {