[WIP - Do not merge] feat(ipfs2filecoin): add IPFS to Filecoin campaign landing page - #346
Draft
SgtPooki wants to merge 13 commits into
Draft
[WIP - Do not merge] feat(ipfs2filecoin): add IPFS to Filecoin campaign landing page#346SgtPooki wants to merge 13 commits into
SgtPooki wants to merge 13 commits into
Conversation
Adds filecoin.cloud/ipfs2filecoin, the front door for the IPFS-to-Filecoin mini-campaign, ported from Jenni's wireframe in FilOzone/FOC-PM onto the site's existing ui-filecoin components. The page is both the campaign's front door and its measuring instrument. It does three things: takes a pasted CID list, produces a deposit estimate from a declared volume, and routes to the agent door or to contact. Interactive parts run entirely client-side, with no wallet and no network calls, so a check costs the visitor nothing and sends us nothing: - CID list checker: validates, dedupes, and steers lists over the 500-item browser cap to the agent prompt. - Deposit estimator: reproduces the PRD's worked example exactly ($128.08 deposit, $5.25 refundable for 1 TiB over two years) from documented constants rather than hardcoded figures. - Agent prompt with copy-to-clipboard, the primary conversion. Plausible events cover the funnel the PRD asks for: CID List Checked, Estimate Viewed, and Agent Prompt Copied, the last being the headline number. Also serves a draft migration brief at /ipfs2filecoin/llms.txt and advertises it via <link rel="alternate" type="text/markdown">, so an agent pointed at the human URL discovers the brief without being told the convention. The brief opens with a stage 0 ingress check, per the 2026-07-28 validation run that found runs die there after the expensive commP pass. The page is unlinked from site navigation, reachable by URL and sitemap only, so campaign attribution stays clean.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new campaign landing page at /ipfs2filecoin to act as the entry point for the IPFS→Filecoin mini-campaign, including client-side CID list checking, deposit estimation, an agent prompt CTA, and a served llms.txt migration brief.
Changes:
- Introduces the
/ipfs2filecoinpage composed from existingui-filecoincomponents, with SEO metadata + JSON-LD structured data. - Adds client-side utilities/components for CID list parsing, pricing comparison, and deposit estimation (with Plausible funnel events).
- Serves
/ipfs2filecoin/llms.txtastext/markdownand links it via metadata alternates for agent discovery.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/constants/paths.ts | Adds a PATHS.IPFS_TO_FILECOIN entry for the new route. |
| src/app/ipfs2filecoin/page.tsx | Implements the campaign landing page layout, content sections, and metadata alternates. |
| src/app/ipfs2filecoin/constants/seo.ts | Defines page SEO title/description. |
| src/app/ipfs2filecoin/utils/generate-structured-data.ts | Generates JSON-LD structured data for the campaign page. |
| src/app/ipfs2filecoin/constants/migration.ts | Centralizes campaign constants (caps, pricing inputs, llms.txt paths, Plausible event names). |
| src/app/ipfs2filecoin/utils/estimate-cost.ts | Implements pricing/deposit math and formatting helpers. |
| src/app/ipfs2filecoin/data/pricing-comparison.ts | Defines the comparison-table rows, including derived Filecoin $/TB/mo. |
| src/app/ipfs2filecoin/components/ComparisonTable.tsx | Renders the pricing comparison table UI. |
| src/app/ipfs2filecoin/components/CostEstimator.tsx | Client-side deposit estimator UI + Plausible event. |
| src/app/ipfs2filecoin/utils/parse-cid-list.ts | Parses/normalizes CID lists (strip gateway prefixes, validate, dedupe). |
| src/app/ipfs2filecoin/components/CidListChecker.tsx | Client-side CID list checker UI + cap routing + Plausible event. |
| src/app/ipfs2filecoin/components/AgentPrompt.tsx | Copy-to-clipboard agent prompt component + Plausible event. |
| src/app/ipfs2filecoin/data/reasons.ts | Defines “why migrate” card content. |
| src/app/ipfs2filecoin/data/steps.ts | Defines the “how it works” step cards. |
| src/app/ipfs2filecoin/data/limits.ts | Defines “what this does not do” limit statements. |
| src/app/ipfs2filecoin/data/faqs.tsx | Adds FAQ content for the landing page. |
| src/app/ipfs2filecoin/llms.txt/route.ts | Serves the llms.txt draft migration brief as markdown with caching headers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+25
to
+40
| export function parseCidList(input: string): CidListSummary { | ||
| const lines = input | ||
| .split('\n') | ||
| .map(normalizeLine) | ||
| .filter((line) => line && !line.startsWith('#')) | ||
|
|
||
| const valid = lines.filter((line) => CID_PATTERN.test(line)) | ||
| const uniqueCids = [...new Set(valid)] | ||
|
|
||
| return { | ||
| totalLines: lines.length, | ||
| uniqueCids, | ||
| duplicateCount: valid.length - uniqueCids.length, | ||
| invalidCount: lines.length - valid.length, | ||
| } | ||
| } |
|
|
||
| ## Prerequisites | ||
|
|
||
| - Node.js 26 or newer. This is a hard requirement. |
A real agent run against the draft brief failed at the first hop: the brief never named the tool, so the agent correctly refused to improvise a pipeline and stopped. It also read the 500 GiB figure as a self-serve cap and routed a 56k-CID job to the contact form, which killed the conversion outright. Both are fixed, and the format question behind them is settled. llms.txt was the wrong format. Per llmstxt.org it is a documentation index -- H1, blockquote, then H2 lists of links -- so a procedure does not belong in it. The procedure now lives at /ipfs2filecoin/migrate.md, named for what it is, and llms.txt is used correctly in two places: a spec-conformant site index at /llms.txt, and a campaign index at /ipfs2filecoin/llms.txt whose first link is the runbook. Discovery never depended on the filename anyway -- the prompt carries the URL, and the page carries rel="alternate". The runbook names ipfs2foc, pins the version its flags were verified against, and carries the real command sequence read out of that repo. Notable content: - One invocation form, stated once. A bare `ipfs2foc` after only an `npx` check was the most likely first failure. - Prerequisites split into "needed now" and "needed before stage 4", so a missing key no longer blocks the free stages. - Stage 0 settles ingress before the commitment pass, and records that the relay only serves the single-asset path. - Stage 2 reports from analyze --json using fields that actually exist, with explicit cost and ETA formulas so nothing is invented. - Stage 4 is executed by the user in their own terminal. The agent is told never to accept a private key -- a key pasted into a chat is a key in a transcript. - Stage 5 spawns the pull source as a background process and extracts the tunnel URL from its log, rather than saying "terminal A". - Duration is framed as expected, not as a limit: a long-running command is working, not hung, and there is no cap on CID count. Page copy follows: SELF_SERVE_VOLUME_CAP_LABEL becomes COORDINATION_VOLUME_LABEL and reads as coordination rather than a ceiling, so an agent reading the page cannot reproduce the original false blocker. Reviewed by Codex and Gemini via the peer-review skill; every finding above came out of that pass. Cursor could not run -- it needs auth.
Audited every command and flag in the runbook against the USAGE string in ipfs2foc's packages/cli/src/index.ts, which is authoritative. Two were wrong. `ipfs2foc --version` is not a subcommand. It falls through to the default branch, writes "unknown command: --version" to stderr, and sets exit code 1. As the very first step of the runbook that reads like a broken install, which is exactly the first-hop failure this rewrite exists to remove. The install check is now `--help`, with a note saying why. The provider's minimum piece size is advisory, not enforced. `pdp-submit` warns and proceeds by default and only refuses under `--strict-piece-size` (see submit-pdp.ts: "The advertised floor is advisory in practice"). The runbook claimed items below the minimum fail at pull time, which would have pushed agents onto the multi-asset path unnecessarily -- it needs staging disk and rules out the relay. Now stated as the trade it is: the minimum is a packing efficiency question, the pull limit is the hard one.
SgtPooki
force-pushed
the
feat/ipfs2filecoin-landing-page
branch
from
July 31, 2026 16:11
fc86253 to
cc32d8e
Compare
4 tasks
Checked all four rows against filebase.com/pricing and pinata.cloud/pricing. Every rate still matches: Filebase Pro storage $0.015/GB and IPFS egress $0.015/GB; Pinata Fiesta $0.035/GB and $0.080/GB; Pinata Picnic $0.070/GB and $0.100/GB. No figures changed. The verification date lives in the source comment rather than on the page: it is a maintenance note for us, it ages badly in public, and the two pricing links already let a reader check the current numbers.
SgtPooki
force-pushed
the
feat/ipfs2filecoin-landing-page
branch
from
August 3, 2026 16:03
8759d34 to
abbe4ca
Compare
* fix(faq): make accordion dividers and chevrons background-aware Faq hardcoded divide-white/20, and Accordion hardcoded text-zinc-200 on the chevron and text-zinc-300 on the body. All three assume a dark background, which held while the homepage was the only consumer since it mounts the FAQ on a dark section. On a light or gray section the dividers and chevrons are effectively invisible. They now use --color-border-base, --color-text-base and --color-paragraph-text, which flip off the .light-section / .dark-section class that Section already sets, so no isDark branching is needed. Faq keeps useBackground purely for prose-invert. Moving the colour onto the item rather than the parent also fixes the first divider. divide-* targets every child after the first, so item one's border was falling back to currentColor and rendering at full brightness on dark. The homepage FAQ shifts slightly as a result: chevron zinc-200 to zinc-50, body zinc-300 to zinc-400, both now matching the tokens used everywhere else. That page is worth a look alongside this one. Review: @filipagr Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ipfs2filecoin): correct layout and type hierarchy from design review Follow-ups from a walkthrough of the page with Filipa Ribeiro. Alignment and spacing - "Estimate your deposit" and the hero sat 60px inset from their siblings, because PageSection already wraps children in a Container and page.tsx nested a second one, doubling the horizontal padding. Removed both, plus the now-unused import. - The Unit and Funded-for selects had the native arrow jammed against the border with a cavern between it and the value. A local SelectField goes appearance-none with a Phosphor caret inset to match the field's text, and the grid drops from three equal columns to 2fr/1fr/2fr so Unit is no longer a full-width field holding three characters. - "What this does not do" is constrained to max-w-5xl; lines ran past 15 words at desktop. Type - Both tables move off text-sm to text-base, with service names at text-lg. - Monospace figures dropped for the body font with tabular-nums. The reported problem was numbers appearing larger than the names beside them, which was a typeface illusion rather than a size difference, so matching the typeface removes it at the root while tabular-nums keeps the columns aligned. Flagging this one as the most debatable call in the batch. - The highlighted Filecoin row carries weight instead of a marginally darker grey, which read as a mistake rather than emphasis. Visual interest - How it works renders 2x2 rather than 3-up with an orphaned fourth, and step numbers sit above each title in the accent colour. This needs a new StepList component because the shared Card types title as a plain string, so the number could only ever be inlined as "01. Hand over the list". - Reason cards take icons, following how agents/ and warm-storage-service/ already pass Phosphor icons to Card. - The agent column takes two thirds and "Talk to us" becomes a one third call-out, giving the path with more to say more room. The external-link arrow beside Filebase and Pinata is tightened with a local override. It is sized for button text inside ExternalTextLink in ui-filecoin, so the real fix belongs upstream; this is a commented stopgap. Still open from the review and deliberately not attempted here: table whitespace now that the type sizes are settled, the hero background treatment, and the optional illustration beside the agent heading. Review: @filipagr Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(ipfs2filecoin): turn a checked CID list into something actionable parseCidList already validated, deduped and stripped gateway prefixes, but the verdict box reported only a count. The successful path gave you nothing to act on, so the top of the page had no purpose: you still assembled cids.txt by hand. The prompt was in fact offered only on the over-cap branch, so the one outcome that succeeded was the one outcome with no output. A checked list now produces the agent prompt with your own CIDs inlined, via buildAgentPrompt, plus a cids.txt download of the cleaned and deduped list. AGENT_PROMPT stays as the fallback for the empty and over-cap cases, where pointing at a file is the right shape rather than inlining hundreds of lines. The instruction to "estimate what they cost to store below" is replaced. A check reads the CIDs and not the bytes behind them, so it cannot price anything on its own, and implying otherwise was the most confusing part of the flow. Resolving a CID to its actual size needs backend capability and is a separate conversation. Hero polish in the same component: "one per line" sits beside the label in the accent colour rather than surfacing only after a failed check, the button is centred, the empty textarea is shorter, and the free-check facts read as a scannable list instead of fine print. Copy prompt demotes from a full-width button to an icon in the code block's corner. Verified against deliberately messy input: a bare CID, a gateway URL, a duplicate and a junk line resolve to three unique CIDs, with the URL prefix stripped and both the skipped line and the duplicate reported. Review: @filipagr Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: ignore local agent and working files CLAUDE.md is per-machine guidance for Claude Code, and todo.md is the working list of design review actions for /ipfs2filecoin. Neither belongs in the repo. Note that this keeps todo.md local, so it does not travel to reviewers via git. Review: @filipagr Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(ipfs2filecoin): rework the CID checker into one input surface Fold the label, textarea and action into a single bordered panel with a live "X of Y lines are CIDs" readout and a Cmd/Ctrl+Enter shortcut. Move the verdict into its own CidListVerdict component with an icon per outcome, and extract pluralize so the readout and verdict agree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ipfs2filecoin): split provider from tier and make the price table responsive Give each pricing row a detail sub-line so the provider is what you compare on and the plan tier stays secondary, and key rows by provider plus tier now that two Pinata tiers share a name. On mobile the three columns do not fit, so each provider becomes a stacked card; the full table returns at md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ipfs2filecoin): pair the deposit estimator with the table, refine hero and type Move the estimator into a companion card beside the comparison table (the table is the market rate, the card prices it for your data), with the two inputs side by side and a compact stacked result that fits the narrow column. Add a faint brand glow along the bottom of the hero, step the reason-card and agent-warning copy down a size, and render How it works four across on desktop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ipfs2filecoin): derive the $2.50 rate from USD_PER_TIB_MONTH_PER_COPY The rate footnote, one reason card, and the SEO description each restated $2.50 as a literal, so they could silently drift from the comparison table and estimator, which already derive from the constant. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: filipagr <filipagoncalvesribeiro@gmail.com> Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
filecoin.cloud/ipfs2filecoin, the front door for the IPFS-to-Filecoin mini-campaign.Ported from Jenni's wireframe onto the site's existing
ui-filecoincomponents, and reconciled against the PRD including its 2026-07-28 validation-run corrections.What's here
The page is the campaign's front door and its measuring instrument: it takes a pasted CID list, produces a deposit estimate from a declared volume, and routes to the agent door or to contact.
Everything interactive runs client-side with no wallet and no network calls, so a check costs the visitor nothing and sends us nothing.
/ipfs2filecoin/llms.txttext/markdown.Instrumentation
Three Plausible events, matching the funnel the PRD asks for:
IPFS2Filecoin CID List Checked— with outcome and CID countIPFS2Filecoin Estimate Viewed— with volume, duration, depositIPFS2Filecoin Agent Prompt Copied— with source; the PRD calls this the headline numberPricing math
The estimator reproduces the PRD's worked example exactly — 1 TiB over two years:
The comparison table's $4.55/TB/month is also derived, from storage-only at 2 copies. Both fall out of constants in
constants/migration.ts, so a price change is a one-line edit that propagates to the table, the estimator, andllms.txttogether.Agent-readability
<link rel="alternate" type="text/markdown" href="…/llms.txt">is in the page head, so an agent pointed at the human URL finds the brief without being told the convention.The brief opens with a stage 0 ingress check — the validation run found runs die on missing public ingress after the expensive commP pass, so it gates before that, and tells the agent to stop and ask rather than install a tunnel binary on the user's behalf.
Copy rules
Followed the PRD's hard rules: sentence case, no emoji, second person, no
FOC/commP/PoDSI/aggregatein public copy, no implication that FilOz custodies anyone's data, no "cheapest" superlative, and no promise of an alert we have no channel to send.Decisions taken
llms.txtserved as a marked draft rather than 404ing, so the prompt resolves and fetch telemetry starts now.Needs a look before merge
llms.txtbody is a placeholder. It must be reconciled with the CLI's actual flags before launch — the PRD calls this launch-blocking.sourcefield for separating migration leads is not done — it needs a Google Form entry id I don't have.next.config.tsrewrites. Out of scope here; this PR is the landing page only, so there's no browser "check and fund" door yet.Verification
npm run lintandnpm run buildclean. Page andllms.txtroute verified against a production server locally.