diff --git a/docs/classroom-notification-center/screenshots/0101-notification-bell.png b/docs/classroom-notification-center/screenshots/0101-notification-bell.png index 145542a20b3..19ab7a81a93 100644 Binary files a/docs/classroom-notification-center/screenshots/0101-notification-bell.png and b/docs/classroom-notification-center/screenshots/0101-notification-bell.png differ diff --git a/docs/classroom-notification-center/screenshots/0102-notification-panel.png b/docs/classroom-notification-center/screenshots/0102-notification-panel.png index 23adf676bde..a49ad33901f 100644 Binary files a/docs/classroom-notification-center/screenshots/0102-notification-panel.png and b/docs/classroom-notification-center/screenshots/0102-notification-panel.png differ diff --git a/docs/classroom-notification-center/screenshots/0103-admin-notify-form.png b/docs/classroom-notification-center/screenshots/0103-admin-notify-form.png index 9b8a3866800..607456d0da8 100644 Binary files a/docs/classroom-notification-center/screenshots/0103-admin-notify-form.png and b/docs/classroom-notification-center/screenshots/0103-admin-notify-form.png differ diff --git a/docs/classroom-notification-center/screenshots/0201-mine-recommended-badges.png b/docs/classroom-notification-center/screenshots/0201-mine-recommended-badges.png index fb6c6c5f8f4..56b011d062d 100644 Binary files a/docs/classroom-notification-center/screenshots/0201-mine-recommended-badges.png and b/docs/classroom-notification-center/screenshots/0201-mine-recommended-badges.png differ diff --git a/docs/classroom-notification-center/screenshots/0202-broaden-form.png b/docs/classroom-notification-center/screenshots/0202-broaden-form.png index 681c60c7e80..40037aa3f87 100644 Binary files a/docs/classroom-notification-center/screenshots/0202-broaden-form.png and b/docs/classroom-notification-center/screenshots/0202-broaden-form.png differ diff --git a/docs/classroom-notification-center/screenshots/0203-admin-shared-recommend.png b/docs/classroom-notification-center/screenshots/0203-admin-shared-recommend.png index 5b01424cf49..ae8dcf1c3a9 100644 Binary files a/docs/classroom-notification-center/screenshots/0203-admin-shared-recommend.png and b/docs/classroom-notification-center/screenshots/0203-admin-shared-recommend.png differ diff --git a/docs/classroom-notification-center/screenshots/0301-share-suggestion-banner.png b/docs/classroom-notification-center/screenshots/0301-share-suggestion-banner.png index 13cfc6a81bd..e0e0a6d2d76 100644 Binary files a/docs/classroom-notification-center/screenshots/0301-share-suggestion-banner.png and b/docs/classroom-notification-center/screenshots/0301-share-suggestion-banner.png differ diff --git a/docs/classroom-notification-center/screenshots/0302-board-share-suggested.png b/docs/classroom-notification-center/screenshots/0302-board-share-suggested.png index 4eb2afbfb32..983c69088ca 100644 Binary files a/docs/classroom-notification-center/screenshots/0302-board-share-suggested.png and b/docs/classroom-notification-center/screenshots/0302-board-share-suggested.png differ diff --git a/docs/classroom-notification-center/screenshots/0303-admin-recommend-sharing.png b/docs/classroom-notification-center/screenshots/0303-admin-recommend-sharing.png index 7f1760f51d2..cc759c43908 100644 Binary files a/docs/classroom-notification-center/screenshots/0303-admin-recommend-sharing.png and b/docs/classroom-notification-center/screenshots/0303-admin-recommend-sharing.png differ diff --git a/docs/classroom-notification-center/screenshots/0304-admin-overview-candidates.png b/docs/classroom-notification-center/screenshots/0304-admin-overview-candidates.png index 49ddbbf7f15..48495b462c3 100644 Binary files a/docs/classroom-notification-center/screenshots/0304-admin-overview-candidates.png and b/docs/classroom-notification-center/screenshots/0304-admin-overview-candidates.png differ diff --git a/docs/classroom/testing.md b/docs/classroom/testing.md index 5b30962f009..df356ae7d3d 100644 --- a/docs/classroom/testing.md +++ b/docs/classroom/testing.md @@ -36,7 +36,8 @@ Playwright MCP および Selenium integration tests で使用する `data-testid | `classroom-back` | button | 戻る | | `classroom-refresh` | button | 更新 (↻) | | `classroom-google-import` | button | Google Classroom からインポート | -| `classroom-teacher-logout` | button | ログアウト | +| `classroom-avatar-button` | button | アカウントメニュー(タイトルバー右上・メール頭文字 + ▼) | +| `classroom-teacher-logout` | button | ログアウト(アカウントメニュー内) | ### クラス作成 @@ -204,7 +205,8 @@ Playwright MCP および Selenium integration tests で使用する `data-testid | `classroom-class-open-{groupId}` | button | クラスカード本体(クリックでクラスをひらく) | | `classroom-class-evaluate-{groupId}` | button | クラスカードの「評価」 | | `classroom-class-import-gc` | button | クラス一覧の「Google Classroom からインポート」(Google ログイン時のみ) | -| `classroom-teacher-logout` | button | ログアウト(タイトルバー右端に常時表示) | +| `classroom-avatar-button` / `classroom-avatar-initials` / `classroom-avatar-email` | button/span | アカウントメニュー(右上・メール頭文字 + ▼。クリックでメール表示 + ログアウト) | +| `classroom-teacher-logout` | button | ログアウト(アカウントメニュー内。#1111 レビューでタイトルバー常時表示から移動) | | `classroom-class-create-section` | input | 同時作成: セクション(オプション) | | `classroom-class-settings-open-{groupId}` | button | クラスカードの「設定」(インライン編集を開く) | | `classroom-class-settings-{groupId}` | form | クラス設定のインライン編集フォーム | @@ -294,7 +296,7 @@ Playwright MCP および Selenium integration tests で使用する `data-testid | `classroom-description-preview` | div | 右ペインの生徒視点プレビュー | | `classroom-description-preview-body` | div | プレビュー本文(テキスト+画像) | | `classroom-description-preview-prev` / `-next` | button | プレビューのページ送り | -| `classroom-teacher-email` | span | タイトルバーのユーザーメール(OIDC トークンに email がある場合のみ) | +| `classroom-avatar-email` | span | アカウントメニュー内のユーザーメール(OIDC トークンに email がある場合のみ。旧 `classroom-teacher-email` は廃止) | | `classroom-board-create-cancel` / `classroom-board-reuse-cancel` | button | インラインフォームのキャンセル | | `classroom-google-course-imported-{courseId}` | span | GC コースの「インポート済み」バッジ | | `classroom-breadcrumb-assignments` | button | パンくず「課題一覧」リンク | diff --git a/docs/classroom/ui-ux.md b/docs/classroom/ui-ux.md index 030cf58a5cb..a30c14d4251 100644 --- a/docs/classroom/ui-ux.md +++ b/docs/classroom/ui-ux.md @@ -165,25 +165,35 @@ Google または Microsoft アカウントでサインインする画面。先 - 課題の所属クラス変更・人数編集・課題単位の共同管理者・複製は**できない**(クラス設定 / 課題一覧の再利用へ集約)。フッターのボタンは「**課題をアーカイブ**」(soft-delete。ボードの「アーカイブ済みの課題」からいつでも復元可能。testid は歴史的経緯で `classroom-delete-classroom` のまま) - 主な data-testid: `classroom-tab-description` / `classroom-description-editor` / `classroom-description-preview[-body|-prev|-next]` / `classroom-tab-members` -## 1.8 先生: お知らせセンター(タイトルバー 🔔・EPIC #1111) +## 1.8 先生: お知らせセンター(タイトルバー・EPIC #1111) ![お知らせセンター](screenshots/0218-teacher-notifications.png) -クラス管理のタイトルバー右上(× の左隣)に 🔔 ボタン。運営(Admin)からのお知らせが届くと未読数バッジが付く。 +クラス管理のタイトルバー右上(× の左隣)は **アバターメニュー**(メール頭文字 + ▼)に固定。その左に **白一色のベル**(お知らせ)を置く。運営(Admin)からのお知らせが届くと未読数バッジが付く。 -- クリックで一覧パネルを開閉。**開いた時点で全既読**になりバッジが消える(その場では未読ドットで新着を見分けられる) -- お知らせ本文をクリックすると、`link` の種類に応じて該当画面へジャンプ(`kind: 'classroom'` → そのクラスを選択して課題詳細へ)。未知の kind は無視(前方互換) -- 60 秒間隔でポーリング。取得エラーはクラス管理本体に影響させない(表示しない) +- **アバターメニュー**: メール頭文字(`kouji@…`→`K` / `kouji.takao@…`→`KT`)の丸アイコン + ▼。クリックでポップアップ(メール表示 + ログアウト。将来の設定項目もここに集約)。紫背景で視認できる白丸 + 紫文字 +- ベルのクリックで一覧パネルを開閉。**開いた時点で全既読**になりバッジが消える(その場では未読ドットで新着を見分けられる) +- パネルは **先頭 5 件**のみ表示。6 件以上あるときは「すべて見る(N件)」で **全件一覧ページ**(`teacher-notifications` フェーズ・**10 件/ページ**)へ遷移 +- お知らせ本文をクリックすると、`link` の種類に応じて該当画面へジャンプ(`kind: 'classroom'` → そのクラスを選択して課題詳細へ / `kind: 'shared-mine'` → みんなの課題の自分の投稿へ)。未知の kind は無視(前方互換) +- **取得は 1 日 1 回**(コスト削減): その日はじめてクラス管理を開いたときだけ `GET /notifications` を 1 回呼び、localStorage に日付つきでキャッシュ。同じ日の再オープンは API を叩かない(旧 60 秒ポーリングは廃止)。共有 PC 対策として先生メールでキャッシュを識別。取得エラーはクラス管理本体に影響させない(表示しない)。※その日の初回取得後に届いたお知らせは翌日反映(運営連絡は多くて週 1 回程度の前提) - 送信側は Admin SPA(クラス詳細の「先生へのお知らせ」フォーム → `POST /admin/notifications`)。`docs/admin/README.md` を参照 | 要素 | data-testid | 操作 | |------|-------------|------| -| 🔔 ボタン | `classroom-notifications-button` | クリックでパネル開閉 | +| アバターボタン | `classroom-avatar-button` | クリックでアカウントメニュー開閉 | +| イニシャル丸 | `classroom-avatar-initials` | メール頭文字(1〜2 文字) | +| メニューのメール | `classroom-avatar-email` | ポップアップ内のメール表示 | +| ログアウト | `classroom-teacher-logout` | アカウントメニュー内 | +| ベルボタン | `classroom-notifications-button` | クリックでパネル開閉 | | 未読バッジ | `classroom-notifications-badge` | 未読数(10 以上は「9+」)。未読 0 で非表示 | -| 一覧パネル | `classroom-notifications-panel` | — | -| お知らせ 1 件 | `classroom-notification-item-{notificationId}` | クリックでリンク先へジャンプ + パネルを閉じる | +| 一覧パネル | `classroom-notifications-panel` | 先頭 5 件 | +| すべて見る | `classroom-notifications-see-all` | 全件一覧ページへ(6 件以上のとき) | +| お知らせ 1 件(パネル) | `classroom-notification-item-{notificationId}` | クリックでリンク先へジャンプ + パネルを閉じる | | 未読ドット | `classroom-notification-unread-dot` | 未読アイテムのみ | | 空メッセージ | `classroom-notifications-empty` | お知らせ 0 件のとき | +| 全件一覧ページ | `classroom-notifications-page` | `teacher-notifications` フェーズ | +| ページ内 1 件 | `classroom-notification-page-item-{notificationId}` | クリックでリンク先へジャンプ | +| ページャ | `classroom-notifications-pager` / `-prev` / `-next` | 10 件/ページ | ## 1.9 先生: 共有推奨バナー(#1106) diff --git a/packages/admin/src/components/app.css b/packages/admin/src/components/app.css index 0290c5817b4..8ecdcb7fba5 100644 --- a/packages/admin/src/components/app.css +++ b/packages/admin/src/components/app.css @@ -45,10 +45,81 @@ body { font-size: 0.75rem; } -.admin-header-email { + +/* アバターメニュー(右上固定・#1111 レビュー)。 */ +.admin-avatar-menu { + position: relative; margin-left: auto; +} + +.admin-avatar-button { + display: flex; + align-items: center; + gap: 0.25rem; + border: none; + background: transparent; + padding: 0; + cursor: pointer; +} + +.admin-avatar-initials { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.9rem; + height: 1.9rem; + border-radius: 50%; + background: white; + color: hsl(260, 60%, 50%); + font-size: 0.75rem; + font-weight: bold; +} + +.admin-avatar-caret { + color: white; + font-size: 0.6rem; + line-height: 1; +} + +.admin-avatar-popup { + position: absolute; + top: 2.6rem; + right: 0; + min-width: 13rem; + background: white; + border: 1px solid hsl(220, 15%, 85%); + border-radius: 0.5rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + color: hsl(220, 15%, 25%); + text-align: left; + overflow: hidden; + z-index: 100; +} + +.admin-avatar-popup-email { + padding: 0.6rem 0.9rem; + font-size: 0.75rem; + color: hsl(220, 10%, 45%); + border-bottom: 1px solid hsl(220, 15%, 92%); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.admin-avatar-popup-item { + display: block; + width: 100%; + padding: 0.6rem 0.9rem; + border: none; + background: none; + text-align: left; font-size: 0.85rem; - opacity: 0.9; + color: inherit; + cursor: pointer; +} + +.admin-avatar-popup-item:hover { + background: hsl(220, 20%, 96%); } .admin-main { diff --git a/packages/admin/src/components/app.jsx b/packages/admin/src/components/app.jsx index 2ad355d92c2..07753b3ef92 100644 --- a/packages/admin/src/components/app.jsx +++ b/packages/admin/src/components/app.jsx @@ -5,6 +5,7 @@ import {useCallback, useEffect, useRef, useState} from 'react'; import {fetchMe, setIdToken} from '../lib/admin-api.js'; import {getDevLoginToken, initGoogleSignIn} from '../lib/google-auth.js'; +import AvatarMenu from './avatar-menu.jsx'; import BugReportsView from './bug-reports-view.jsx'; import ClassroomsView from './classrooms-view.jsx'; import SharedAssignmentsView from './shared-assignments-view.jsx'; @@ -41,6 +42,13 @@ const App = () => { const handleReload = useCallback(() => window.location.reload(), []); + // トークンはモジュールメモリのみ。ログアウトはリロードで確実に破棄し + // サインイン画面へ戻す(session-expired の再読み込みと同じ手当て)。 + const handleLogout = useCallback(() => { + setIdToken(null); + window.location.reload(); + }, []); + // Google ID tokens live ~1 hour and the SPA keeps them in memory only, so // an expired session surfaces as API 401s. The clients broadcast those; // show one clear prompt instead of per-view raw errors. @@ -91,10 +99,10 @@ const App = () => {

{'Smalruby Admin'}

{me.stage} - {me.email} +