Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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