Skip to content
Merged
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
10 changes: 9 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ function AuthenticatedLayout({ children }: { children: React.ReactNode }) {

return (
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-950 transition-colors">
{/* Skip to main content link */}
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:top-2 focus:left-2 focus:px-4 focus:py-2 focus:bg-amber-500 focus:text-white focus:rounded-lg focus:text-sm focus:font-medium"
>
Skip to main content
</a>

{/* Header */}
<header className="sticky top-0 z-40 bg-white/80 dark:bg-gray-900/80 backdrop-blur-lg border-b border-gray-200 dark:border-gray-800 safe-area-inset-top">
<div className="container mx-auto px-4 py-3 flex items-center justify-between">
Expand Down Expand Up @@ -89,7 +97,7 @@ function AuthenticatedLayout({ children }: { children: React.ReactNode }) {
</header>

{/* Main content */}
<main className="container mx-auto px-4 py-6 safe-area-inset-bottom">
<main id="main-content" className="container mx-auto px-4 py-6 safe-area-inset-bottom">
<ErrorBoundary>{children}</ErrorBoundary>
</main>

Expand Down
4 changes: 3 additions & 1 deletion src/components/AddItemInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ export const AddItemInput = forwardRef<HTMLInputElement, AddItemInputProps>(func
};

return (
<form onSubmit={handleSubmit} className="flex gap-3">
<form onSubmit={handleSubmit} className="flex gap-3" aria-label="Add new item">
<div className="flex-1 relative">
<label htmlFor="add-item-input" className="sr-only">Add new item</label>
<input
ref={inputRef}
id="add-item-input"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
Expand Down
4 changes: 4 additions & 0 deletions src/components/BatchOperations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export function BatchOperations({
disabled={isProcessing}
className="p-2 hover:bg-gray-700 dark:hover:bg-gray-300 rounded-lg transition-colors disabled:opacity-50"
title="Check all"
aria-label="Check all selected items"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
Expand All @@ -120,6 +121,7 @@ export function BatchOperations({
disabled={isProcessing}
className="p-2 hover:bg-gray-700 dark:hover:bg-gray-300 rounded-lg transition-colors disabled:opacity-50"
title="Uncheck all"
aria-label="Uncheck all selected items"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
Expand All @@ -134,6 +136,7 @@ export function BatchOperations({
disabled={isProcessing}
className="p-2 text-red-400 hover:bg-red-900/30 rounded-lg transition-colors disabled:opacity-50"
title="Delete all"
aria-label="Delete all selected items"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
Expand All @@ -149,6 +152,7 @@ export function BatchOperations({
}}
className="p-2 hover:bg-gray-700 dark:hover:bg-gray-300 rounded-lg transition-colors"
title="Clear selection"
aria-label="Clear selection"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
Expand Down
1 change: 1 addition & 0 deletions src/components/ListCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const ListCard = memo(function ListCard({ list, currentUserDid, showOwner
to={`/list/${list._id}`}
onClick={() => haptic('light')}
className="group block bg-white dark:bg-gray-800 rounded-2xl shadow-lg hover:shadow-xl dark:shadow-gray-900/50 transition-all duration-200 p-5 card-hover border border-gray-100 dark:border-gray-700 hover:border-amber-200 dark:hover:border-amber-600"
aria-label={`Open list: ${list.name}`}
>
<div className="flex items-start gap-4">
{/* Emoji icon */}
Expand Down
2 changes: 2 additions & 0 deletions src/components/ProvenanceInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ function DidRow({
: "hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
}`}
title={copied ? "Copied!" : "Copy full DID"}
aria-label={copied ? "Copied!" : `Copy ${label}`}
>
{copied ? (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
Expand Down Expand Up @@ -178,6 +179,7 @@ function ProvenanceSection({
<button
onClick={() => setIsOpen(!isOpen)}
className="w-full flex items-center justify-between px-4 py-3 bg-gray-50 dark:bg-gray-800/50 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
aria-expanded={isOpen}
>
<div className="flex items-center gap-2">
<svg
Expand Down
7 changes: 6 additions & 1 deletion src/components/RenameListDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ export function RenameListDialog({ list, onClose }: RenameListDialogProps) {
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 animate-fade-in">
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="rename-dialog-title"
className="bg-white dark:bg-gray-800 rounded-2xl shadow-xl max-w-sm w-full p-6 animate-slide-up"
>
<h3 className="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
<h3 id="rename-dialog-title" className="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
Rename list
</h3>

<label htmlFor="rename-list-input" className="sr-only">List name</label>
<input
id="rename-list-input"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
Expand Down
3 changes: 3 additions & 0 deletions src/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export function Settings({ onClose }: SettingsProps) {
}`}
role="switch"
aria-checked={darkMode}
aria-label="Toggle dark mode"
>
<div
className={`absolute top-1 w-6 h-6 bg-white rounded-full shadow-md transition-transform ${
Expand Down Expand Up @@ -137,6 +138,7 @@ export function Settings({ onClose }: SettingsProps) {
}`}
role="switch"
aria-checked={hapticsEnabled}
aria-label="Toggle haptic feedback"
>
<div
className={`absolute top-1 w-6 h-6 bg-white rounded-full shadow-md transition-transform ${
Expand Down Expand Up @@ -221,6 +223,7 @@ export function Settings({ onClose }: SettingsProps) {
} ${notificationsLoading || notificationPermission === 'denied' ? 'opacity-50 cursor-not-allowed' : ''}`}
role="switch"
aria-checked={notificationsEnabled}
aria-label="Toggle push notifications"
>
<div
className={`absolute top-1 w-6 h-6 bg-white rounded-full shadow-md transition-transform ${
Expand Down
3 changes: 2 additions & 1 deletion src/components/ShareModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,12 @@ export function ShareModal({ list, onClose }: ShareModalProps) {

{inviteLink && !isCreating && (
<div className="space-y-3">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label htmlFor="invite-link-input" className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Invite link
</label>
<div className="flex gap-2">
<input
id="invite-link-input"
type="text"
value={inviteLink}
readOnly
Expand Down
1 change: 1 addition & 0 deletions src/components/TagSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export function TagSelector({
}`}
style={{ backgroundColor: color.value }}
title={color.name}
aria-label={`Select ${color.name} color`}
/>
))}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/lists/CategoryHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function CategoryHeader({
<button
onClick={() => setIsExpanded(!isExpanded)}
className="w-full flex items-center justify-between py-2 text-left group"
aria-expanded={isExpanded}
>
<div className="flex items-center gap-2">
<span
Expand Down
2 changes: 1 addition & 1 deletion src/components/offline/OfflineIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function OfflineIndicator() {
if (isOnline) return null;

return (
<div className="fixed top-0 left-0 right-0 z-50 safe-area-top">
<div className="fixed top-0 left-0 right-0 z-50 safe-area-top" role="alert" aria-live="assertive">
<div className="bg-gradient-to-r from-amber-500 to-orange-500 text-white px-4 py-2.5 text-center text-sm font-medium shadow-lg">
<div className="flex items-center justify-center gap-2">
<span className="relative flex h-3 w-3">
Expand Down
2 changes: 2 additions & 0 deletions src/components/publish/VerificationBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export function VerificationBadge({ did, didDocument }: VerificationBadgeProps)
<button
onClick={() => setShowDetails(!showDetails)}
className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-green-100 text-green-800 rounded-full text-sm font-medium hover:bg-green-200 transition-colors"
aria-expanded={showDetails}
aria-label="Verification details"
>
<svg
className="w-4 h-4"
Expand Down
1 change: 1 addition & 0 deletions src/components/sharing/CollaboratorList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ function RoleSelector({ value, onChange, disabled }: RoleSelectorProps) {
onChange={(e) => onChange(e.target.value as "editor" | "viewer")}
disabled={disabled}
className="px-2 py-1 text-xs border border-gray-300 rounded bg-white text-gray-700 disabled:opacity-50"
aria-label="Change role"
>
<option value="editor">Editor</option>
<option value="viewer">Viewer</option>
Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export function SearchInput({
}, []);

return (
<div className={`relative ${className}`}>
<div className={`relative ${className}`} role="search">
<label htmlFor="search-lists-input" className="sr-only">Search lists</label>
{/* Search icon */}
<div
className={`absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${
Expand All @@ -57,7 +58,8 @@ export function SearchInput({

<input
ref={inputRef}
type="text"
id="search-lists-input"
type="search"
value={value}
onChange={(e) => onChange(e.target.value)}
onFocus={() => setIsFocused(true)}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ export function Home() {

{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
Your Lists
</h2>
</h1>
<div className="flex items-center gap-2">
<Link
to="/priority"
Expand Down
4 changes: 2 additions & 2 deletions src/pages/PriorityFocus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ export function PriorityFocus() {
/>
</svg>
</Link>
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
🎯 Priority Focus
</h2>
</h1>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
{isLoading
Expand Down
Loading