From 928cac67995ca6d2c0e7b678703a2cf9b3b7d498 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 29 Jan 2026 00:43:59 +0000 Subject: [PATCH] feat(questions): add production-ready pages and components - Add forgot-password page with email recovery flow - Add settings page with account, theme, notifications, privacy options - Add collections management page with create/edit/delete functionality - Add CollectionModal component for collection CRUD - Add ErrorAlert component for consistent error handling - Add loading skeletons (QuestionSkeleton, QuestionDetailSkeleton, AppLoadingSkeleton) - Update layouts and pages to use skeletons and error handling https://claude.ai/code/session_01Rk3YVJCU3nM8uvVPghRz6r --- .../src/lib/components/CollectionModal.svelte | 218 ++++++++++++++++++ .../web/src/lib/components/ErrorAlert.svelte | 39 ++++ .../apps/web/src/lib/components/index.ts | 3 + .../skeletons/AppLoadingSkeleton.svelte | 47 ++++ .../skeletons/QuestionDetailSkeleton.svelte | 56 +++++ .../skeletons/QuestionSkeleton.svelte | 32 +++ .../web/src/lib/components/skeletons/index.ts | 3 + .../apps/web/src/routes/(app)/+layout.svelte | 4 +- .../apps/web/src/routes/(app)/+page.svelte | 16 +- .../src/routes/(app)/collections/+page.svelte | 162 +++++++++++++ .../routes/(app)/question/[id]/+page.svelte | 19 +- .../src/routes/(app)/settings/+page.svelte | 178 ++++++++++++++ .../(auth)/forgot-password/+page.svelte | 81 +++++++ .../apps/web/src/routes/+layout.svelte | 10 +- 14 files changed, 845 insertions(+), 23 deletions(-) create mode 100644 apps/questions/apps/web/src/lib/components/CollectionModal.svelte create mode 100644 apps/questions/apps/web/src/lib/components/ErrorAlert.svelte create mode 100644 apps/questions/apps/web/src/lib/components/index.ts create mode 100644 apps/questions/apps/web/src/lib/components/skeletons/AppLoadingSkeleton.svelte create mode 100644 apps/questions/apps/web/src/lib/components/skeletons/QuestionDetailSkeleton.svelte create mode 100644 apps/questions/apps/web/src/lib/components/skeletons/QuestionSkeleton.svelte create mode 100644 apps/questions/apps/web/src/lib/components/skeletons/index.ts create mode 100644 apps/questions/apps/web/src/routes/(app)/collections/+page.svelte create mode 100644 apps/questions/apps/web/src/routes/(app)/settings/+page.svelte create mode 100644 apps/questions/apps/web/src/routes/(auth)/forgot-password/+page.svelte diff --git a/apps/questions/apps/web/src/lib/components/CollectionModal.svelte b/apps/questions/apps/web/src/lib/components/CollectionModal.svelte new file mode 100644 index 000000000..5cf5846ec --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/CollectionModal.svelte @@ -0,0 +1,218 @@ + + + +
+
e.stopPropagation()}> + +
+

+ {collection ? 'Edit Collection' : 'New Collection'} +

