π This is a great first issue β it's visible, self-contained, touches a handful of well-understood pages, and it noticeably improves how polished the whole app feels.
Background
Swipely has many data-driven pages, and right now they don't handle two very common situations consistently: while data is loading, and when there's no data to show. Some pages render a blank area, some show a bare spinner, some show nothing at all until data arrives. To a user, a blank panel is indistinguishable from a broken one β they can't tell whether the app is working, still loading, or genuinely empty. There's already an open issue about the empty state on the Bridges page specifically; this issue generalizes that fix into a consistent pattern across the primary pages.
Why this matters
Loading and empty states are small details that disproportionately shape how trustworthy an app feels. A skeleton that matches the shape of the incoming content tells the user "this is working, hold on" without a jarring layout jump. A friendly empty state tells them "there's genuinely nothing here β and here's what you can do about it" instead of leaving them staring at a blank rectangle wondering if something failed. Making these consistent across pages also makes the codebase more predictable for the next contributor.
What needs to be done
- Establish or reuse a small set of shared building blocks: a loading skeleton/placeholder and an
EmptyState component. Check src/components/ first β these may already exist, in which case reuse them rather than creating new ones.
- Apply them consistently to the primary list/data pages β for example
Bridges.tsx, Watchlist.tsx, Alerts.tsx, Incidents.tsx, and Transactions.tsx:
- Loading: show a skeleton that roughly matches the eventual content's shape, so there's no layout shift when data arrives.
- Empty: show a friendly
EmptyState with a helpful message. Where filters or search can cause emptiness, distinguish "nothing here yet" from "nothing matches your current filter," and offer a way to clear the filters in the latter case.
- Route all user-facing copy through the existing internationalization setup (
react-i18next) rather than hardcoding strings.
- Respect reduced-motion preferences for any shimmer/animation on the skeletons.
Where to look
src/components/ β existing EmptyState and skeleton primitives to reuse if present
src/pages/Bridges.tsx, Watchlist.tsx, Alerts.tsx, Incidents.tsx, Transactions.tsx
src/i18n/ β for the localized copy
Acceptance criteria
Notes
Scoped to the primary pages so it stays approachable β the remaining pages are future-batch work. If you're unsure whether a shared component already exists, just ask in the comments and someone will point you at it. π
π This is a great first issue β it's visible, self-contained, touches a handful of well-understood pages, and it noticeably improves how polished the whole app feels.
Background
Swipely has many data-driven pages, and right now they don't handle two very common situations consistently: while data is loading, and when there's no data to show. Some pages render a blank area, some show a bare spinner, some show nothing at all until data arrives. To a user, a blank panel is indistinguishable from a broken one β they can't tell whether the app is working, still loading, or genuinely empty. There's already an open issue about the empty state on the Bridges page specifically; this issue generalizes that fix into a consistent pattern across the primary pages.
Why this matters
Loading and empty states are small details that disproportionately shape how trustworthy an app feels. A skeleton that matches the shape of the incoming content tells the user "this is working, hold on" without a jarring layout jump. A friendly empty state tells them "there's genuinely nothing here β and here's what you can do about it" instead of leaving them staring at a blank rectangle wondering if something failed. Making these consistent across pages also makes the codebase more predictable for the next contributor.
What needs to be done
EmptyStatecomponent. Checksrc/components/first β these may already exist, in which case reuse them rather than creating new ones.Bridges.tsx,Watchlist.tsx,Alerts.tsx,Incidents.tsx, andTransactions.tsx:EmptyStatewith a helpful message. Where filters or search can cause emptiness, distinguish "nothing here yet" from "nothing matches your current filter," and offer a way to clear the filters in the latter case.react-i18next) rather than hardcoding strings.Where to look
src/components/β existingEmptyStateand skeleton primitives to reuse if presentsrc/pages/Bridges.tsx,Watchlist.tsx,Alerts.tsx,Incidents.tsx,Transactions.tsxsrc/i18n/β for the localized copyAcceptance criteria
EmptyStatewhen emptyNotes
Scoped to the primary pages so it stays approachable β the remaining pages are future-batch work. If you're unsure whether a shared component already exists, just ask in the comments and someone will point you at it. π