Skip to content

improve auth accessibility and consistency#310

Merged
InfinityBowman merged 7 commits into
mainfrom
309-auth-accessibility
Jan 19, 2026
Merged

improve auth accessibility and consistency#310
InfinityBowman merged 7 commits into
mainfrom
309-auth-accessibility

Conversation

@InfinityBowman
Copy link
Copy Markdown
Owner

@InfinityBowman InfinityBowman commented Jan 18, 2026

Summary by CodeRabbit

  • New Features

    • Introduced a semantic design-token system and dark-mode tokens.
    • Added tabbed sign-in (Password / Email Link) with animated panel sizing.
    • Password visibility toggle in reset-password flow.
  • Improvements

    • Widespread visual updates to components and pages to use tokens.
    • Accessibility enhancements across auth flows (status/alert roles, aria-describedby, radiogroup semantics).
    • Tighter error-message associations for form inputs.
  • Other Changes

    • Updated redirect target for unauthenticated users.

✏️ Tip: You can customize this high-level summary in your review settings.

@InfinityBowman InfinityBowman linked an issue Jan 18, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 18, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Replaces hard-coded color usage with a semantic design-token system (light/dark tokens and radii), updates the style guide and global CSS, and applies accessibility and structural updates across many auth and settings UI components (ARIA attributes, form wiring, layout/step/panel reorganizations).

Changes

Cohort / File(s) Summary
Design System Foundation
packages/docs/guides/style-guide.md, packages/web/src/global.css
Introduces semantic design tokens (background, foreground, card, primary, secondary, muted, accent, destructive, success, warning, border, input, ring) and radius tokens with light/dark OKLCH values; updates docs to show token usage and removes legacy color references.
Auth: Layouts & Flows
packages/web/src/components/auth/SignIn.jsx, packages/web/src/components/auth/SignUp.jsx, packages/web/src/components/auth/CompleteProfile.jsx, packages/web/src/components/auth/CheckEmail.jsx, packages/web/src/components/auth/ResetPassword.jsx
Reworks sign-in into a tabbed multi-panel (password / magic link) with measured form height animation; refactors sign-up, complete-profile (stepper), check-email and reset-password layouts; replaces password inputs with PasswordInput primitives and adds IDs/aria-describedby where applicable.
Auth: Accessibility & Error Handling
packages/web/src/components/auth/ErrorMessage.jsx, packages/web/src/components/auth/MagicLinkForm.jsx, packages/web/src/components/auth/TwoFactorVerify.jsx, packages/web/src/components/auth/RoleSelector.jsx, packages/web/src/components/auth/ProtectedGuard.jsx
ErrorMessage now exposes role/aria-live and optional id for aria-describedby; inputs wire to error ids; RoleSelector uses radiogroup/role="radio"/aria-checked; ProtectedGuard redirect changed to /signin.
Auth: Buttons & Loading States
packages/web/src/components/auth/AuthButtons.jsx, packages/web/src/components/auth/AuthLayout.jsx, packages/web/src/components/auth/SocialAuthButtons.jsx
AuthButtons add aria-busy and accessible status regions for loading; AuthLayout simplified wrapper structure; SocialAuthButtons add aria-labels, aria-hidden on decorative imagery, and role="status" loading indicators.
Settings UI Adjustments
packages/web/src/components/settings/pages/ProfileSettings.jsx, packages/web/src/components/settings/pages/AcademicInfoSection.jsx, packages/web/src/components/settings/pages/PersonaSection.jsx
Replace slate color classes with semantic tokens (bg-card, border-border, text-foreground, text-muted-foreground), adjust spacing and typography (pt-5→pt-4, py-5→py-4, smaller text sizes) and refine fallback layouts.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'improve auth accessibility and consistency' directly summarizes the main changes across the PR, which focus on adding accessibility attributes, refactoring components, and updating styling to be consistent with a new design token system.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0fd6a48 and d7d829b.

