-
-
Notifications
You must be signed in to change notification settings - Fork 143
スライドのセリフ編集機能を追加 #337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
スライドのセリフ編集機能を追加 #337
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
ウォークスルーこのPRは、スライド編集機能に関連する複数の変更を含みます。日本語ローカライズに新規エントリを追加し、設定コンポーネントには選択中のスライドの編集ページへ遷移するリンクボタンが実装されました。また、SlideControlsに表示制御用のオプションが導入され、APIエンドポイントでは入力サニタイズやバリデーション、エラーハンドリングの改善が行われました。さらに、新規スライドエディタページが追加され、データの取得、編集、保存、リバートが可能になっています。 変更点
シーケンス図sequenceDiagram
participant U as ユーザー
participant SE as スライドエディタページ
participant GS as GET /api/getSupplement
participant US as POST /api/updateSlideData
U->>SE: ページ読み込み(スライド名取得)
SE->>GS: 補足情報リクエスト送信
GS-->>SE: データレスポンス受信
U->>SE: スライド内容を編集
U->>SE: 保存操作を実施
SE->>US: 更新データ送信
US-->>SE: 保存完了レスポンス受信
sequenceDiagram
participant U as ユーザー
participant SC as Slideコンポーネント
participant E as エディタページ
U->>SC: スライド選択・編集リンクをクリック
SC->>E: 新規タブでエディタページをオープン
関連するPR
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/components/settings/slide.tsx (1)
96-142: セリフ編集機能へのリンクボタンが追加されていますスライド選択プルダウンと編集ボタンを横並びにするレイアウトが実装され、機能的にも優れています。条件付きレンダリングにより、スライドが選択されている場合のみ編集ボタンが表示される仕組みは適切です。
一点注意点として、Next.jsの
LinkコンポーネントでlegacyBehaviorとpassHrefを併用していますが、将来的なNext.jsのバージョンアップで非推奨になる可能性があります。将来的なメンテナンス性を考慮すると、以下のような最新のNext.js Linkの使い方に更新することを検討してください:
- <Link - href={`/slide-editor/${selectedSlideDocs}`} - passHref - legacyBehavior - > - <a - target="_blank" // 新しいタブで開く - rel="noopener noreferrer" - className="inline-flex items-center px-3 py-2 text-sm bg-primary hover:bg-primary-hover rounded-3xl text-white font-bold transition-colors duration-200 whitespace-nowrap" - > - {t('EditSlideScripts')} - {/* 外部リンクアイコンを追加しても良いかも */} - <svg - xmlns="http://www.w3.org/2000/svg" - className="h-4 w-4 ml-1" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - strokeWidth={2} - > - <path - strokeLinecap="round" - strokeLinejoin="round" - d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" - /> - </svg> - </a> + <Link + href={`/slide-editor/${selectedSlideDocs}`} + target="_blank" + rel="noopener noreferrer" + className="inline-flex items-center px-3 py-2 text-sm bg-primary hover:bg-primary-hover rounded-3xl text-white font-bold transition-colors duration-200 whitespace-nowrap" + > + {t('EditSlideScripts')} + <svg + xmlns="http://www.w3.org/2000/svg" + className="h-4 w-4 ml-1" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" + strokeWidth={2} + > + <path + strokeLinecap="round" + strokeLinejoin="round" + d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" + /> + </svg> - </Link> + </Link>src/pages/slide-editor/[slideName].tsx (1)
321-558: 変更の元に戻す処理やキーボード操作に対応したUI設計がユーザーフレンドリーです。
もう一度編集前の状態に戻す・Ctrl+S・左右矢印キー対応が直感的で使いやすいです。- バックエンドと連携した保存結果も含め、UI全体の完成度が高いです。
もし将来的にスライド数が多い場合、ページ一覧をモーダルで表示してジャンプできる機能があると利便性がさらに向上しそうです。必要であれば実装を検討してみてください。
🧰 Tools
🪛 Biome (1.9.4)
[error] 348-349: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
locales/ja/translation.json(1 hunks)src/components/settings/slide.tsx(2 hunks)src/components/slideControls.tsx(2 hunks)src/pages/api/getSupplement.ts(1 hunks)src/pages/api/updateSlideData.ts(1 hunks)src/pages/slide-editor/[slideName].tsx(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/components/settings/slide.tsx (1)
src/components/link.tsx (1)
Link(1-12)
src/pages/api/updateSlideData.ts (1)
src/pages/api/getSupplement.ts (1)
handler(11-64)
src/pages/api/getSupplement.ts (1)
src/pages/api/updateSlideData.ts (1)
handler(22-107)
src/components/slideControls.tsx (1)
src/components/iconButton.tsx (1)
IconButton(14-51)
🪛 Biome (1.9.4)
src/pages/slide-editor/[slideName].tsx
[error] 224-224: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 348-349: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (27)
locales/ja/translation.json (1)
158-158: 新しい翻訳キーが適切に追加されていますスライドのセリフ編集機能に対応する翻訳キー「EditSlideScripts」が適切に追加されています。この追加により、新機能のUIが日本語環境で正しく表示されるようになります。
src/components/settings/slide.tsx (1)
4-4: Next.jsのLinkコンポーネントが適切にインポートされています
next/linkからのインポートが適切に行われています。コメントも明確に記述されており、コードの理解を助けています。src/components/slideControls.tsx (3)
11-11: プロパティの追加が適切に行われています
showPlayButtonというオプショナルプロパティが適切に追加されています。コメントも明確で、この変更の目的がわかりやすく記述されています。
21-21: デフォルト値の設定が適切です
showPlayButtonのデフォルト値がtrueに設定されており、既存のユースケースとの互換性が維持されています。コメントも適切です。
24-51: レイアウトとボタンの条件付き表示が改善されていますスライドコントロールのレイアウトが改善され、Tailwind CSSを使用して適切にスタイリングされています。
mx-16を削除し、親要素にgap-8を追加することで、より柔軟なレイアウトになっています。また、
showPlayButtonプロパティに基づく条件付きレンダリングと、ボタンの無効化ロジックが適切に実装されています。各ボタンのdisabled属性の条件分岐が明確に記述されており、可読性が高いです。src/pages/api/updateSlideData.ts (5)
1-21: APIエンドポイントの型定義が適切ですスライドデータ更新のためのAPIエンドポイントの型定義が適切に実装されています。
ScriptEntryインターフェース、リクエストボディの型、レスポンスの型が明確に定義されており、型安全性が確保されています。
22-52: バリデーションとサニタイゼーションが適切に実装されていますリクエストメソッドの検証、必須パラメータのチェック、そしてスライド名のサニタイゼーションが適切に実装されています。特にパストラバーサル攻撃を防止するための対策が講じられており、セキュリティ面でも配慮されています。
エラーレスポンスも適切なHTTPステータスコードと明確なメッセージが返されるようになっています。
53-67: ディレクトリとファイルパスの処理が適切ですファイルパスの構築が適切に行われており、ターゲットディレクトリの存在確認も実装されています。存在しないディレクトリに対するエラーハンドリングも適切です。
68-90: 入力データの検証が詳細に実装されています
scripts配列の形式検証とsupplementContentの検証が適切に実装されています。型チェックだけでなく、配列の各要素の構造も確認されており、不正なデータを早期に検出できるようになっています。
91-107: ファイル書き込み処理とエラーハンドリングが適切です
Promise.allを使用して両方のファイルを並行して書き込む実装は効率的です。エラーハンドリングも適切に行われており、エラーメッセージが詳細に記録されるようになっています。成功時と失敗時のレスポンスの形式も一貫しており、クライアント側での処理がしやすい設計になっています。
src/pages/api/getSupplement.ts (10)
1-9: レスポンスデータ型を導入している点が良いですね。
ResponseData型でレスポンスの構造を明示しているため、クライアント側との連携が分かりやすく保守性も高いです。
13-14: ジェネリック型パラメータでのレスポンス型指定が適切です。
NextApiResponse<ResponseData>により、API レスポンス内容が明瞭化され、開発者体験が向上します。
15-17: GET以外のリクエストを早期に 405 返す実装は明確で良いです。
REST 原則にも合致しており、エラー処理が分かりやすくなります。
19-20: クエリパラメータから slideName を取得する処理は問題ありません。
特にエラー処理も混乱なく実装されており、読みやすいです。
21-25: slideName の妥当性チェックが適切です。
空文字や文字列以外を 400 エラーで早期に弾くため、想定外のバグを防げます。
27-39: path の正規化と無効文字・パストラバーサル対策がしっかりしています。
安全なファイルアクセスのために欠かせない実装で、セキュリティ面が大きく向上します。
41-47: OS依存しないパス作成ができており、可読性も高いです。
path.joinの利用で誤ったパス指定のリスクを減らせています。
49-51: ファイルの読み込みに成功した場合に content を返す設計が分かりやすいです。
レスポンス内容もシンプルで、クライアント側で処理しやすいと思われます。
53-56: ENOENT 時に空文字列を返す方針は、利用者にとって便利ですが想定動作を要確認です。
ファイルが存在しないケースでも例外ではなく正常系となるため、フロント側の処理が簡易化されますが、期待どおりかどうか要再確認すると良いでしょう。
57-61: ファイル読み込み以外のエラーはログ出力の上で 500 を返しており、運用時のトラブルシュートもしやすいです。src/pages/slide-editor/[slideName].tsx (7)
1-14: import と goToSlide の定義が分かりやすいです。
goToSlide関数が単独でエクスポートされているため、再利用やテストがしやすくなっています。
15-114: コンポーネントの基本的な状態管理とマークダウン変換ロジックがよく整理されています。
useEffectでスライドデータを非同期取得し、エラー時やローディング時の状態を適切に制御しています。- スタイル要素を DOM に追加・削除するライフサイクル管理も正しく行われており、メモリリークを防げています。
114-123: スライドの表示切り替えが適切です。
currentSlideの変更をフックにして SVG を切り替えるシンプルな実装となっており、分かりやすいです。
124-174: scripts.json を取得する処理が堅牢です。
- 404 時に空スクリプトとして扱うなど、想定外エラーにも柔軟に対応しています。
- スクリプトフォーマットのバリデーションで、型が厳密に保証されている点も安心です。
176-206: supplement.txt の読み込みも同様に分かりやすい設計です。
404 はエラー扱いにせず、空文字列にして取り込む方針が統一されており、フロント処理の簡易化が図れます。
208-226: currentSlide に応じて現在のセリフや追加情報をセットするフローが読みやすいです。
nextSlide/prevSlideもslideCountをもとに安全に境界処理をしており、意図しないインデックスエラーを避けられます。🧰 Tools
🪛 Biome (1.9.4)
[error] 224-224: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
228-319: scripts ステート更新関数や保存処理がしっかり設計されています。
updateScriptsStateによる差分更新で複雑度が低く、拡張が容易です。handleSaveでは POST リクエストをまとめて実行し、エラー時に警告を出す実装が妥当です。- 静的解析の指摘があった行(224, 348 付近)については、
state.currentSlideとinitialScriptsは配列として初期化されるため、オプショナルチェーンは不要と考えられます。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/pages/api/getSlideFolders.ts (1)
9-19: 同期 I/O の多用はレスポンス遅延の原因になります
readdirSyncとexistsSyncをループ内で呼び出すと、CPU バウンドではなく I/O バウンドの待ちが連続し、API がブロッキングされます。非同期 API (fs.promises) を使い、Promise.allで並列判定に切り替えるとスケールしやすくなります。-const folders = fs - .readdirSync(slidesDir, { withFileTypes: true }) +const dirents = await fs.promises.readdir(slidesDir, { withFileTypes: true }) + +const folders = await Promise.all( + dirents .filter((dirent) => dirent.isDirectory()) - .filter((dirent) => { - const folderPath = path.join(slidesDir, dirent.name) - const hasSlidesFile = fs.existsSync(path.join(folderPath, 'slides.md')) - const hasScriptsFile = fs.existsSync(path.join(folderPath, 'scripts.json')) - return hasSlidesFile && hasScriptsFile - }) - .map((dirent) => dirent.name) + .filter(async (dirent) => { + const folderPath = path.join(slidesDir, dirent.name) + const [slides, scripts] = await Promise.all([ + fs.promises + .stat(path.join(folderPath, 'slides.md')) + .then(() => true) + .catch(() => false), + fs.promises + .stat(path.join(folderPath, 'scripts.json')) + .then(() => true) + .catch(() => false), + ]) + return slides && scripts + }) +)src/pages/slide-editor/[slideName].tsx (5)
1-1: 未使用のKeyboardEventインポートを削除してください
globalThis.KeyboardEventを直接使用しており、ここでインポートした型は参照されていません。ビルド時の不要コード削減のためにも除去しましょう。
4-4:homeStoreが未使用です現状このファイル内で
homeStoreは参照されておらず、Linter で警告対象になります。削除か使用の検討をお願いします。
8-13:goToSlideの重複定義とコメントの残骸を整理してください
- 既に別ファイルで定義済みなら再利用して DRY 原則を保ちましょう。
- 「slides.tsxからインポートするか…」というコメントはレビュー用メモに見えるため、マージ前に削除を推奨します。
226-229: optional chaining で可読性&安全性を向上三項演算子よりも
script?.line ?? ''などの記法が簡潔です。静的解析でも指摘されています。-setCurrentScript(script ? script.line : '') -setCurrentNotes(script && script.notes ? script.notes : '') +setCurrentScript(script?.line ?? '') +setCurrentNotes(script?.notes ?? '')
371-383:isDirty判定のパフォーマンスを改善可能
JSON.stringifyとソートは O(n log n) + シリアライズのコストがあり、スクリプト数が多いと再計算が重くなります。変更フラグをhandleScriptChange / handleNotesChange / handleSupplementChange内で都度立てる方式へ切り替えると、不要な比較を避けられます。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
⛔ Files ignored due to path filters (1)
public/images/icons/external-link.svgis excluded by!**/*.svg
📒 Files selected for processing (6)
locales/ja/translation.json(1 hunks)src/components/settings/messageReceiver.tsx(2 hunks)src/components/settings/slide.tsx(2 hunks)src/pages/api/getSlideFolders.ts(1 hunks)src/pages/send-message.tsx(1 hunks)src/pages/slide-editor/[slideName].tsx(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/pages/send-message.tsx
- locales/ja/translation.json
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/settings/slide.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/settings/messageReceiver.tsx (1)
src/components/link.tsx (1)
Link(1-12)
🪛 Biome (1.9.4)
src/pages/slide-editor/[slideName].tsx
[error] 240-241: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 367-369: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (4)
src/components/settings/messageReceiver.tsx (3)
3-3: 適切なNext.jsコンポーネントのインポートが追加されています。
ImageとLinkコンポーネントの追加は、Webアプリケーションのパフォーマンスと開発体験の向上に貢献します。Next.jsの組み込みコンポーネントを使用することで、画像の最適化やルーティングの取り扱いが改善されます。Also applies to: 7-7
50-65: リンク実装の改善が適切に行われています。従来のシンプルなアンカータグから、Next.jsの
Linkコンポーネントへの変更は以下の点で優れています:
legacyBehaviorとpassHrefを正しく使用し、子要素のアンカータグにhref属性を渡しています- 新しいタブでの開き方が実装され、適切なセキュリティ属性(
rel="noopener noreferrer")が設定されています- Tailwind CSSを活用した視覚的に魅力的なスタイリングが適用されています
- 外部リンクであることを示すアイコンが追加され、ユーザーエクスペリエンスが向上しています
スタイリングのクラス名も適切で、他のUIコンポーネントとの一貫性を保っています。
57-63: 適切な画像コンポーネントの実装です。Next.jsの
Imageコンポーネントの使用は以下の点で適切です:
- 必要な
widthとheight属性が指定されています- 適切な代替テキストが翻訳関数を通して提供されています
- アイコンと周囲の要素との間隔が適切に設定されています
画像の最適化により、ページのパフォーマンスが向上し、ユーザーエクスペリエンスが改善されます。
src/pages/api/getSlideFolders.ts (1)
12-19: 👍 必要ファイルの存在チェックが追加されました
slides.mdとscripts.jsonの双方を確認してからリストに載せるロジックは要件を満たしており、意図したフォルダのみを UI に露出させられます。
スライドのセリフ編集機能を追加
@tegnike
プロダクトのコンセプトに沿っていそうでしたら取り込みご検討いただけますでしょうか...?
関連するイシュー
やったこと
できるようになること(ユーザ目線)
メニューのスライド設定内にセリフ編集ボタンが追加

ボタンを押すと選択中のスライドのセリフ編集画面が別タブで表示
動作確認
Summary by CodeRabbit
新機能
改善