Skip to content

feat: 議程軌詳細頁面#215

Open
pan93412 wants to merge 4 commits into
mainfrom
implement-topic-page
Open

feat: 議程軌詳細頁面#215
pan93412 wants to merge 4 commits into
mainfrom
implement-topic-page

Conversation

@pan93412

@pan93412 pan93412 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

實作 #209:獨立的議程軌頁面。

本 PR 只負責議程軌詳細頁。美觀的議程軌列表頁由他人負責;這裡附帶的 /track 只是內部檢查用的索引頁。

內容

議程軌詳細頁 /track/[id](依新設計)

  • 標題、右上角「N 場議程」、概要副標
  • 議程日數切換、教室、社群連結
  • 公告 banner、議程軌描述
  • 依時間比例排版的議程表:CSS grid 時間軸,整點實線+半點虛線,卡片與刻度線共用同一組 grid 列而精準對齊
CleanShot 2026-06-20 at 22 07 09@2x CleanShot 2026-06-20 at 22 06 45@2x CleanShot 2026-06-20 at 22 06 42@2x

議程軌索引頁 /track(內部檢查用)

  • 列出所有議程軌與場次數,連到各詳細頁
CleanShot 2026-06-20 at 22 06 57@2x

設計決定

  • 設計系統交給 Riley 重新定義,這裡就繼續用 primary 來保證語意一致
  • 再麻煩 @mirumodapon 提供社群資訊的 Google Spreadsheet,用來取代 app/data/trackMeta.ts
  • 議程軌列表頁現在是隨便設計的,考慮到 Riley 之後就會設計跳轉過去的頁面。

待辦(非本 PR 範圍)

  • app/data/trackMeta.ts 目前只有範例結構,需填入各議程軌真實資料。
  • 正式的議程軌列表頁(美觀版)由他人負責;屆時詳細頁「返回議程軌列表」連結指向 /track,可視情況調整。

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added track browsing with a track list showing confirmed session counts.
    • Added track detail pages with localized, day-based filtering and a per-room timetable grid with time-aligned session blocks.
    • Added a session details modal with close controls and scroll locking.
    • Added a track header with localized subtitles/announcements, room locations, and external community links.
  • Improvements
    • Improved in-track navigation scrolling to better preserve position when switching within the same track path.

@pan93412 pan93412 marked this pull request as ready for review June 20, 2026 14:08
@pan93412 pan93412 marked this pull request as draft June 21, 2026 02:36
@pan93412 pan93412 marked this pull request as ready for review June 22, 2026 02:49
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 306e5f55-098f-4e05-b1b0-9d2287903b99

📥 Commits

Reviewing files that changed from the base of the PR and between 0ec1549 and bfef72e.

📒 Files selected for processing (1)
  • app/components/feature/CpTrackSessionPanel.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/components/feature/CpTrackSessionPanel.vue

📝 Walkthrough

Walkthrough

Adds track browsing and detail pages with shared track session types, Pretalx session helpers, track APIs, local track metadata, new track components, a session modal, and track-route scroll preservation.

Changes

Track browsing and detail

Layer / File(s) Summary
Track schemas and session helpers
shared/types/session.ts, server/utils/pretalx/sessions.ts, server/api/session/index.get.ts
Adds TrackSummary/TrackDetail schemas, shared Pretalx session conversion and day-grouping helpers, and refactors the session endpoint to use them.
Track list and detail APIs
server/api/track/index.get.ts, server/api/track/[id]/index.get.ts
Adds /api/track for sorted track counts and /api/track/[id] for track detail payloads grouped by day.
Track display components
app/components/feature/CpTrackHeader.vue, app/components/feature/CpTrackSchedule.vue, app/components/feature/CpTrackSessionBlock.vue
Adds the track header with day selection and community links, the per-room schedule grid, and the session card block used inside the schedule.
Track metadata, pages, modal, and scroll behavior
app/data/trackMeta.ts, app/pages/track/index.vue, app/pages/track/[id].vue, app/components/feature/CpTrackSessionPanel.vue, app/router.options.ts
Adds local track metadata, the track listing page, the track detail page with session-panel routing, the session panel modal, and track-route scroll preservation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: rileychh

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 標題清楚指出新增議程軌詳細頁面,與這次主要變更一致。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch implement-topic-page