📒 Files selected for processing (1)
  • packages/web/src/components/auth/SignIn.jsx

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jan 18, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
corates d7d829b Commit Preview URL Jan 19 2026, 03:13 AM

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/components/auth/CompleteProfile.jsx (1)

76-77: Use createFormErrorSignals for form errors instead of a single error signal.

This form currently manages errors with a single error signal. The codebase standard is to use createFormErrorSignals so field-level and global errors stay consistent across auth flows. As per coding guidelines, please align this form’s error handling with createFormErrorSignals.

🤖 Fix all issues with AI agents
In `@packages/web/src/components/auth/SignIn.jsx`:
- Around line 268-351: The inactive tab panels need the inert attribute to block
keyboard focus; add inert to the password panel (the div using ref
passwordFormRef / id 'panel-password') and to the magic link panel (the div
using ref magicLinkFormRef / id 'panel-magic-link') so that inert mirrors
aria-hidden (use inert={useMagicLink()} on the password panel and
inert={!useMagicLink()} on the magic-link panel) ensuring hidden panels are
removed from keyboard navigation and the accessibility tree.
🧹 Nitpick comments (4)
packages/web/src/components/auth/RoleSelector.jsx (1)

56-77: Add arrow-key handling to complete the radiogroup keyboard pattern.

With role="radio", keyboard users expect Arrow keys to move selection within the group. Consider adding roving focus/selection handling so the radiogroup behaves consistently for keyboard and screen-reader users.

