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
9 changes: 9 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Palette's Journal

## 2024-05-22 - [Initial Setup]
**Learning:** This journal was missing, so I created it to track critical UX/accessibility learnings.
**Action:** Ensure this file is checked before starting work in the future.

## 2024-05-22 - [Dynamic State Labels]
**Learning:** Dynamic state indicators (like notification badges or status dots) often lack accessible text equivalents in this codebase, relying solely on visual cues (colors/dots).
**Action:** Always check icon-only buttons for `aria-label` and ensure the label reflects the *current state* (e.g., "Notifications, 3 unread") rather than just the static name ("Notifications").
8 changes: 6 additions & 2 deletions src/components/notifications/notification-bell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,14 @@ export function NotificationBell() {
variant="ghost"
size="icon"
className="relative text-foreground/70 hover:text-foreground hover:bg-accent/10"
aria-label={count > 0 ? `Notifications, ${count} unread` : "Notifications"}
>
<Bell className="w-5 h-5" />
<Bell className="w-5 h-5" aria-hidden="true" />
{count > 0 && (
<span className="absolute top-2 right-2 h-2.5 w-2.5 rounded-full bg-red-500 border border-black animate-pulse" />
<span
className="absolute top-2 right-2 h-2.5 w-2.5 rounded-full bg-red-500 border border-black animate-pulse"
aria-hidden="true"
/>
)}
</Button>
</PopoverTrigger>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/supabase/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function createClient() {
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options),
cookieStore.set(name, value, options)
);
} catch {
// The `setAll` method was called from a Server Component.
Expand Down
50 changes: 50 additions & 0 deletions verify_bell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from playwright.sync_api import sync_playwright

def verify_notification_bell():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()

try:
# 1. Navigate to the verification page
print("Navigating to verification page...")
page.goto("http://localhost:3000/verify-notification-bell")

# Wait for content to load
page.wait_for_selector("text=Notification Bell Verification", timeout=10000)

# 2. Find the notification button by its aria-label
# Initially count is 0, so label should be "Notifications"
print("Locating bell button...")
bell_button = page.locator("button[aria-label='Notifications']")

# 3. Assert it is visible
if bell_button.is_visible():
print("✅ Bell button found with correct aria-label 'Notifications'")
else:
print("❌ Bell button NOT found with expected aria-label")
# Try to find it by icon to see what the label actually is
all_buttons = page.locator("button").all()
for btn in all_buttons:
print(f"Found button with label: {btn.get_attribute('aria-label')}")

# 4. Check that the icon inside is hidden from screen readers
icon = bell_button.locator("svg.lucide-bell")
if icon.get_attribute("aria-hidden") == "true":
print("✅ Bell icon correctly marked as aria-hidden='true'")
else:
print(f"❌ Bell icon missing or incorrect aria-hidden: {icon.get_attribute('aria-hidden')}")

# 5. Take a screenshot
screenshot_path = "/home/jules/verification/notification-bell.png"
page.screenshot(path=screenshot_path)
print(f"Screenshot saved to {screenshot_path}")

except Exception as e:
print(f"Verification failed: {e}")
page.screenshot(path="/home/jules/verification/error.png")
finally:
browser.close()

if __name__ == "__main__":
verify_notification_bell()