feat: ✨ fix tag cloud overflow on mobile#62
Conversation
📝 WalkthroughWalkthroughタグクラウドがモバイル表示時にビューポート外へはみ出す問題を、CSS レスポンシブ高さ、JavaScript 描画ロジック再構築、座標クランプ、リサイズ観測によって解決。複数言語環境での E2E テストで境界内配置を検証。同時に Hugo 開発サーバーを LAN 内デバイスからアクセス可能に構成。 Changesタグクラウド モバイル対応&開発環境LAN対応
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@assets/js/tag-cloud.ts`:
- Around line 211-221: The JSON.parse calls in initTagCloud (parsing `raw` into
`parsed` and `rawPinned` into `pinnedTags`) can throw and currently abort
initialization; wrap each parse in a try/catch, validate the result
(Array.isArray for `parsed` and array/string items for `pinnedTags`), and on
error log the exception (e.g., console.error or a logger) and fall back safely
(return early if main `parsed` is invalid or set `pinnedTags = []` when pinned
parsing fails) so the tag cloud can continue rendering without crashing.
In `@README.md`:
- Line 73: The "start" task description and example connection URL are
inconsistent: update the README "start" (aliases: dev) entry so the example
access URL uses <LOCAL_IP> instead of 0.0.0.0 and ensure the explanatory text
clarifies LAN/mobile access; locate the line containing "* start:
開始 - Hugo開発サーバー起動(LAN内スマホからもアクセス可) (aliases: dev)" and replace the example
URL and any adjacent sentence that references 0.0.0.0 with a <LOCAL_IP>-based
instruction and brief note on how to find the local IP for mobile testing.
In `@tests/posts.en.spec.ts`:
- Around line 55-63: The current overflow calculation in the test (using
cloud.getBoundingClientRect(), internalScroll, and externalOverflow) only
measures right-side overflow (rect.right > viewport) and misses left-side
overflow (rect.left < 0); update the externalOverflow computation to account for
both sides by taking the max of 0 and rect.right -
document.documentElement.clientWidth as well as max of 0 and -rect.left (or
combine them), recompute overflow as internalScroll + both external overflows,
and keep the existing expect(overflow).toBe(0) assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bfe9d555-966a-44c9-80c5-8e520e91626e
📒 Files selected for processing (11)
.claude/settings.local.json.vscode/settings.jsonREADME.mdTaskfile.ymlassets/css/custom.cssassets/js/tag-cloud.tslayouts/partials/tag-cloud.htmltests/posts.en.spec.tstests/posts.ja.spec.tstests/tags.en.spec.tstests/tags.ja.spec.ts
💤 Files with no reviewable changes (1)
- layouts/partials/tag-cloud.html
| const parsed: unknown = JSON.parse(raw) | ||
| if (!Array.isArray(parsed) || parsed.length === 0) return | ||
| const data = parsed as TagData[] | ||
|
|
||
| const activeTag = (container.dataset.activeTag ?? "").toLowerCase() | ||
|
|
||
| // pinnedCenterTags is configured in config/_default/params.toml [tagCloud] | ||
| const rawPinned = container.dataset.pinnedTags | ||
| const pinnedTags: string[] = rawPinned | ||
| ? (JSON.parse(rawPinned) as string[]).map((s) => s.toLowerCase()) | ||
| : [] |
There was a problem hiding this comment.
JSON.parseの例外未処理で初期化が中断されます
Line 211 と Line 220 の JSON.parse が失敗すると initTagCloud() 全体が落ち、タグクラウド描画が完全停止します。データ属性破損時のフォールバックを入れてください。
修正案(例外を握りつぶさず安全にフォールバック)
function initTagCloud(): void {
injectTagCloudStyle()
const container = document.getElementById("tag-cloud")
if (!container) return
const raw = container.dataset.tags
if (!raw) return
- const parsed: unknown = JSON.parse(raw)
+ let parsed: unknown
+ try {
+ parsed = JSON.parse(raw)
+ } catch {
+ return
+ }
if (!Array.isArray(parsed) || parsed.length === 0) return
const data = parsed as TagData[]
const activeTag = (container.dataset.activeTag ?? "").toLowerCase()
// pinnedCenterTags is configured in config/_default/params.toml [tagCloud]
const rawPinned = container.dataset.pinnedTags
- const pinnedTags: string[] = rawPinned
- ? (JSON.parse(rawPinned) as string[]).map((s) => s.toLowerCase())
- : []
+ let pinnedTags: string[] = []
+ if (rawPinned) {
+ try {
+ const parsedPinned = JSON.parse(rawPinned)
+ if (Array.isArray(parsedPinned)) {
+ pinnedTags = parsedPinned
+ .filter((v): v is string => typeof v === "string")
+ .map((s) => s.toLowerCase())
+ }
+ } catch {
+ pinnedTags = []
+ }
+ }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@assets/js/tag-cloud.ts` around lines 211 - 221, The JSON.parse calls in
initTagCloud (parsing `raw` into `parsed` and `rawPinned` into `pinnedTags`) can
throw and currently abort initialization; wrap each parse in a try/catch,
validate the result (Array.isArray for `parsed` and array/string items for
`pinnedTags`), and on error log the exception (e.g., console.error or a logger)
and fall back safely (return early if main `parsed` is invalid or set
`pinnedTags = []` when pinned parsing fails) so the tag cloud can continue
rendering without crashing.
| * restart: 再起 - Hugo開発サーバーを再起動 | ||
| * setup: 初回 - 初期セットアップ | ||
| * start: 開始 - Hugo開発サーバー起動 (aliases: dev) | ||
| * start: 開始 - Hugo開発サーバー起動(LAN内スマホからもアクセス可) (aliases: dev) |
There was a problem hiding this comment.
start の説明と接続先URL案内を一致させてください。
タスク一覧はLANアクセス対応になっていますが、Start セクションの案内URLが 0.0.0.0 のままだと、モバイル確認時の導線として誤解を招きます。<LOCAL_IP> ベースの案内に更新してください。
✏️ 提案差分(READMEの案内文更新)
-Then, web server is available at [http://0.0.0.0:1313/](http://0.0.0.0:1313/).
+Then, web server is available at `http://<LOCAL_IP>:1313/` (example: `http://192.168.1.10:1313/`).
+`task start` sets the base URL automatically; use the URL shown in Hugo startup logs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 73, The "start" task description and example connection
URL are inconsistent: update the README "start" (aliases: dev) entry so the
example access URL uses <LOCAL_IP> instead of 0.0.0.0 and ensure the explanatory
text clarifies LAN/mobile access; locate the line containing "* start:
開始 - Hugo開発サーバー起動(LAN内スマホからもアクセス可) (aliases: dev)" and replace the example
URL and any adjacent sentence that references 0.0.0.0 with a <LOCAL_IP>-based
instruction and brief note on how to find the local IP for mobile testing.
| const rect = cloud.getBoundingClientRect() | ||
| const internalScroll = cloud.scrollWidth - cloud.clientWidth | ||
| const externalOverflow = Math.max( | ||
| 0, | ||
| rect.right - document.documentElement.clientWidth | ||
| ) | ||
| return internalScroll + externalOverflow | ||
| }) | ||
| expect(overflow).toBe(0) |
There was a problem hiding this comment.
左方向のはみ出し検知が欠けています
Line 57-60 は右側だけを評価しているため、rect.left < 0 のケースを見逃します。ビューポート内保証の回帰テストとしては片手落ちです。
修正案(左右両方を評価)
const rect = cloud.getBoundingClientRect()
const internalScroll = cloud.scrollWidth - cloud.clientWidth
- const externalOverflow = Math.max(
- 0,
- rect.right - document.documentElement.clientWidth
- )
- return internalScroll + externalOverflow
+ const rightOverflow = Math.max(
+ 0,
+ rect.right - document.documentElement.clientWidth
+ )
+ const leftOverflow = Math.max(0, -rect.left)
+ return internalScroll + rightOverflow + leftOverflow📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const rect = cloud.getBoundingClientRect() | |
| const internalScroll = cloud.scrollWidth - cloud.clientWidth | |
| const externalOverflow = Math.max( | |
| 0, | |
| rect.right - document.documentElement.clientWidth | |
| ) | |
| return internalScroll + externalOverflow | |
| }) | |
| expect(overflow).toBe(0) | |
| const rect = cloud.getBoundingClientRect() | |
| const internalScroll = cloud.scrollWidth - cloud.clientWidth | |
| const rightOverflow = Math.max( | |
| 0, | |
| rect.right - document.documentElement.clientWidth | |
| ) | |
| const leftOverflow = Math.max(0, -rect.left) | |
| return internalScroll + rightOverflow + leftOverflow | |
| }) | |
| expect(overflow).toBe(0) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/posts.en.spec.ts` around lines 55 - 63, The current overflow
calculation in the test (using cloud.getBoundingClientRect(), internalScroll,
and externalOverflow) only measures right-side overflow (rect.right > viewport)
and misses left-side overflow (rect.left < 0); update the externalOverflow
computation to account for both sides by taking the max of 0 and rect.right -
document.documentElement.clientWidth as well as max of 0 and -rect.left (or
combine them), recompute overflow as internalScroll + both external overflows,
and keep the existing expect(overflow).toBe(0) assertion.
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
Summary
#tag-cloudコンテナの高さをレスポンシブ化(clamp(240px, 50vw, 320px))し、インラインstyle="height: 320px;"を削除tag-cloud.tsをリファクタリングしrenderTagCloud()を分離、ResizeObserverでデバイス回転時も再描画するよう対応task startに--bind 0.0.0.0 --baseURLを追加し、LAN 内スマホからの実機確認を可能にTest plan
task test:headless— 380件全テスト通過tag cloud container stays within viewportテストを追加(getBoundingClientRect+scrollWidthで tag cloud コンテナ固有のオーバーフローを検証)/posts/および/tags/*を目視確認Closes #58
Summary by CodeRabbit
新機能
バグ修正
テスト
その他