Proposed update
-      <For each={ROLES}>
-        {roleOption => (
+      <For each={ROLES}>
+        {(roleOption, index) => (
           <button
             type='button'
             role='radio'
             onClick={() => props.onSelect(roleOption.id)}
+            onKeyDown={e => {
+              if (!['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp'].includes(e.key)) return;
+              e.preventDefault();
+              const delta = e.key === 'ArrowRight' || e.key === 'ArrowDown' ? 1 : -1;
+              const nextIndex = (index() + delta + ROLES.length) % ROLES.length;
+              props.onSelect(ROLES[nextIndex].id);
+              const radios = e.currentTarget
+                .closest('[role="radiogroup"]')
+                ?.querySelectorAll('[role="radio"]');
+              radios?.[nextIndex]?.focus();
+            }}
             aria-checked={props.selectedRole === roleOption.id}
+            tabIndex={props.selectedRole === roleOption.id ? 0 : -1}
             class={`rounded-xl border-2 p-3 text-left transition-all hover:border-blue-400 hover:bg-blue-50 focus:ring-2 focus:ring-blue-500 focus:outline-none sm:p-4 ${
               props.selectedRole === roleOption.id ?
                 'border-blue-600 bg-blue-50'
               : 'border-gray-200'
             }`}
           >
packages/web/src/components/auth/AuthLayout.jsx (1)

55-61: Consider adding accessibility attributes to the loading spinner for consistency.

Other auth components in this PR add role="status" and aria-label to loading spinners (e.g., AuthButtons.jsx, SocialAuthButtons.jsx). This spinner could benefit from the same treatment for screen reader users.

Suggested improvement
       <Show when={showLoading()}>
         <div class='flex w-full max-w-md items-center justify-center sm:max-w-xl'>
           <div class='text-center'>
-            <div class='mx-auto h-12 w-12 animate-spin rounded-full border-b-2 border-blue-600' />
+            <div
+              role='status'
+              aria-label='Loading'
+              class='mx-auto h-12 w-12 animate-spin rounded-full border-b-2 border-blue-600'
+            />
             <p class='mt-4 text-gray-600'>Loading...</p>
           </div>
         </div>
       </Show>
packages/web/src/components/auth/AuthButtons.jsx (1)

24-29: Potential duplicate screen reader announcement.

The loading state currently has two announcement sources:

  1. aria-label on the spinner (role="status")
  2. aria-live="polite" on the text span

This may cause screen readers to announce the loading message twice. Consider removing aria-live from the span since the role="status" already implies aria-live="polite" and will announce its label.

Suggested fix
           <div
             role='status'
             aria-label={props.loadingText || 'Loading'}
             class='mr-2 h-5 w-5 animate-spin rounded-full border-2 border-white border-t-transparent'
           />
-          <span aria-live='polite'>{props.loadingText || 'Loading...'}</span>
+          <span>{props.loadingText || 'Loading...'}</span>
packages/web/src/components/auth/CheckEmail.jsx (1)

1-1: Use Solid Show for conditional rendering blocks

The loading branch and resent state are rendered with a ternary and &&. Prefer <Show> for conditional rendering in SolidJS for consistency and reactivity patterns. As per coding guidelines.

Proposed update
-import { createSignal, onMount, onCleanup } from 'solid-js';
+import { createSignal, onMount, onCleanup, Show } from 'solid-js';
@@
-      {loading() ?
-        <>
-          <div class='flex justify-center'>
-            <AiOutlineLoading3Quarters
-              class='animate-spin text-blue-600'
-              size={48}
-              role='status'
-              aria-label='Verifying email'
-            />
-          </div>
-          <h2 class='text-xl font-bold text-gray-900 sm:text-2xl'>Email Verified!</h2>
-          <p class='text-sm text-gray-600 sm:text-base'>Redirecting you to the dashboard...</p>
-        </>
-      : <>
-          <div class='flex justify-center'>
-            <div class='rounded-full bg-blue-100 p-4'>
-              <AiOutlineMail class='text-blue-600' size={48} />
-            </div>
-          </div>
-
-          <div>
-            <h2 class='mb-2 text-xl font-bold text-gray-900 sm:text-2xl'>Check Your Email</h2>
-            <p class='text-sm text-gray-600 sm:text-base'>We've sent a verification email to:</p>
-            <p class='mt-1 text-sm font-semibold text-blue-600 sm:text-base'>{email()}</p>
-          </div>
-
-          <div class='space-y-4'>
-            <p class='text-xs text-gray-500 sm:text-sm'>
-              Click the verification link in your email to activate your account. Once verified,
-              you'll automatically be redirected to the dashboard.
-            </p>
-
-            <ErrorMessage displayError={displayError} />
-
-            {resent() && (
-              <div class='rounded-lg border border-green-200 bg-green-50 p-3 text-xs text-green-600 sm:text-sm'>
-                Verification email sent successfully!
-              </div>
-            )}
-          </div>
-
-          <div class='space-y-3'>
-            <PrimaryButton
-              loading={resending()}
-              loadingText='Sending...'
-              type='button'
-              onClick={handleResendEmail}
-            >
-              Resend Email
-            </PrimaryButton>
-
-            <SecondaryButton onClick={handleBackToSignIn}>Back to Sign In</SecondaryButton>
-          </div>
-
-          <div class='text-xs text-gray-400 sm:text-sm'>
-            <p>Didn't receive the email? Check your spam folder or try resending.</p>
-          </div>
-        </>
-      }
+      <Show
+        when={loading()}
+        fallback={
+          <>
+            <div class='flex justify-center'>
+              <div class='rounded-full bg-blue-100 p-4'>
+                <AiOutlineMail class='text-blue-600' size={48} />
+              </div>
+            </div>
+
+            <div>
+              <h2 class='mb-2 text-xl font-bold text-gray-900 sm:text-2xl'>Check Your Email</h2>
+              <p class='text-sm text-gray-600 sm:text-base'>We've sent a verification email to:</p>
+              <p class='mt-1 text-sm font-semibold text-blue-600 sm:text-base'>{email()}</p>
+            </div>
+
+            <div class='space-y-4'>
+              <p class='text-xs text-gray-500 sm:text-sm'>
+                Click the verification link in your email to activate your account. Once verified,
+                you'll automatically be redirected to the dashboard.
+              </p>
+
+              <ErrorMessage displayError={displayError} />
+
+              <Show when={resent()}>
+                <div class='rounded-lg border border-green-200 bg-green-50 p-3 text-xs text-green-600 sm:text-sm'>
+                  Verification email sent successfully!
+                </div>
+              </Show>
+            </div>
+
+            <div class='space-y-3'>
+              <PrimaryButton
+                loading={resending()}
+                loadingText='Sending...'
+                type='button'
+                onClick={handleResendEmail}
+              >
+                Resend Email
+              </PrimaryButton>
+
+              <SecondaryButton onClick={handleBackToSignIn}>Back to Sign In</SecondaryButton>
+            </div>
+
+            <div class='text-xs text-gray-400 sm:text-sm'>
+              <p>Didn't receive the email? Check your spam folder or try resending.</p>
+            </div>
+          </>
+        }
+      >
+        <>
+          <div class='flex justify-center'>
+            <AiOutlineLoading3Quarters
+              class='animate-spin text-blue-600'
+              size={48}
+              role='status'
+              aria-label='Verifying email'
+            />
+          </div>
+          <h2 class='text-xl font-bold text-gray-900 sm:text-2xl'>Email Verified!</h2>
+          <p class='text-sm text-gray-600 sm:text-base'>Redirecting you to the dashboard...</p>
+        </>
+      </Show>

Also applies to: 130-188

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ea7692 and 0fd6a48.

📒 Files selected for processing (18)
  • packages/docs/guides/style-guide.md
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/global.css
🧰 Additional context used
📓 Path-based instructions (14)
packages/web/src/**/*.{js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)

packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from @/lib/formStatePersistence.js

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/web/src/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)

packages/web/src/**/*.{js,jsx,ts,tsx}: Always use uploadPdf from @api/pdf-api.js for uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
Use cachePdf and getCachedPdf from @primitives/pdfCache.js for caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
Use importFromGoogleDrive from @api/google-drive.js for importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state using saveFormState from @/lib/formStatePersistence.js before triggering OAuth redirects for Google Drive
Use addPdfToStudy operation from useProject hook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
Use removePdfFromStudy operation from useProject hook to remove PDFs from a study
Use pdfPreviewStore from @/stores/pdfPreviewStore.js for managing PDF preview state (openPreview, closePreview, getPreview methods)
Use downloadPdf from @api/pdf-api.js to download PDFs from server, then cache the result using cachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations from useProject hook instead of bypassing through direct API calls

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/web/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)

Use PdfViewer component from @/components/checklist-ui/pdf/PdfViewer.jsx for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)

{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS components

Use Show and For components for conditional and list rendering in SolidJS

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)

{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state

{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)

**/*.{js,jsx,ts,tsx}: Use the useProject hook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/web/src/**

📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)

packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/global.css
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/web/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

packages/web/**/*.{js,ts,jsx,tsx}: Use apiFetch for all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
Use handleFetchError for wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions like isErrorCode from error-utils to check specific error types instead of direct string comparisons

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/web/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

Use createFormErrorSignals for form error handling in frontend forms to manage field-level and global error states

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

Never throw string literals; always throw Error objects or return domain errors from API routes

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}

📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)

