Skip to content

feat: URL から PDF を開く (#11)#20

Merged
miyaji255 merged 4 commits into
mainfrom
feat/open-pdf-from-url
May 3, 2026
Merged

feat: URL から PDF を開く (#11)#20
miyaji255 merged 4 commits into
mainfrom
feat/open-pdf-from-url

Conversation

@miyaji255
Copy link
Copy Markdown
Collaborator

Closes #11

Summary

  • ?pdf=URL (+任意の ?pdfpc=URL) クエリパラメータでの自動取得
  • ホーム画面に「URL から開く」折りたたみフォーム (PDF URL 必須 + pdfpc URL 任意)
  • 「デモを試す」ボタンでリポジトリの demo/pdfpw-demo[.ja].pdf + pdfpw-demo.pdfpc を raw GitHub から取得
  • CORS / HTTP / 非 PDF / 不正 URL を FetchPdfError.kind で分類、ja/en の丁寧な案内
  • proxy サービスは導入せず、CORS 失敗時は CORS 対応ホスト (GitHub raw / jsDelivr) を案内

設計メモ

  • src/lib/fetch-pdf.ts で取得・エラー分類を一元化、fetchImpl 注入で純粋テスト可能に
  • %PDF- マジックバイトで PDF を検証 (Content-Type に依存しない)
  • 未指定時のみ sibling .pdfpc を best-effort 取得 (失敗は無音)
  • pdfpcUrl 明示指定時は失敗をハードエラーで返す
  • URL 由来の PDF は FSA ハンドルなし → 既存の Standard モードのスナップショット保存にそのまま乗る (saveHistory=off なら保存しない)

Test plan

  • pnpm tsc -b clean
  • pnpm test 全 pass (新規 fetch-pdf 11 ケース × 2 browser = 22 件追加)
  • pnpm exec biome check 該当ファイル warnings 0
  • pnpm build 成功
  • 手動確認: 「デモを試す」→ presenter (72 ページ + ノート) 表示
  • 手動確認: ?pdf=...&pdfpc=... で自動取得 → presenter 遷移
  • 手動確認: CORS 非対応 URL で「このサーバーは CORS を許可していません…」表示

🤖 Generated with Claude Code

miyaji255 and others added 4 commits April 28, 2026 12:32
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- FetchPdfError で invalid-url / cors-or-network / http-error / not-pdf / aborted を分類
- %PDF- マジックバイトでバリデーションし HTML を返すサーバを早期に弾く
- pdfpcUrl オプションで明示指定、未指定時は sibling .pdfpc を best-effort 取得
- vitest browser mode で 11 ケースのテスト

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ?pdf=URL & ?pdfpc=URL クエリパラメータでの自動取得 (一度きり ref-guard)
- HeroSection に「URL から開く」折りたたみフォーム (PDF URL + 任意の pdfpc URL)
- 「デモを試す」ボタンで raw GitHub の demo を取得 (ja/en でロケール別 PDF)
- FetchPdfError の kind に応じた丁寧なエラーメッセージ表示

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a0b08287e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +370 to +375
useEffect(() => {
if (!pdfUrlParam) return;
const key = `${pdfUrlParam}${pdfpcUrlParam ?? ""}`;
if (autoOpenedUrlRef.current === key) return;
autoOpenedUrlRef.current = key;
void onUrlSubmit(pdfUrlParam, pdfpcUrlParam);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prevent auto-open from re-triggering on browser back

The dedupe guard is scoped to component lifetime, so it resets after navigation. Starting from /$locale/?pdf=..., the effect auto-opens once, but pressing Back remounts home with the same query and runs onUrlSubmit again, creating a back-button loop that keeps re-fetching and bouncing users to presenter. This should be gated per history entry (or the pdf/pdfpc params should be cleared/replaced after the first auto-open) so returning to home is possible.

Useful? React with 👍 / 👎.

Comment thread src/lib/fetch-pdf.ts
);
}

const buffer = await response.arrayBuffer();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map body-read failures into FetchPdfError kinds

Only the initial fetch() call is wrapped in error classification, but response.arrayBuffer() can also reject (for example, if the request is aborted during download or the stream errors mid-transfer). In that case a raw exception escapes, so callers that rely on FetchPdfError.kind (like onUrlSubmit) misclassify it as a generic failure instead of aborted or cors-or-network. Wrap body reading in the same mapping logic to keep error handling consistent.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a third “input source” for presentations—opening PDFs directly from remote URLs—via both query parameters and a home-screen UI, with user-friendly error classification and i18n messages.

Changes:

  • Introduce fetchPdfFromUrl() utility with typed error kinds and optional sibling/explicit .pdfpc fetching.
  • Wire ?pdf=... (+ optional ?pdfpc=...) auto-open behavior into the home route and add a collapsible “Open from URL” form + “Try the demo” action.
  • Add Vitest coverage for URL fetching/error classification and add en/ja message keys for the new UI + error states.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/routes/$locale/(main)/index.tsx Adds validateSearch for pdf/pdfpc, auto-fetch effect, and URL-submit handler wired into HeroSection.
src/routes/$locale/(main)/-index/HeroSection.tsx Adds “Open from URL” toggle form and “Try the demo” button; passes URL(s) upstream via onUrlSubmit.
src/lib/fetch-pdf.ts New URL fetch helper that validates URLs, fetches PDF (+ optional .pdfpc), and classifies failures with FetchPdfError.
src/lib/fetch-pdf.test.ts New browser-mode tests covering success paths and each error kind.
messages/ja.json Adds labels/hints/status/errors for URL open flow (Japanese).
messages/en.json Adds labels/hints/status/errors for URL open flow (English).
docs/superpowers/plans/2026-04-28-open-pdf-from-url.md Adds an implementation plan document for the feature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 64 to +71
function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
const files = event.target.files ? Array.from(event.target.files) : [];
if (files.length > 0) void onFilesSelected(files);
event.target.value = "";
}

function handleUrlSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component references React.ChangeEvent / React.FormEvent, but there’s no import type * as React from "react" (or equivalent type imports). Align with other components (e.g. ui/button.tsx) by importing React types or switching the annotations to ChangeEvent/FormEvent imported from react, otherwise type-checking can fail depending on TS settings.

Copilot uses AI. Check for mistakes.
// biome-ignore lint/correctness/useExhaustiveDependencies: onUrlSubmit recreated each render; ref-guard dedupes
useEffect(() => {
if (!pdfUrlParam) return;
const key = `${pdfUrlParam}${pdfpcUrlParam ?? ""}`;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key is built using a literal NUL character between pdfUrlParam and pdfpcUrlParam (non-printable). This is easy to miss and can cause tooling/editor issues; use an explicit escape ("\u0000") or a visible separator instead.

Suggested change
const key = `${pdfUrlParam}
const key = `${pdfUrlParam}\u0000${pdfpcUrlParam ?? ""}`;

Copilot uses AI. Check for mistakes.
@miyaji255 miyaji255 merged commit 2de95fa into main May 3, 2026
6 checks passed
@miyaji255 miyaji255 deleted the feat/open-pdf-from-url branch May 3, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: URL から PDF を開く (URLパラメータ + UI、CORS 対応)

2 participants