paperclip/ui
Dotta 24aa2f516d
feat(ui): add animated paperclip page loaders (#10456)
## 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.

![Large centered paperclip loading state in light and dark
themes](https://pages.paperclip.ing/pap-15760-loading-state/pap15760-loading.png)

## 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>
2026-07-29 17:58:50 -07:00
..
public
src feat(ui): add animated paperclip page loaders (#10456) 2026-07-29 17:58:50 -07:00
storybook
README.md
components.json
index.html
package.json
tsconfig.json
vite.config.ts
vite.qa.config.mjs
vitest.config.ts
vitest.setup.ts

README.md

@paperclipai/ui

Published static assets for the Paperclip board UI.

What gets published

The npm package contains the production build under dist/. It does not ship the UI source tree or workspace-only dependencies.

Storybook

Storybook config, stories, and fixtures live under ui/storybook/.

pnpm --filter @paperclipai/ui storybook
pnpm --filter @paperclipai/ui build-storybook

Typical use

Install the package, then serve or copy the built files from node_modules/@paperclipai/ui/dist.