Shared or cross-feature state should use external stores located in packages/web/src/stores/

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
**/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/docs/guides/style-guide.md
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/global.css
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
packages/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention // TODO(agent): Brief description for incomplete work, flagging items for future attention, known limitations, and documentation section references

Use TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues

Files:

  • packages/web/src/components/settings/pages/AcademicInfoSection.jsx
  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/ProtectedGuard.jsx
  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/RoleSelector.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/web/src/components/settings/pages/ProfileSettings.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/settings/pages/PersonaSection.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
  • packages/web/src/components/auth/SocialAuthButtons.jsx
🧠 Learnings (20)
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities

Applied to files:

  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/auth/CheckEmail.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's Show component for conditional rendering instead of ternary operators

Applied to files:

  • packages/web/src/components/auth/AuthButtons.jsx
  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/docs/guides/style-guide.md
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
📚 Learning: 2026-01-06T23:56:57.354Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2026-01-06T23:56:57.354Z
Learning: Applies to packages/web/**/*.{jsx,tsx} : Use `createFormErrorSignals` for form error handling in frontend forms to manage field-level and global error states

Applied to files:

  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/ErrorMessage.jsx
  • packages/web/src/components/auth/TwoFactorVerify.jsx
  • packages/web/src/components/auth/SignUp.jsx
  • packages/web/src/components/auth/SignIn.jsx
  • packages/web/src/components/auth/ResetPassword.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/components/project-ui/**/*.{js,jsx} : Form state should include serializable metadata when handling files (name, size, type) and use the store's pendingPdfs pattern for actual File objects that persist across redirects

