Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .Jules/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
5 changes: 3 additions & 2 deletions .Jules/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions web/components/ui/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const Button: React.FC<ButtonProps> = ({
}) => {
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",
Expand All @@ -31,16 +31,16 @@ export const Button: React.FC<ButtonProps> = ({
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";
Expand Down
6 changes: 3 additions & 3 deletions web/components/ui/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ export const Input: React.FC<InputProps> = ({ label, error, className = '', type
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className={`absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-md transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-1 ${
className={`absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-md transition-opacity hover:opacity-100 focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 ${
style === THEMES.NEOBRUTALISM
? (mode === 'dark' ? 'text-white opacity-80 focus:ring-white' : 'text-black opacity-60 focus:ring-black')
: 'text-white/60 hover:text-white focus:ring-white/50'
? (mode === 'dark' ? 'text-white opacity-80 focus-visible:ring-white' : 'text-black opacity-60 focus-visible:ring-black')
: 'text-white/60 hover:text-white focus-visible:ring-white/50 focus-visible:ring-offset-transparent'
}`}
aria-label={showPassword ? "Hide password" : "Show password"}
>
Expand Down
2 changes: 1 addition & 1 deletion web/components/ui/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children,
{/* Header */}
<div className={`p-6 flex justify-between items-center ${style === THEMES.NEOBRUTALISM ? 'border-b-2 border-black bg-neo-main text-white' : 'border-b border-white/10 bg-white/5'}`}>
<h3 id={titleId} className={`text-2xl font-bold ${style === THEMES.NEOBRUTALISM ? 'uppercase font-mono tracking-tighter' : ''}`}>{title}</h3>
<button type="button" onClick={onClose} className="hover:rotate-90 transition-transform duration-200" aria-label="Close modal">
<button type="button" onClick={onClose} className="p-1 rounded-md hover:rotate-90 transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-transparent" aria-label="Close modal">
<X size={24} />
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion web/components/ui/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const ToastItem: React.FC<{ toast: Toast }> = ({ toast }) => {
<button
type="button"
onClick={() => removeToast(toast.id)}
className="shrink-0 hover:opacity-70 transition-opacity"
className="shrink-0 rounded hover:opacity-70 transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current focus-visible:ring-offset-1 focus-visible:ring-offset-transparent"
aria-label="Close notification"
>
<X className="w-4 h-4" />
Expand Down
Loading