Comment @coderabbitai help to get the list of available commands.

@pan93412 pan93412 requested a review from a team June 22, 2026 02:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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 `@app/components/feature/CpTrackHeader.vue`:
- Around line 57-68: The button component in the v-for loop iterating over days
is missing an aria-pressed attribute to announce the selected state to assistive
technologies. Add an aria-pressed attribute to the button element that is bound
to the same condition used for styling (day === activeDay), so that when a day
is selected, aria-pressed will be set to true and announced to screen readers.
- Line 80: The hardcoded Chinese delimiter `、` in the rooms.join('、') call on
the span element needs to be replaced with a localized separator that adapts to
the current language/locale. Instead of hardcoding the delimiter, use your
application's i18n system (such as this.$t() or useI18n()) to retrieve the
appropriate room separator string based on the user's locale, ensuring that
English pages display English delimiters (typically commas or comma-space) and
other languages display their respective separators.

In `@app/components/feature/CpTrackSchedule.vue`:
- Around line 24-30: In the parseMinutes function, change the return value from
0 to null (or undefined) when the regex match fails, since 0 represents midnight
and is a valid time that can distort grid calculations. Then update all callers
of parseMinutes (in the range/session-row calculation code around lines 51-57
and 98-105) to check for null/undefined return values and skip invalid entries
rather than treating them as valid session times that contribute to the grid
layout.

In `@app/pages/track/`[id].vue:
- Around line 166-167: The day label in the zh locale configuration is using
English text "Day {n}" instead of a Chinese translation. Locate the day key in
the zh locale section and replace the English string with the appropriate
Chinese translation while preserving the {n} placeholder for dynamic day
numbering.
- Around line 36-45: The issue is that when the `days` array changes (such as
when navigating between different track IDs), the `manualSelectedDay` retains
its previous value even if that day no longer exists in the new `days` array,
causing `daySessions` to become empty and `dayIndex` to show Day 0. Add a
watcher on the `days` array that monitors changes and validates whether the
current `selectedDay.value` still exists in the updated `days` array. If the
selected day is no longer present in the new days list, reset
`manualSelectedDay` to null so that the computed property `selectedDay` will
properly default to the first available day from the new `days` array.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b983e647-a695-415d-9ea9-7748502388d2

📥 Commits

Reviewing files that changed from the base of the PR and between a4f7bbb and e3e3c55.

📒 Files selected for processing (11)
  • app/components/feature/CpTrackHeader.vue
  • app/components/feature/CpTrackSchedule.vue
  • app/components/feature/CpTrackSessionBlock.vue
  • app/data/trackMeta.ts
  • app/pages/track/[id].vue
  • app/pages/track/index.vue
  • server/api/session/index.get.ts
  • server/api/track/[id]/index.get.ts
  • server/api/track/index.get.ts
  • server/utils/pretalx/sessions.ts
  • shared/types/session.ts

Comment thread app/components/feature/CpTrackHeader.vue
Comment thread app/components/feature/CpTrackHeader.vue Outdated
Comment thread app/components/feature/CpTrackSchedule.vue
Comment thread app/pages/track/[id].vue
Comment thread app/pages/track/[id].vue Outdated

@mirumodapon mirumodapon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

當列表中的議程被點擊,會被轉跳到議程的網址,並且在這個網址關閉之後,會維持在議程表,期待可以直接在原頁面展開議程,應該用 clientonly 就可以了

@pan93412

Copy link
Copy Markdown
Contributor Author