Applied to files:

  • packages/web/src/components/auth/MagicLinkForm.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Save form state using `saveFormState` from `@/lib/formStatePersistence.js` before triggering OAuth redirects for Google Drive

Applied to files:

  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/**/*.{js,jsx} : Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()

Applied to files:

  • packages/web/src/components/auth/MagicLinkForm.jsx
  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/**/*.{js,jsx} : Add restore parameters to the URL after OAuth redirects in the format '?restore=<formType>&projectId=<projectId>' to signal form state restoration on mount

Applied to files:

  • packages/web/src/components/auth/MagicLinkForm.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Show and For components for conditional and list rendering in SolidJS

Applied to files:

  • packages/web/src/components/auth/CompleteProfile.jsx
  • packages/docs/guides/style-guide.md
  • packages/web/src/components/auth/AuthLayout.jsx
  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components

Applied to files:

  • packages/docs/guides/style-guide.md
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components

Applied to files:

  • packages/docs/guides/style-guide.md
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use the children helper when manipulating props.children in SolidJS components

Applied to files:

  • packages/web/src/components/auth/AuthLayout.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity

Applied to files:

  • packages/web/src/components/auth/AuthLayout.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Prefer derived state with createMemo or signals over effects whenever possible

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple, reactive values in SolidJS

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Always clean up SolidJS effects that create subscriptions or timers using onCleanup

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for computed/derived values that depend on reactive state in SolidJS

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createStore for complex objects and arrays that need granular reactivity in SolidJS

Applied to files:

  • packages/web/src/components/auth/SignIn.jsx
🧬 Code graph analysis (6)
packages/web/src/components/settings/pages/AcademicInfoSection.jsx (3)
packages/web/src/components/settings/pages/PersonaSection.jsx (1)
  • user (39-39)
packages/web/src/components/settings/pages/DeleteAccountSection.jsx (1)
  • user (12-12)
packages/web/src/components/settings/pages/ProfileInfoSection.jsx (1)
  • user (34-34)
packages/web/src/components/auth/ProtectedGuard.jsx (1)
packages/web/src/api/better-auth-store.js (1)
  • isLoggedIn (195-207)
packages/web/src/components/auth/ErrorMessage.jsx (1)
packages/web/src/components/AnimatedShow.jsx (1)
  • AnimatedShow (15-66)
packages/web/src/components/auth/TwoFactorVerify.jsx (2)
packages/web/src/components/auth/SignIn.jsx (1)
  • displayError (92-92)
packages/web/src/components/auth/ErrorMessage.jsx (1)
  • ErrorMessage (10-21)
packages/web/src/components/auth/CheckEmail.jsx (2)
packages/web/src/components/auth/ErrorMessage.jsx (1)
  • ErrorMessage (10-21)
packages/web/src/components/auth/AuthButtons.jsx (2)
  • PrimaryButton (13-34)
  • SecondaryButton (44-55)
packages/web/src/components/auth/ResetPassword.jsx (2)
packages/web/src/components/ui/password-input.tsx (4)
  • PasswordInput (137-137)
  • PasswordInputControl (139-139)
  • PasswordInputField (140-140)
  • PasswordInputVisibilityTrigger (141-141)
