diff --git a/src/app/demo/notifications/page.tsx b/src/app/demo/notifications/page.tsx
new file mode 100644
index 0000000..6d46fe0
--- /dev/null
+++ b/src/app/demo/notifications/page.tsx
@@ -0,0 +1,188 @@
+"use client";
+
+import { useState } from "react";
+import { useToast } from "@/components/notifications/ToastProvider";
+import { InlineBanner } from "@/components/ui/InlineBanner";
+import { Button } from "@/components/ui/Button";
+import { NotificationCenter } from "@/components/notifications/NotificationCenter";
+
+export default function NotificationsDemo() {
+ const { pushToast, dismissToast, setLimit, limit, toasts } = useToast();
+ const [showBanner, setShowBanner] = useState<"success" | "info" | "warning" | "error" | null>(null);
+ const [showNotificationCenter, setShowNotificationCenter] = useState(false);
+
+ const handleToast = (variant: "success" | "info" | "warning" | "error") => {
+ const messages = {
+ success: { title: "Changes saved", description: "Your settings have been updated successfully." },
+ info: { title: "New feature available", description: "Check out the latest updates in your dashboard." },
+ warning: { title: "Session expiring soon", description: "Please save your work before your session ends." },
+ error: { title: "Save failed", description: "Could not save your changes. Please try again." },
+ };
+
+ pushToast({
+ title: messages[variant].title,
+ description: messages[variant].description,
+ variant,
+ duration: 4500,
+ });
+ };
+
+ const handleMockFlow = (flow: "save" | "failure" | "timeout") => {
+ switch (flow) {
+ case "save":
+ pushToast({ title: "Saving...", description: "Please wait while we save your changes.", variant: "info", duration: 2000 });
+ setTimeout(() => {
+ pushToast({ title: "Changes saved", description: "Your settings have been updated successfully.", variant: "success", duration: 4500 });
+ }, 2000);
+ break;
+ case "failure":
+ pushToast({ title: "Processing...", description: "Please wait while we process your request.", variant: "info", duration: 2000 });
+ setTimeout(() => {
+ pushToast({ title: "Request failed", description: "Network error occurred. Please check your connection.", variant: "error", duration: 5000 });
+ }, 2000);
+ break;
+ case "timeout":
+ pushToast({ title: "Connecting...", description: "Establishing connection to server.", variant: "info", duration: 2000 });
+ setTimeout(() => {
+ pushToast({ title: "Connection timeout", description: "Server did not respond in time. Please.try again.", variant: "warning", duration: 5500 });
+ }, 2000);
+ break;
+ }
+ };
+
+ return (
+
+
+
+
Notification System Demo
+
Demonstrates toast notifications and inline banners with all variants.
+
+
+ {/* Toast Queue Section */}
+
+ Toast Notifications
+
+
+
+
Stacking Limit
+
Current limit: {limit}
+
+
+
+
+
+
+
+
+
+
Active toasts: {toasts.length}
+
+
+
+
+
+
+
+
+
+
+
+
Mock Common Flows
+
+
+
+
+
+
+
+
+ {/* Inline Banner Section */}
+
+ Inline Banners
+
+
+
+
+
+
+
+ {showBanner && (
+
+
+ This is an inline banner with the {showBanner} variant. It can be used for page-level messages that require user attention.
+
+
+
+ )}
+
+
+ {/* Notification Center Section */}
+
+ Notification Center
+
+
+
+
In-App Notification Center
+
View and manage transaction and system event notifications
+
+
+
+ {showNotificationCenter && (
+
+
+
+ )}
+
+
+
+ {/* Accessibility Notes */}
+
+ Accessibility Features
+
+
+
+
+
Keyboard Focusable
+
Close buttons are focusable with Tab key and can be activated with Enter/Space
+
+
+
+
+
+
Screen Reader Announcements
+
Uses aria-live regions for polite (info/success) and assertive (warning/error) announcements
+
+
+
+
+
+
Pause on Hover/Focus
+
Auto-dismiss timer pauses when hovering or focusing on toast
+
+
+
+
+
+
Auto-Dismiss (3-6s)
+
Toasts automatically dismiss after 3-6 seconds (configurable)
+
+
+
+
+
+
44px Touch Target
+
Preference toggle controls meet minimum touch target requirements
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/demo/release-checklist/page.tsx b/src/app/demo/release-checklist/page.tsx
new file mode 100644
index 0000000..e04403e
--- /dev/null
+++ b/src/app/demo/release-checklist/page.tsx
@@ -0,0 +1,442 @@
+"use client";
+
+import { useState } from "react";
+import { Button } from "@/components/ui/Button";
+import { Input } from "@/components/ui/Input";
+import {
+ ReleaseChecklist,
+ ChecklistItem,
+ ChecklistStatus,
+ SignOff,
+ KnownIssue
+} from "@/lib/release-checklist-types";
+import {
+ CheckCircle2,
+ Clock,
+ XCircle,
+ AlertTriangle,
+ Download,
+ Plus,
+ Trash2,
+ Edit2,
+ Save
+} from "lucide-react";
+
+const statusConfig: Record = {
+ pending: { label: "Pending", color: "bg-slate-500/20 text-slate-300 border-slate-500/30", icon: Clock },
+ "in-progress": { label: "In Progress", color: "bg-sky-500/20 text-sky-300 border-sky-500/30", icon: Clock },
+ completed: { label: "Completed", color: "bg-emerald-500/20 text-emerald-300 border-emerald-500/30", icon: CheckCircle2 },
+ blocked: { label: "Blocked", color: "bg-red-500/20 text-red-300 border-red-500/30", icon: XCircle },
+ skipped: { label: "Skipped", color: "bg-amber-500/20 text-amber-300 border-amber-500/30", icon: AlertTriangle },
+};
+
+const severityConfig: Record = {
+ critical: { label: "Critical", color: "bg-red-500/20 text-red-300 border-red-500/30" },
+ high: { label: "High", color: "bg-orange-500/20 text-orange-300 border-orange-500/30" },
+ medium: { label: "Medium", color: "bg-amber-500/20 text-amber-300 border-amber-500/30" },
+ low: { label: "Low", color: "bg-slate-500/20 text-slate-300 border-slate-500/30" },
+};
+
+export default function ReleaseChecklistPage() {
+ const [checklist, setChecklist] = useState({
+ id: "1",
+ version: "v1.0.0",
+ title: "Release v1.0.0 - Initial Launch",
+ description: "Initial production release of NeuroWealth platform",
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ sections: [
+ {
+ id: "functional",
+ title: "Functional Checks",
+ items: [
+ {
+ id: "f1",
+ title: "User authentication flow",
+ description: "Verify login, signup, and wallet connection",
+ status: "completed",
+ assignee: "John",
+ priority: "high",
+ },
+ {
+ id: "f2",
+ title: "Transaction processing",
+ description: "Test deposit, withdrawal, and strategy execution",
+ status: "in-progress",
+ assignee: "Sarah",
+ priority: "high",
+ },
+ {
+ id: "f3",
+ title: "Data persistence",
+ description: "Verify localStorage and API data sync",
+ status: "pending",
+ assignee: "Mike",
+ priority: "medium",
+ },
+ {
+ id: "f4",
+ title: "Error handling",
+ description: "Test error states and user feedback",
+ status: "pending",
+ assignee: "John",
+ priority: "high",
+ },
+ ],
+ },
+ {
+ id: "visual",
+ title: "Visual Checks",
+ items: [
+ {
+ id: "v1",
+ title: "Responsive design",
+ description: "Verify layout on mobile, tablet, and desktop",
+ status: "completed",
+ assignee: "Emma",
+ priority: "high",
+ },
+ {
+ id: "v2",
+ title: "Color contrast",
+ description: "Check WCAG AA compliance for all text",
+ status: "in-progress",
+ assignee: "Emma",
+ priority: "medium",
+ },
+ {
+ id: "v3",
+ title: "Animation performance",
+ description: "Verify smooth animations at 60fps",
+ status: "pending",
+ assignee: "Sarah",
+ priority: "low",
+ },
+ ],
+ },
+ ],
+ knownIssues: [
+ {
+ id: "k1",
+ title: "Mobile menu animation stutter",
+ description: "Menu animation has slight stutter on older Android devices",
+ severity: "low",
+ workaround: "Use tap instead of swipe",
+ status: "open",
+ },
+ ],
+ signOffs: [
+ { role: "product", name: "", status: "pending", notes: "" },
+ { role: "design", name: "", status: "pending", notes: "" },
+ { role: "engineering", name: "", status: "pending", notes: "" },
+ ],
+ });
+
+ const [editingItem, setEditingItem] = useState(null);
+ const [editingSignOff, setEditingSignOff] = useState(null);
+
+ const updateItemStatus = (sectionId: string, itemId: string, status: ChecklistStatus) => {
+ setChecklist((prev) => ({
+ ...prev,
+ sections: prev.sections.map((section) =>
+ section.id === sectionId
+ ? {
+ ...section,
+ items: section.items.map((item) =>
+ item.id === itemId ? { ...item, status } : item
+ ),
+ }
+ : section
+ ),
+ updatedAt: new Date().toISOString(),
+ }));
+ };
+
+ const updateItemAssignee = (sectionId: string, itemId: string, assignee: string) => {
+ setChecklist((prev) => ({
+ ...prev,
+ sections: prev.sections.map((section) =>
+ section.id === sectionId
+ ? {
+ ...section,
+ items: section.items.map((item) =>
+ item.id === itemId ? { ...item, assignee } : item
+ ),
+ }
+ : section
+ ),
+ updatedAt: new Date().toISOString(),
+ }));
+ };
+
+ const updateSignOff = (role: "product" | "design" | "engineering", updates: Partial) => {
+ setChecklist((prev) => ({
+ ...prev,
+ signOffs: prev.signOffs.map((signOff) =>
+ signOff.role === role ? { ...signOff, ...updates } : signOff
+ ),
+ updatedAt: new Date().toISOString(),
+ }));
+ };
+
+ const exportSummary = () => {
+ const completedItems = checklist.sections.reduce(
+ (acc, section) => acc + section.items.filter((i) => i.status === "completed").length,
+ 0
+ );
+ const totalItems = checklist.sections.reduce((acc, section) => acc + section.items.length, 0);
+ const progress = Math.round((completedItems / totalItems) * 100);
+
+ const summary = `
+# Release Checklist: ${checklist.title}
+Version: ${checklist.version}
+Last Updated: ${new Date(checklist.updatedAt).toLocaleString()}
+
+## Progress: ${progress}% (${completedItems}/${totalItems} items completed)
+
+${checklist.sections.map(
+ (section) => {
+ const sectionCompleted = section.items.filter((i) => i.status === "completed").length;
+ return `
+### ${section.title} (${sectionCompleted}/${section.items.length})
+${section.items.map((item) => `- [${item.status === "completed" ? "x" : " "}] ${item.title} (${item.assignee || "Unassigned"})`).join("\n")}
+`;
+ }
+).join("\n")}
+
+## Known Issues
+${checklist.knownIssues.length === 0 ? "None" : checklist.knownIssues.map((issue) => `- **${issue.title}** (${issue.severity}): ${issue.description}`).join("\n")}
+
+## Sign-offs
+${checklist.signOffs.map((signOff) => `- **${signOff.role.charAt(0).toUpperCase() + signOff.role.slice(1)}**: ${signOff.name || "Pending"} (${signOff.status})`).join("\n")}
+`.trim();
+
+ const blob = new Blob([summary], { type: "text/markdown" });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = `release-checklist-${checklist.version}.md`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ };
+
+ const completedCount = checklist.sections.reduce(
+ (acc, section) => acc + section.items.filter((i) => i.status === "completed").length,
+ 0
+ );
+ const totalCount = checklist.sections.reduce((acc, section) => acc + section.items.length, 0);
+ const progress = Math.round((completedCount / totalCount) * 100);
+
+ return (
+
+
+ {/* Header */}
+
+
+
{checklist.title}
+
{checklist.description}
+
+
+
+ Progress:
+ {progress}%
+
+
+
+
+
+ {/* Progress Bar */}
+
+
+
+ {completedCount} of {totalCount} items completed
+
+
+
+ {/* Checklist Sections */}
+
+ {checklist.sections.map((section) => (
+
+
+
{section.title}
+
+ {section.items.filter((i) => i.status === "completed").length} / {section.items.length} completed
+
+
+
+ {section.items.map((item) => {
+ const config = statusConfig[item.status];
+ const StatusIcon = config.icon;
+ return (
+
+
+
+
+
+
+
{item.title}
+ {item.description && (
+
{item.description}
+ )}
+
+
+
+
+
+
+ Assignee:
+ {editingItem === item.id ? (
+ {
+ updateItemAssignee(section.id, item.id, e.target.value);
+ setEditingItem(null);
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ updateItemAssignee(section.id, item.id, e.currentTarget.value);
+ setEditingItem(null);
+ }
+ }}
+ autoFocus
+ className="bg-dark-900 border border-sky-500/50 rounded px-2 py-1 text-white text-xs w-24 focus:outline-none"
+ />
+ ) : (
+
+ )}
+
+
+
+
+ );
+ })}
+
+
+ ))}
+
+
+ {/* Known Issues */}
+
+
+
+
Known Issues
+
+ {checklist.knownIssues.length} issue{checklist.knownIssues.length !== 1 ? "s" : ""}
+
+
+
+
+ {checklist.knownIssues.map((issue) => (
+
+
+
+
+
{issue.title}
+
+ {severityConfig[issue.severity].label}
+
+
+
{issue.description}
+ {issue.workaround && (
+
+
+ Workaround: {issue.workaround}
+
+
+ )}
+
+
+
+ ))}
+ {checklist.knownIssues.length === 0 && (
+
+ No known issues
+
+ )}
+
+
+
+ {/* Sign-offs */}
+
+
+
Sign-offs
+
+ Required approvals before release
+
+
+
+ {checklist.signOffs.map((signOff) => (
+
+
+
+
{signOff.role}
+ {signOff.notes && (
+
{signOff.notes}
+ )}
+
+
+ updateSignOff(signOff.role, { name: e.target.value })}
+ className="bg-dark-900 border border-white/10 rounded-lg px-3 py-2 text-white text-sm w-32 md:w-40 focus:outline-none focus:ring-2 focus:ring-sky-500/50"
+ />
+
+
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/ui/Switch.tsx b/src/components/ui/Switch.tsx
index b1220dd..56bbb46 100644
--- a/src/components/ui/Switch.tsx
+++ b/src/components/ui/Switch.tsx
@@ -9,7 +9,7 @@ interface SwitchProps {
export function Switch({ checked, onChange, label, disabled = false }: SwitchProps) {
return (
-