mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-06 21:05:21 +02:00
## Thinking Path > - Paperclip is the open source control plane people use to manage AI agents for work > - Operators regularly pass through full-page loading states while authentication and company context resolve > - Those states currently render as small bare text, which is easy to miss and does not reinforce Paperclip's visual identity > - A shared loading component gives these transitions one accessible, consistent representation > - This pull request introduces an animated paperclip loader and uses it at the existing full-page loading boundaries > - The benefit is a clearer, calmer loading experience with reduced-motion and screen-reader support ## Linked Issues or Issue Description ### Subsystem affected `ui/` — React + Vite board UI ### Problem or motivation Full-page authentication, access-gate, and company-context waits use small bare `Loading…` text that is visually weak and inconsistent. ### Proposed solution Use one large centered paperclip loader at those boundaries, drawing the SVG with `currentColor` so it follows the active theme. ### Alternatives considered Keeping text-only states or adding a generic spinner would preserve less of Paperclip's product identity and would continue duplicating loading markup. ### Roadmap alignment This is tightly scoped UI polish and does not duplicate a planned roadmap capability. ### Additional context Internal coordination task PAP-15760 requested this focused change. ## What Changed - Added `AnimatedPaperclipIcon`, a theme-aware SVG whose stroke draws in a loop. - Added `PaperclipLoading`, a large full-viewport centered loader with `role="status"` and an `sr-only` `Loading…` label. - Added a static fully drawn fallback under `prefers-reduced-motion: reduce`. - Replaced bare loading text in `CloudAccessGate`, the Auth session check, and three company-context redirects. - Used token-safe Tailwind utilities throughout the component. - Added focused coverage for the status semantics and the Auth layout height override. ## Verification - `pnpm check:token-gates` - `pnpm -C ui exec tsc -b` - `pnpm -C ui exec vitest run src/components/AnimatedPaperclipIcon.test.tsx` - `pnpm -C ui exec vitest run src/App.test.tsx src/App.cases-routing.test.tsx` — 8/8 tests passed - Visually checked light and dark loading states; the screenshot below shows both themes.  ## Risks - Low risk: this changes presentation only at existing loading branches. - Motion-sensitive users receive a static, fully drawn paperclip through the reduced-motion media query. - Screen readers retain a concise loading announcement through the status role and visually hidden label. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 (exact service build ID and context-window size are not exposed in this environment), with reasoning, repository inspection, shell tool use, code execution, and image inspection. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used with all deployment details available to this environment - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and found none - [x] I have described the issue in-PR following the feature-request fields - [x] I included the task-mandated internal parent reference and no private instance URL - [x] I preserved the task-mandated existing branch name without renaming it - [x] I have run scoped tests locally and they pass - [x] I added focused component coverage for the new loading state - [x] No documentation update is required for this presentation-only change - [x] I have considered and documented the risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import type { SVGProps } from "react";
|
|
import { cn } from "../lib/utils";
|
|
|
|
export function AnimatedPaperclipIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
|
|
return (
|
|
<svg
|
|
viewBox="-1 -1 26 26"
|
|
className={cn("paperclip-thinking-icon", className)}
|
|
aria-hidden="true"
|
|
{...props}
|
|
>
|
|
<path
|
|
className="paperclip-thinking-icon-path"
|
|
d="M16 6 l-8.414 8.586 a2.000 2.000 0 0 0 2.828 2.828 l8.414 -8.586 a4.000 4.000 0 1 0 -5.657 -5.657 l-8.379 8.551 a6.000 6.000 0 1 0 8.485 8.485 l8.379 -8.551"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
/** Full-page loading state: a large, centered, gray animated paperclip. */
|
|
export function PaperclipLoading({ className }: { className?: string }) {
|
|
return (
|
|
<div
|
|
role="status"
|
|
className={cn("flex min-h-dvh w-full items-center justify-center", className)}
|
|
>
|
|
<AnimatedPaperclipIcon className="h-24 w-24 text-muted-foreground" />
|
|
<span className="sr-only">Loading…</span>
|
|
</div>
|
|
);
|
|
}
|