packages/web/src/components/auth/ErrorMessage.jsx (1)
  • ErrorMessage (10-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: corates
🔇 Additional comments (22)
packages/web/src/components/auth/CompleteProfile.jsx (1)

269-276: Loading fallback looks solid.

The Show-based gating with a role="status" spinner cleanly avoids rendering the flow before auth resolves and provides a basic accessible loading affordance.

packages/web/src/components/auth/ProtectedGuard.jsx (1)

14-17: LGTM! Redirect target updated correctly.

The redirect to /signin is appropriate for unauthenticated users attempting to access protected pages. The effect properly waits for auth loading to complete before redirecting.

packages/web/src/components/settings/pages/PersonaSection.jsx (1)

73-87: LGTM! UI refinements look good.

The spacing and text styling adjustments are clean. The nested span structure properly handles the "Not set" fallback case with appropriate color differentiation.

packages/web/src/components/auth/AuthLayout.jsx (1)

63-63: LGTM! Simplified rendering structure.

Removing the extra wrapper div around children reduces unnecessary DOM nesting while maintaining the same conditional display logic.

packages/web/src/components/auth/AuthButtons.jsx (1)

20-20: Good accessibility addition.

Adding aria-busy to the button provides screen reader users with context that the button is processing.

packages/web/src/components/auth/SocialAuthButtons.jsx (3)

26-32: Excellent accessibility improvements on GoogleButton.

  • alt="" with aria-hidden="true" correctly marks the logo as decorative
  • role="status" with aria-label provides meaningful loading feedback to screen readers
  • Consistent pattern applied across both loading and non-loading states

44-57: Good aria-label on icon-only button variant.

The aria-label ensures the icon-only button is accessible when the visible text is not present.


86-117: OrcidButton follows the same accessible pattern as GoogleButton.

Consistent implementation across both social auth buttons maintains a predictable experience for assistive technology users.

packages/web/src/components/auth/ErrorMessage.jsx (2)

3-9: Good documentation clarifying the accessibility behavior.

The JSDoc clearly documents the component's purpose and the optional id prop for aria-describedby linking.


12-18: Accessibility improvements look good with one note.

The ariaLive='assertive' is appropriate for error messages as they require immediate attention. The id prop enables proper aria-describedby linking from form inputs.

Note: The comment states AnimatedShow already provides role="alert" by default (confirmed in the relevant code snippet), so explicitly passing it is redundant but harmless. The key change is overriding the default aria-live="polite" to "assertive" for more urgent error announcements.

packages/web/src/components/auth/TwoFactorVerify.jsx (1)

95-99: Good error association for the 2FA input.

aria-describedby now matches the ErrorMessage id, which improves assistive tech support.

packages/web/src/components/auth/MagicLinkForm.jsx (2)

103-103: Resend error region id is consistent.

No issues with the new id on the resend error region.


162-166: Input now references the form error region.

Conditional aria-describedby matches the ErrorMessage id.

packages/web/src/components/auth/ResetPassword.jsx (2)

23-31: Wrapper restructuring looks consistent.

No issues with the new outer container and token gating.


8-13: PasswordInput integration looks good; verify prop forwarding.

Please confirm that required and autoComplete are applied to the native input; otherwise move those props to PasswordInputField to keep browser validation and autofill working.

Run the following script to inspect the PasswordInput implementation:

#!/bin/bash
# Inspect password input component to verify prop forwarding.
# Expectation: PasswordInput or PasswordInputField applies required and autoComplete to the native input.
fd -a 'password-input' -e tsx -e ts -e jsx -e js -x sed -n '1,240p' {}

Also applies to: 210-250

packages/web/src/components/auth/SignUp.jsx (1)

110-179: Layout and error placement look consistent.

The new header and ordering read well.

packages/web/src/global.css (2)

16-21: Radius and semantic color tokens look consistent.

Light and dark token sets are coherent.

Also applies to: 34-111


22-31: Verify remaining references to brand color variables before deciding on uncomment/restore strategy.

The concern about undefined color variables is valid—if --color-brand-100 through --color-brand-800 are referenced anywhere in the stylesheet or component styles, keeping them commented out will cause those styles to fail. Search the codebase for any usage of --color-brand-* to determine whether restoration or deletion is appropriate.

packages/web/src/components/settings/pages/AcademicInfoSection.jsx (1)

103-127: Spacing and text size tweaks look fine.

No issues.

packages/web/src/components/settings/pages/ProfileSettings.jsx (1)

14-31: Token-based class updates look consistent

The semantic token classes for containers, cards, and icon treatments are consistent and should align well with theming updates.

Also applies to: 44-50

packages/docs/guides/style-guide.md (1)

12-552: Style guide token documentation updates look good

The token reference, usage examples, and component snippets read consistently with the new semantic token system.

packages/web/src/components/auth/SignIn.jsx (1)

32-35: Prevent panel clipping when content height changes

The container locks its height based on a single measurement and uses overflow-hidden. If the active form height changes (error message, helper text, or other dynamic content), the content can be clipped. Consider observing the active panel size and updating height whenever it changes, and cancel scheduled frames on cleanup.

Proposed update
-  const [formHeight, setFormHeight] = createSignal('auto');
-  let passwordFormRef;
-  let magicLinkFormRef;
+  const [formHeight, setFormHeight] = createSignal('auto');
+  let passwordFormRef;
+  let magicLinkFormRef;
+  let formResizeObserver;
@@
-  const updateFormHeight = () => {
-    const activeRef = useMagicLink() ? magicLinkFormRef : passwordFormRef;
-    if (activeRef) {
-      setFormHeight(`${activeRef.offsetHeight}px`);
-    }
-  };
+  const observeActiveForm = () => {
+    const activeRef = useMagicLink() ? magicLinkFormRef : passwordFormRef;
+    if (!activeRef) return;
+
+    formResizeObserver?.disconnect();
+    formResizeObserver = new ResizeObserver(() => {
+      setFormHeight(`${activeRef.offsetHeight}px`);
+    });
+    formResizeObserver.observe(activeRef);
+    setFormHeight(`${activeRef.offsetHeight}px`);
+  };
@@
-  onMount(() => {
-    // Small delay to ensure refs are measured after initial render
-    requestAnimationFrame(updateFormHeight);
-  });
+  onMount(() => {
+    // Small delay to ensure refs are measured after initial render
+    const frameId = requestAnimationFrame(observeActiveForm);
+    onCleanup(() => cancelAnimationFrame(frameId));
+    onCleanup(() => formResizeObserver?.disconnect());
+  });
@@
-  createEffect(() => {
-    // Track the signal
-    useMagicLink();
-    // Update after a frame to ensure layout is complete
-    requestAnimationFrame(updateFormHeight);
-  });
+  createEffect(() => {
+    // Track the signal
-    useMagicLink();
+    useMagicLink();
-    // Update after a frame to ensure layout is complete
+    // Update after a frame to ensure layout is complete
-    const frameId = requestAnimationFrame(observeActiveForm);
+    const frameId = requestAnimationFrame(observeActiveForm);
+    onCleanup(() => cancelAnimationFrame(frameId));
+  });

Also applies to: 69-89, 252-259

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread packages/web/src/components/auth/SignIn.jsx
@InfinityBowman InfinityBowman merged commit 559af44 into main Jan 19, 2026
1 of 3 checks passed
@InfinityBowman InfinityBowman deleted the 309-auth-accessibility branch January 19, 2026 03:09
@github-actions github-actions Bot restored the 309-auth-accessibility branch January 19, 2026 03:10
@coderabbitai coderabbitai Bot mentioned this pull request Jan 19, 2026
@InfinityBowman InfinityBowman deleted the 309-auth-accessibility branch March 29, 2026 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth accessibility

2 participants