Commit Graph
7 Commits
Author SHA1 Message Date
bb8d4f30e7 feat(chat): add experimental Pi classroom runtime behind a flag (#914)
* feat(chat): add experimental Pi classroom runtime

* fix(chat): harden Pi whiteboard action sequencing

* style(chat): format session retirement flow

* style(playback): format async scene transition

* fix(chat): retire actions on session errors

* fix(chat): close Pi runtime lifecycle gaps

* fix(chat): avoid replaying historical whiteboard actions

* fix(chat): prevent Pi structured-output residue from leaking and inflating turns

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): expose whiteboard element/line ids and bound code-line context

Surface each element's id (and code line ids) in the Pi whiteboard context so
later child agents can target wb_delete / wb_edit_code, and cap the rendered
code lines with a shared character budget so a code-heavy board cannot grow the
prompt without bound. Return only the current turn's whiteboard ledger from the
Pi director loop instead of carrying history forward across requests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): bound Pi whiteboard code context

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): prioritize newer persisted whiteboard code in budget

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): enforce whiteboard boundaries across Pi sessions

* feat(chat): refine soft-closing discussion controls

* fix(chat): make whiteboard clearing model-directed

---------

Co-authored-by: apple <apple@GigideMacBook-Air.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: LING-6150 <duan.lin@northeastern.edu>
2026-07-17 11:22:02 +08:00
f86c0482dc feat: end-of-course completion page + persistent quiz state (#484)
* refactor(quiz): extract grading helpers into lib/quiz/grading

* feat(classroom): add summarizeScenes aggregation helper

* feat(i18n): add classroomComplete translations

* feat(classroom): add ClassroomCompletePage component

* feat(stage): render ClassroomCompletePage when course finishes

* feat(stage): show 'Course complete' slot in sidebar

* chore: apply prettier formatting

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

* feat(classroom): richer completion visuals — confetti, gold trophy, stats cards

- Replace lucide Trophy with custom gradient SVG (3x larger, base + stem + star)
- Add one-shot confetti burst (55 particles, 7-color palette, no new dep)
- Add looping sparkles + pulsing halo around trophy
- Redesign stats from thin icon row into metric cards with count-up numbers
- Upgrade quiz block to gradient card with animated gold progress ring
- Add gradient ribbon badge above title, bg-clip gradient title
- Sidebar thumbnail: amber gradient + sparkles + larger filled trophy
- Respect prefers-reduced-motion (skips confetti/sparkles/count-up)

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

* fix(stage): show course-complete title in header; tone down sidebar thumbnail

- Header top-left was showing loading fallback on pending slot; now renders
  t('stage.courseComplete') when isCourseComplete && isPendingScene
- Sidebar thumbnail was too saturated next to neutral slide thumbnails; back
  to soft amber-50 base with a subtle radial glow, smaller muted sparkles,
  and colored amber-500 trophy (no more filled white on gradient)

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

* fix(classroom): persist submitted quiz answers for completion page

Previously handleSubmit cleared the quizDraft cache, leaving nothing for
the completion page to read — score always showed 0/N. Now submit also
writes to a separate quizAnswers:<sceneId> key that is not cleared by
the normal in-progress draft lifecycle.

- quiz-view: on submit, mirror answers into quizAnswers:<sceneId>
- quiz-view: on retry, remove that persistent key too
- classroom-complete: read quizAnswers first; fall back to quizDraft so
  an unsubmitted attempt still shows partial progress rather than 0

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

* feat(quiz): persist submitted quiz state across unmounts

Before: remounting a quiz scene after submit restarted it from 'not_started'
because the draft cache was cleared at submit time. Reopening meant redoing
everything.

Now on mount, read quizAnswers:<sceneId> + quizResults:<sceneId> and restore:
- Both present → jump to 'reviewing' with graded answers and feedback
- Only answers (mid-grading unmount) → 'answering' with answers pre-filled
- Neither → fall through to existing draft-restore path

Results are persisted when the grading useEffect transitions to 'reviewing',
and both keys are cleared together by handleRetry.

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

* fix(home): prevent horizontal shift when recent classrooms expand

Expanding recent classrooms could grow the page past the viewport height,
making a vertical scrollbar appear. Because the scrollbar takes layout
width, the centered header and trigger row jumped horizontally. Reserve
the scrollbar gutter on <html> so the gutter is always present and layout
stays stable across expand/collapse.

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

* fix(home): force always-visible scrollbar to eliminate expand/collapse shift

scrollbar-gutter: stable alone wasn't enough (browser/config dependent).
Adding overflow-y: scroll on html forces the vertical scrollbar to always
occupy layout width, so expanding recent classrooms past the viewport
no longer shifts the centered trigger row.

Trade-off: home page now always shows a scrollbar track, even when
content fits viewport. Acceptable cost for stable layout.

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

* refactor(quiz): extract persistence module + sweep localStorage on delete

Addresses code review on #484:

1. New lib/quiz/persistence.ts centralizes the three per-scene localStorage
   keys (draft / answers / results) behind readSubmittedState,
   readAnswersForSummary, writeSubmittedAnswers, writeSubmittedResults,
   clearSubmitted, clearAllForScene. quiz-view and classroom-complete now
   both consume this module instead of hand-rolling localStorage calls,
   removing the schema-coupling between the two components.

2. deleteStageData now collects scene ids before deletion and sweeps the
   matching quiz persistence keys, fixing the storage leak when a
   classroom is deleted.

3. ClassroomCompletePage gets role=status / aria-live=polite /
   aria-label for screen readers to announce the completion moment.

4. Tests: 11 new unit tests covering the persistence module
   (read/write/clear roundtrips, draft fallback, corrupt-JSON
   tolerance, scene-isolation).

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

* fix(classroom): address review on PR #484 (a11y, motion, coupling)

Addresses cosarah's review:

1. prefers-reduced-motion now fully honored — wrap ClassroomCompletePage
   in MotionConfig with reducedMotion='always' when the OS preference is
   on. This neutralizes the previously-uncovered animations (trophy
   float repeat:Infinity, halo pulse repeat:Infinity, page/cards/trophy
   entrance fade+scale+spring).

2. Move role='status' off the noisy outer wrapper; replace with a single
   sr-only span carrying the title text so screen readers get one clean
   announcement instead of every count-up tick. Outer is now a plain
   <section aria-label=...>.

3. Wrap ClassroomCompletePageConnected in a motion.div inside
   AnimatePresence so leaving the pending slot fades instead of snapping
   (matches the loading-overlay branch).

4. quiz-view's draft cache key now uses the draftKey() helper exported
   from lib/quiz/persistence so the prefix has one source of truth (no
   silent desync if the schema evolves).

5. isCourseComplete now requires scenes.length === outlines.length, so
   a partial generation with failed outlines doesn't falsely trigger.

6. aria-hidden on decorative motion wrappers (Confetti, Sparkles,
   trophy entrance) for cleaner SR experience.

7. Comment on summarizeScenes useMemo explaining the mount-fresh
   assumption.

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

* chore: prettier-format review-fix changes

CI's format check (pnpm check) failed because the previous commit's
changes weren't run through prettier locally before push.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com>
2026-04-25 16:17:41 +08:00
Yizuki_AmeandYizukiAme 0533adbe82 feat: refine presentation mode speech bubbles, input flow, and accessibility (#195)
* feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

.git/COMMIT_EDITMSG [unix] (14:47 22/03/2026)                                                                    1,1 Top
feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

.git/COMMIT_EDITMSG [unix] (14:47 22/03/2026)                                                                    1,1 Top
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

* feat: refine presentation mode speech bubbles, input flow, and accessibility

- User messages now display as right-side speech bubbles for send confirmation
- 'Your turn' cue is a clickable glass button respecting ASR preference
- Cue properly excludes bubbleRole/thinkingState to avoid UI overlap
- Right-side dock + bubble uses flexbox for dynamic stacking
- Voice-to-text switch now stops recording to prevent mic leaks
- Backdrop no longer blocks toolbar (bottom-14 cutoff)
- User message clears immediately when agent starts responding
- Dock buttons and avatar have proper aria-labels and button semantics
- Voice panel mic trigger converted from div to button with aria-label
- Added 5 i18n keys (zh-CN + en-US) for new accessible labels
- matchesSide typed as boolean, removed unused userAvatar from left overlay
- Avatar alt text localized via i18n

Refs #102

* fix: address code review audit  cancel ghost sends, consolidate getAgentConfig, fix a11y

* fix: guard concurrent voice recording and suppress cancel error toast

* style: vertically center placeholder text in presentation input bar

* style: full light-mode adaptation for presentation UI, toolbar dividers, bubble opacity 60%

* chore: address #129 follow-up  remove orphan i18n keys, clarify waitUntilDrained pause behavior

* fix: resolve spacebar conflict and address review feedback

- Stage: skip Space during active QA/discussion (let Roundtable own
  buffer-level pause); deterministic, no listener-order dependency
- Stage: wrap handlePlayPause in useCallback([playbackCompleted,
  currentScene]) to avoid keyboard listener re-registration
- Stage: clear presentationIdleTimerRef on unmount
- PresentationBubbleCard: add aria-live='polite' for screen readers
- Extract shared avatar constants to roundtable/constants.ts

* style: format with prettier

* fix: render ProactiveCard inside fullscreen container via portalContainer prop

* feat: show requesting agent avatar in dock on discussion request

---------

Co-authored-by: YizukiAme <yizukiame@github.com>
2026-03-24 13:04:55 +08:00
wyucandClaude Opus 4.6 14f10736e1 fix: restore classroom playback toolbar removed in 0610053
The CanvasToolbar component and all toolbar-related wiring were
accidentally deleted during a refactor. This restores:
- components/canvas/canvas-toolbar.tsx (scene nav, play/pause, speed,
  volume, whiteboard, auto-play, stop discussion controls)
- Toolbar rendering in CanvasArea (autonomous mode) and Roundtable
  (playback mode)
- Toolbar-related props/handlers in Stage (scene navigation, stop
  discussion)
- Missing i18n keys: roundtable.stopDiscussion, speed, autoPlay,
  autoPlayOff (zh-CN + en-US)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:33:35 +08:00
wyucandClaude Opus 4.6 843d33e5cc chore: enforce Prettier formatting and fix lint issues
- Add .prettierignore to exclude vendor packages, lock files, markdown, and YAML
- Update .prettierrc: printWidth 100, singleQuote, trailingComma "all"
- Run Prettier across all source files for consistent formatting
- Fix unused imports (UserRequirements, setTTSProvider)
- Fix eslint-disable comment placement after Prettier reformat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:09:45 +08:00
wyucandClaude Opus 4.6 0610053d58 Refactor: remove Canvas toolbar, extract model resolution, delete dead routes
- Delete CanvasToolbar, CanvasTool, and toolbar types entirely
- Remove toolbar-related props/state from Stage, CanvasArea, Roundtable
- Delete 3 obsolete generation routes (generate/, scene/, scene-outlines/)
- Extract resolveModel/resolveModelFromHeaders into lib/server/resolve-model.ts
  reducing ~15 lines of boilerplate per route to 1 line (9 routes updated)
- Delete unused lib/audio/qwen.html (156KB unreferenced doc snapshot)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:06:33 +08:00
wyucandClaude Opus 4.6 cc44f32ca8 Refactor: directory structure cleanup + Google Fonts localization
- Replace next/font/google with local fonts (geist + @fontsource-variable/inter)
  to eliminate build-time network dependency
- Resolve lib/utils.ts vs lib/utils/ naming conflict (cn() → lib/utils/cn.ts)
- Move React Context Providers from lib/store/ to lib/contexts/
- Consolidate hooks into lib/hooks/ (use-theme, use-i18n)
- Organize loose components into subdirectories:
  agent-* → components/agent/
  canvas-* → components/canvas/
  generation-toolbar, media-popover → components/generation/
  speech-button, tts-config-popover → components/audio/
  proactive-card → components/chat/

65 files changed, lint 0 errors, build 28 pages passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 19:35:06 +08:00