Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Before diving in, these are the most common issues:

10. **Free tier has two axes**: `useFreeUploadLimit()` returns `{ freeUploadLimitBytes, freeTier }`. `freeUploadLimitBytes` (== `freeTier.maxItemBytes`) is the per-item size cap used by `isFileFree()`. `freeTier.lifetimeBytes` / `freeTier.ipBytes` are separate lifetime/IP quotas (0 = uncapped) shown in UI messaging — don't conflate them with the per-item limit.

11. **The store's `creditBalance` is spendable, not shareable**: `useCreditBalance` fills it from the payment service's `effectiveBalance`, which includes credits *other wallets shared with this one*. Those can pay for uploads but cannot be shared onward; only `winc` can. Anything that offers to share or hand credits on reads `toShareableBalance()` (`utils/shareableCredits.ts`), as `ShareCreditsPanel` does. Reading `creditBalance` there offers more than the service will approve.

## Architecture Overview

### Application Structure
Expand Down Expand Up @@ -769,7 +771,7 @@ its own surface or horizontal padding — that's a frame inside a frame and
double inset. Panels written for a standalone page (the `/topup` fiat and
crypto steps) carry both and gate them on being embedded.

All modal chrome lives in `components/modals/BaseModal.tsx` (~22 consumers). It provides Escape-to-close, a Tab focus trap, `role="dialog"`/`aria-modal`, body scroll lock, focus restore on close, and a labelled close button — **don't reimplement any of that in a consumer.** Two things to know:
All modal chrome lives in `components/modals/BaseModal.tsx` (~28 consumers). It provides Escape-to-close, a Tab focus trap, `role="dialog"`/`aria-modal`, body scroll lock, focus restore on close, and a labelled close button — **don't reimplement any of that in a consumer.** Two things to know:

- `showCloseButton` defaults to **true**. A dismiss affordance is opt-out, not opt-in.
- Modals **nest** (`WalletSelectionModal` renders `BlockingMessageModal` inside its own `BaseModal`), so BaseModal keeps a module-level stack: only the topmost instance answers Escape and traps Tab, and the scroll lock lifts only when the last one closes. Preserve that if you touch it.
Expand All @@ -787,6 +789,10 @@ All modal chrome lives in `components/modals/BaseModal.tsx` (~22 consumers). It

**Every routed screen has the same body width, on every device.** `Layout` wraps the outlet in `max-w-site`, and each screen's outermost element is `px-4 sm:px-6`, which also gives phones the same side gutter everywhere. **A screen must not add its own `mx-auto max-w-*` cap.** Name Detail (`max-w-5xl`), Pages (`max-w-6xl`) and two views inside Pages (`max-w-3xl`, `max-w-xl`) each had one, so they read as narrower than Upload or Deploy for no reason. Narrow measures are still right *inside* a screen: a centred empty-state sentence (`max-w-md`), prose (`max-w-prose`), modals, and the Pages live preview, which is a phone-sized frame on purpose. Browse is the one deliberate exception: it reclaims the layout padding to give its viewer more room.

### Docs links

Every link to documentation is `<DocsLink>` (`components/DocsLink.tsx`), placed beside what it explains (under the page description, or at the end of the sentence) and named for its topic ("How ArNS works"), never "Learn more". No bottom-of-page resource blocks or card grids. The console had five styles for this before 4.11.2 and three of its docs URLs were dead, one of them a soft 404 (`docs.ar.io` returns 200 with a "404: This page could not be found" title), so check a new URL's `<title>`, not its status code. Rules and exceptions: `docs/STYLE_GUIDE.md` § Docs links.

### Key Files

- `src/styles/globals.css` - CSS custom properties
Expand Down
18 changes: 18 additions & 0 deletions docs/STYLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,24 @@ Back, "Pay with card instead", "Register another name": a plain text link
(`text-sm text-primary hover:underline`, or `text-foreground/80
hover:text-foreground` for a quieter one), not a button shape.

### Docs links
A link to documentation is always `<DocsLink>` (`src/components/DocsLink.tsx`):
primary, medium weight, underline on hover, a small external-link icon, and a
new tab. Don't hand-write one.

- **Beside what it explains.** Under a page's description, or at the end of
the sentence it explains. No "Learn more" or "Resources" block at the bottom
of a page, and no card grid of docs links.
- **Name the topic.** "How ArNS works", "What are credits?", not "Learn more".
- **One per topic.** Two links to the same page is one link.
- **Never a button.** A docs link is a tertiary action, so it sits beside the
button it supports ("Find a name" · How ArNS works), not as a second button.
- Standalone, pass `className="text-xs"`; inside a sentence it takes the
sentence's size.

Exceptions: the Gateway page's Developer Resources panel (there the links are
the content), the landing page's marketing sections, and site navigation.

### Small Action Button (section and list headers)
The buttons beside a section or list title ("Export CSV", "Check Status", "Edit", "Manage", "Add record"), and the small primary action that sits with them ("Create page"). Always use `actionButtonClass` from `src/components/actionButton.ts`; don't hand-write these classes.

Expand Down
38 changes: 38 additions & 0 deletions src/components/DocsLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { ReactNode } from 'react';
import { ExternalLink } from 'lucide-react';

/**
* The one way to link to documentation (see "Docs links" in
* docs/STYLE_GUIDE.md).
*
* It sits beside what it explains, under a page's description or at the end
* of the relevant sentence, never in a "Learn more" block at the bottom of a
* page. Name the topic ("How ArNS works", "What are credits?") rather than
* "Learn more". Standalone, pass `text-xs`; inside a sentence it takes the
* sentence's size.
*
* Primary purple reaches only ~1.9:1 on the dark washes, so this is for light
* surfaces; a docs link on a dark one needs the `on-dark` accent instead.
*/
export default function DocsLink({
href,
children,
className = '',
}: {
href: string;
children: ReactNode;
className?: string;
}) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className={`inline-flex items-center gap-1 whitespace-nowrap font-medium text-primary hover:underline ${className}`}
>
{children}
<ExternalLink className="h-3 w-3 flex-shrink-0" aria-hidden="true" />
<span className="sr-only"> (opens in a new tab)</span>
</a>
);
}
12 changes: 5 additions & 7 deletions src/components/panels/DeploySitePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { actionButtonClass } from '@/components/actionButton';
import AssignedDomainLinks from '@/components/AssignedDomainLinks';
import { assignedLabel, useArnsHost } from '@/hooks/useArnsHost';
import { buttonClass } from '@/components/button';
import DocsLink from '@/components/DocsLink';

// Helper function moved outside component to prevent recreation on every render
function getFileIcon(filename: string) {
Expand Down Expand Up @@ -2512,19 +2513,16 @@ export default function DeploySitePanel() {
</li>
</ul>

<div className="flex flex-col sm:flex-row gap-3">
<div className="flex flex-col sm:flex-row sm:items-center gap-3">
<button
onClick={() => navigate('/arns')}
className={`${buttonClass('secondary', 'lg')} flex-1`}
className={buttonClass('secondary', 'lg')}
>
Find a name
</button>
<button
onClick={() => window.open('https://docs.ar.io/learn/arns', '_blank', 'noopener,noreferrer')}
className={`${buttonClass('secondary', 'lg')} flex-1`}
>
<DocsLink href="https://docs.ar.io/learn/arns" className="text-sm self-center">
How ArNS works
</button>
</DocsLink>
</div>
</div>
</div>
Expand Down
120 changes: 0 additions & 120 deletions src/components/panels/InfoPanel.tsx

This file was deleted.

Loading
Loading