當列表中的議程被點擊,會被轉跳到議程的網址,並且在這個網址關閉之後,會維持在議程表,期待可以直接在原頁面展開議程,應該用 clientonly 就可以了

好,我來調整一下設計~

@mirumodapon mirumodapon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

資料顯示好像只有英文,沒有正確再中文模式下顯示中文

@pan93412 pan93412 marked this pull request as draft June 28, 2026 06:32
@pan93412

pan93412 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

@mirumodapon 已在 f660d56 處理:

① 直接在原頁面展開議程
點擊議程卡片不再跳轉到 /session/<id>,改為在網址加上 ?session=<id> query string,並用 <ClientOnly> 在原頁面展開側邊面板(沿用既有的 CpSessionInfoCard,資料直接取自已載入的 session,不需額外 fetch,靜態產生也沒問題)。關閉時移除 query string,會停留在議程軌頁面、且維持原本的捲動位置。

② 中文模式只顯示英文
我用 dev server 實測了 zh 模式(SSR 與 client 都試過),議程軌名稱、描述、議程標題、教室、「第 N 天」都有正確顯示中文。

@pan93412 pan93412 requested a review from mirumodapon June 28, 2026 07:03
@pan93412 pan93412 marked this pull request as ready for review June 28, 2026 07:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@app/components/feature/CpTrackSessionPanel.vue`:
- Around line 45-53: The dialog in CpTrackSessionPanel.vue currently locks body
scroll and handles Escape, but it does not manage keyboard focus, so users can
tab behind the modal. Update the panel’s mounted/unmounted behavior and focus
handlers to move focus into the dialog when it opens, keep Tab/Shift+Tab trapped
within the dialog content, and restore focus to the previously focused element
when it closes; use the existing onMounted, onUnmounted, and onKeydown logic in
CpTrackSessionPanel.vue as the entry points.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b6c5b18b-b7aa-45d9-b350-b9ed02bad285

📥 Commits

Reviewing files that changed from the base of the PR and between e3e3c55 and f660d56.

📒 Files selected for processing (5)
  • app/components/feature/CpTrackHeader.vue
  • app/components/feature/CpTrackSchedule.vue
  • app/components/feature/CpTrackSessionPanel.vue
  • app/pages/track/[id].vue
  • app/router.options.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/components/feature/CpTrackSchedule.vue
  • app/components/feature/CpTrackHeader.vue
  • app/pages/track/[id].vue

Comment thread app/components/feature/CpTrackSessionPanel.vue

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

Copy link
Copy Markdown

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: f660d56b9a

ℹ️ 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 thread app/components/feature/CpTrackSessionPanel.vue Outdated
@rileychh-dokploy-coscup

rileychh-dokploy-coscup Bot commented Jul 5, 2026

Copy link
Copy Markdown

Dokploy Preview Deployment

Name Status Preview Updated (UTC)
Nuxt ✅ Done Preview URL 2026-07-05T07:47:43.946Z

pan93412 and others added 3 commits July 5, 2026 14:59
Add a per-track agenda page at `/track/[id]` showing the track title,
session count, day toggles, room(s), community links, announcement, and a
time-aligned schedule (CSS-grid timeline with hour/half-hour gridlines).

- server/api/track/[id]: track name/description + sessions grouped by day
- server/api/track: track index (id, name, session count) for the checking list
- server/utils/pretalx/sessions: shared buildSessionSummary/groupSessionsByDay
  (session index endpoint refactored to reuse it)
- app/data/trackMeta: local source for subtitle/links/announcement (not in Pretalx)
- app/pages/track/[id] + index, CpTrackHeader/Schedule/SessionBlock components

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clicking a session in the track schedule now opens a ClientOnly side
panel on the same page (driven by a `?session=<id>` query string)
instead of navigating away to /session/<id>. Scroll position is kept
when opening/closing the panel.

Also addresses CodeRabbit review:
- aria-pressed on day filter buttons
- localized room/speaker separator via i18n block
- parseMinutes returns null on parse failure; callers skip invalid slots
- reset selected day when it no longer exists in the available days
- Chinese label for the "day" string

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The fixed w-120 drawer anchored with right-0 pushed its left edge
off-screen on viewports narrower than 30rem, and the body scroll lock
made that content unreachable. Use max-w-120 w-full so the drawer fits
small viewports and caps at 30rem on larger ones.
@pan93412 pan93412 force-pushed the implement-topic-page branch from 58a7ff0 to 0ec1549 Compare July 5, 2026 06:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/components/feature/CpTrackSessionPanel.vue (1)

60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

UnoCSS class ordering flagged by linter.

Static analysis flags unordered utility classes on these lines; low-effort cleanup to keep lint clean.

Also applies to: 66-66

🤖 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 `@app/components/feature/CpTrackSessionPanel.vue` at line 60, The UnoCSS
utilities in CpTrackSessionPanel are out of the expected order, so reorder the
class lists on the affected template elements to satisfy the linter. Update the
static class strings in the component’s overlay markup (including the matching
element on the other flagged line) so the utilities follow the project’s
prescribed ordering without changing behavior.

Source: Linters/SAST tools

🤖 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 `@app/components/feature/CpTrackSessionPanel.vue`:
- Around line 16-22: The locale resolution in `sessionInfo` is being handled
manually with `localeKey` and inline room fallback ternaries, which should
instead use the shared `useLocaleContent` composable. Update
`CpTrackSessionPanel.vue` to resolve both session content and room locale
content through `useLocaleContent`, so fallback behavior is centralized and
consistent with the rest of the app.
- Around line 18-37: The CpSessionInfoCard usage in CpTrackSessionPanel is
missing the required ad prop, so update the template to pass an explicit null
value unless ad data is available to thread through. Locate the
CpSessionInfoCard binding in CpTrackSessionPanel.vue and add the ad prop
alongside the existing sessionInfo data so the component receives the expected
Ad | null input.

---

Nitpick comments:
In `@app/components/feature/CpTrackSessionPanel.vue`:
- Line 60: The UnoCSS utilities in CpTrackSessionPanel are out of the expected
order, so reorder the class lists on the affected template elements to satisfy
the linter. Update the static class strings in the component’s overlay markup
(including the matching element on the other flagged line) so the utilities
follow the project’s prescribed ordering without changing behavior.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9a1f1da-3b25-4c2c-9313-f01699854992

📥 Commits

Reviewing files that changed from the base of the PR and between f660d56 and 0ec1549.

📒 Files selected for processing (13)
  • app/components/feature/CpTrackHeader.vue
  • app/components/feature/CpTrackSchedule.vue
  • app/components/feature/CpTrackSessionBlock.vue
  • app/components/feature/CpTrackSessionPanel.vue
  • app/data/trackMeta.ts
  • app/pages/track/[id].vue
  • app/pages/track/index.vue
  • app/router.options.ts
  • server/api/session/index.get.ts
  • server/api/track/[id]/index.get.ts
  • server/api/track/index.get.ts
  • server/utils/pretalx/sessions.ts
  • shared/types/session.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • app/components/feature/CpTrackHeader.vue
  • server/api/track/index.get.ts
  • app/components/feature/CpTrackSessionBlock.vue
  • shared/types/session.ts
  • app/router.options.ts
  • server/api/track/[id]/index.get.ts
  • server/api/session/index.get.ts
  • server/utils/pretalx/sessions.ts
  • app/data/trackMeta.ts
  • app/pages/track/index.vue
  • app/pages/track/[id].vue
  • app/components/feature/CpTrackSchedule.vue

Comment thread app/components/feature/CpTrackSessionPanel.vue
Comment thread app/components/feature/CpTrackSessionPanel.vue

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

Copy link
Copy Markdown

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: 0ec1549110

ℹ️ 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 thread app/pages/track/[id].vue
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.

2 participants