+ +
+ + +
+ {#if error} +
+ {error} +
+ {/if} + + +
+ + +
+ + +
+ + +
+ + +
+ +
+ {#each colors as c} + + {/each} +
+
+ + +
+ +
+ {#each icons as i} + + {/each} +
+
+ + +
+ +
+ + +
+ + +
+
+
+
diff --git a/apps/questions/apps/web/src/lib/components/ErrorAlert.svelte b/apps/questions/apps/web/src/lib/components/ErrorAlert.svelte new file mode 100644 index 000000000..600e60485 --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/ErrorAlert.svelte @@ -0,0 +1,39 @@ + + + diff --git a/apps/questions/apps/web/src/lib/components/index.ts b/apps/questions/apps/web/src/lib/components/index.ts new file mode 100644 index 000000000..5132757ad --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/index.ts @@ -0,0 +1,3 @@ +export { default as CollectionModal } from './CollectionModal.svelte'; +export { default as ErrorAlert } from './ErrorAlert.svelte'; +export * from './skeletons'; diff --git a/apps/questions/apps/web/src/lib/components/skeletons/AppLoadingSkeleton.svelte b/apps/questions/apps/web/src/lib/components/skeletons/AppLoadingSkeleton.svelte new file mode 100644 index 000000000..543a9b282 --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/skeletons/AppLoadingSkeleton.svelte @@ -0,0 +1,47 @@ +
+ + + + +
+
+
+
+
+ +
+
+
+
+
+ +
+ {#each Array(5) as _} +
+ {/each} +
+
+
diff --git a/apps/questions/apps/web/src/lib/components/skeletons/QuestionDetailSkeleton.svelte b/apps/questions/apps/web/src/lib/components/skeletons/QuestionDetailSkeleton.svelte new file mode 100644 index 000000000..067724d23 --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/skeletons/QuestionDetailSkeleton.svelte @@ -0,0 +1,56 @@ +
+ +
+
+
+
+ +
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + +
+
+
+ {#each Array(3) as _} +
+
+
+
+
+
+
+
+
+
+
+
+
+ {/each} +
+
+
diff --git a/apps/questions/apps/web/src/lib/components/skeletons/QuestionSkeleton.svelte b/apps/questions/apps/web/src/lib/components/skeletons/QuestionSkeleton.svelte new file mode 100644 index 000000000..f0adafcb6 --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/skeletons/QuestionSkeleton.svelte @@ -0,0 +1,32 @@ + + +
+ {#each Array(count) as _, i} +
+
+ +
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
+
+ {/each} +
diff --git a/apps/questions/apps/web/src/lib/components/skeletons/index.ts b/apps/questions/apps/web/src/lib/components/skeletons/index.ts new file mode 100644 index 000000000..c67f8fdce --- /dev/null +++ b/apps/questions/apps/web/src/lib/components/skeletons/index.ts @@ -0,0 +1,3 @@ +export { default as QuestionSkeleton } from './QuestionSkeleton.svelte'; +export { default as QuestionDetailSkeleton } from './QuestionDetailSkeleton.svelte'; +export { default as AppLoadingSkeleton } from './AppLoadingSkeleton.svelte'; diff --git a/apps/questions/apps/web/src/routes/(app)/+layout.svelte b/apps/questions/apps/web/src/routes/(app)/+layout.svelte index 592cb5a17..32919ea7b 100644 --- a/apps/questions/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/questions/apps/web/src/routes/(app)/+layout.svelte @@ -119,11 +119,11 @@ {#if sidebarOpen} - Add Collection + Manage Collections {/if} diff --git a/apps/questions/apps/web/src/routes/(app)/+page.svelte b/apps/questions/apps/web/src/routes/(app)/+page.svelte index 60b85e7cd..2fd175053 100644 --- a/apps/questions/apps/web/src/routes/(app)/+page.svelte +++ b/apps/questions/apps/web/src/routes/(app)/+page.svelte @@ -1,5 +1,6 @@ + +
+ +
+
+ + + Back to questions + +

Collections

+

+ Organize your questions into collections +

+
+ +
+ + + {#if collectionsStore.collections.length === 0} +
+
📁
+

No collections yet

+

+ Create your first collection to organize your questions. +

+ +
+ {:else} +
+ {#each collectionsStore.collections as collection} +
+ +
+ +
+ + +
+ +
+ + +
+
+

{collection.name}

+ {#if collection.isDefault} + + Default + + {/if} +
+ {#if collection.description} +

+ {collection.description} +

+ {/if} +

+ {collection.questionCount || 0} questions +

+
+ + +
+ + + {#if deleteConfirm === collection.id} +
+ + +
+ {:else} + + {/if} +
+
+ {/each} +
+ {/if} +
+ + +{#if showModal} + +{/if} diff --git a/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte b/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte index 5a0340811..64275a10d 100644 --- a/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte +++ b/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte @@ -4,6 +4,7 @@ import { questionsApi } from '$lib/api/questions'; import { researchApi } from '$lib/api/research'; import { sourcesApi } from '$lib/api/sources'; + import { QuestionDetailSkeleton, ErrorAlert } from '$lib/components'; import { ArrowLeft, Clock, @@ -95,16 +96,14 @@ } +{#if loading} + +{:else if error} +
+ +
+{:else if question}
- {#if loading} -
- -
- {:else if error} -
- {error} -
- {:else if question} {/if} - {/if}
+{/if} diff --git a/apps/questions/apps/web/src/routes/(app)/settings/+page.svelte b/apps/questions/apps/web/src/routes/(app)/settings/+page.svelte new file mode 100644 index 000000000..68be920cc --- /dev/null +++ b/apps/questions/apps/web/src/routes/(app)/settings/+page.svelte @@ -0,0 +1,178 @@ + + +
+ + + + +
+

+ + Account +

+
+
+
+ +

{authStore.user?.email || 'Not signed in'}

+
+
+ +

{authStore.user?.id || '-'}

+
+
+
+
+ + +
+

+ + Appearance +

+
+ +
+ {#each themeOptions as option} + + {/each} +
+
+
+ + +
+

+ + Notifications +

+
+
+ + + +
+
+
+ + +
+

+ + Privacy & Data +

+
+
+
+

Export Data

+

+ Download all your questions and research data +

+ +
+ +
+ +
+

Delete Account

+

+ Permanently delete your account and all data +

+ {#if deleteConfirm} +
+ + +
+ {:else} + + {/if} +
+
+
+
+ + +
+
+

+ Questions App v1.0.0 +
+ Powered by mana-search +

+
+
+
diff --git a/apps/questions/apps/web/src/routes/(auth)/forgot-password/+page.svelte b/apps/questions/apps/web/src/routes/(auth)/forgot-password/+page.svelte new file mode 100644 index 000000000..e6216ba0e --- /dev/null +++ b/apps/questions/apps/web/src/routes/(auth)/forgot-password/+page.svelte @@ -0,0 +1,81 @@ + + +
+
+

Reset Password

+

Enter your email to receive a reset link

+
+ + {#if success} +
+
📧
+

Check your email

+

+ We've sent a password reset link to {email}. Please check your inbox. +

+ Back to login +
+ {:else} +
+ {#if error} +
+ {error} +
+ {/if} + +
+ + +
+ + +
+ + + {/if} +
diff --git a/apps/questions/apps/web/src/routes/+layout.svelte b/apps/questions/apps/web/src/routes/+layout.svelte index 39771babd..8e870768c 100644 --- a/apps/questions/apps/web/src/routes/+layout.svelte +++ b/apps/questions/apps/web/src/routes/+layout.svelte @@ -4,6 +4,7 @@ import { theme } from '$lib/stores/theme'; import { authStore } from '$lib/stores/auth.svelte'; import { apiClient } from '$lib/api/client'; + import { AppLoadingSkeleton } from '$lib/components/skeletons'; let { children } = $props(); @@ -24,14 +25,7 @@ {#if loading} -
-
-
-

Loading...

-
-
+ {:else}
{@render children()}