summaryrefslogtreecommitdiffhomepage
path: root/packages/app
diff options
context:
space:
mode:
authorBrendan Allan <[email protected]>2026-02-02 19:05:47 +0800
committerGitHub <[email protected]>2026-02-02 05:05:47 -0600
commit52eb8a7a8c2ceefa0de8a1a37d5f8754f08cfcff (patch)
tree3417ad2c169a3f666dfe60b35485830325443399 /packages/app
parent1cabeb00d0a391cf83495bf4e3544aa53f155ef4 (diff)
downloadopencode-52eb8a7a8c2ceefa0de8a1a37d5f8754f08cfcff.tar.gz
opencode-52eb8a7a8c2ceefa0de8a1a37d5f8754f08cfcff.zip
feat(app): unread session navigation keybinds (#11750)
Diffstat (limited to 'packages/app')
-rw-r--r--packages/app/src/i18n/ar.ts2
-rw-r--r--packages/app/src/i18n/br.ts2
-rw-r--r--packages/app/src/i18n/da.ts2
-rw-r--r--packages/app/src/i18n/de.ts2
-rw-r--r--packages/app/src/i18n/en.ts2
-rw-r--r--packages/app/src/i18n/es.ts2
-rw-r--r--packages/app/src/i18n/fr.ts2
-rw-r--r--packages/app/src/i18n/ja.ts2
-rw-r--r--packages/app/src/i18n/ko.ts2
-rw-r--r--packages/app/src/i18n/no.ts2
-rw-r--r--packages/app/src/i18n/pl.ts2
-rw-r--r--packages/app/src/i18n/ru.ts2
-rw-r--r--packages/app/src/i18n/th.ts2
-rw-r--r--packages/app/src/i18n/zh.ts2
-rw-r--r--packages/app/src/i18n/zht.ts2
-rw-r--r--packages/app/src/pages/layout.tsx60
16 files changed, 90 insertions, 0 deletions
diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts
index e3831e23c..3718303e5 100644
--- a/packages/app/src/i18n/ar.ts
+++ b/packages/app/src/i18n/ar.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "فتح الإعدادات",
"command.session.previous": "الجلسة السابقة",
"command.session.next": "الجلسة التالية",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "أرشفة الجلسة",
"command.palette": "لوحة الأوامر",
diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts
index f930a66af..43336f8d6 100644
--- a/packages/app/src/i18n/br.ts
+++ b/packages/app/src/i18n/br.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Abrir configurações",
"command.session.previous": "Sessão anterior",
"command.session.next": "Próxima sessão",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Arquivar sessão",
"command.palette": "Paleta de comandos",
diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts
index 2b7d77456..69e8e8114 100644
--- a/packages/app/src/i18n/da.ts
+++ b/packages/app/src/i18n/da.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Åbn indstillinger",
"command.session.previous": "Forrige session",
"command.session.next": "Næste session",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Arkivér session",
"command.palette": "Kommandopalette",
diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts
index 4648ad9c4..1c28e4a16 100644
--- a/packages/app/src/i18n/de.ts
+++ b/packages/app/src/i18n/de.ts
@@ -32,6 +32,8 @@ export const dict = {
"command.settings.open": "Einstellungen öffnen",
"command.session.previous": "Vorherige Sitzung",
"command.session.next": "Nächste Sitzung",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Sitzung archivieren",
"command.palette": "Befehlspalette",
diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts
index 12ddcb4cd..5589337e5 100644
--- a/packages/app/src/i18n/en.ts
+++ b/packages/app/src/i18n/en.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Open settings",
"command.session.previous": "Previous session",
"command.session.next": "Next session",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Archive session",
"command.palette": "Command palette",
diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts
index 5d396f0b4..6e3eac0dd 100644
--- a/packages/app/src/i18n/es.ts
+++ b/packages/app/src/i18n/es.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Abrir ajustes",
"command.session.previous": "Sesión anterior",
"command.session.next": "Siguiente sesión",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Archivar sesión",
"command.palette": "Paleta de comandos",
diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts
index 4226d0c7e..fa3dccd9a 100644
--- a/packages/app/src/i18n/fr.ts
+++ b/packages/app/src/i18n/fr.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Ouvrir les paramètres",
"command.session.previous": "Session précédente",
"command.session.next": "Session suivante",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Archiver la session",
"command.palette": "Palette de commandes",
diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts
index 28a925a0d..4fccbd77e 100644
--- a/packages/app/src/i18n/ja.ts
+++ b/packages/app/src/i18n/ja.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "設定を開く",
"command.session.previous": "前のセッション",
"command.session.next": "次のセッション",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "セッションをアーカイブ",
"command.palette": "コマンドパレット",
diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts
index 1be4e1eb4..5b5d29c0e 100644
--- a/packages/app/src/i18n/ko.ts
+++ b/packages/app/src/i18n/ko.ts
@@ -32,6 +32,8 @@ export const dict = {
"command.settings.open": "설정 열기",
"command.session.previous": "이전 세션",
"command.session.next": "다음 세션",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "세션 보관",
"command.palette": "명령 팔레트",
diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts
index 0a3b39885..89614ce85 100644
--- a/packages/app/src/i18n/no.ts
+++ b/packages/app/src/i18n/no.ts
@@ -31,6 +31,8 @@ export const dict = {
"command.settings.open": "Åpne innstillinger",
"command.session.previous": "Forrige sesjon",
"command.session.next": "Neste sesjon",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Arkiver sesjon",
"command.palette": "Kommandopalett",
diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts
index f4457c6ac..b89921a9b 100644
--- a/packages/app/src/i18n/pl.ts
+++ b/packages/app/src/i18n/pl.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Otwórz ustawienia",
"command.session.previous": "Poprzednia sesja",
"command.session.next": "Następna sesja",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Zarchiwizuj sesję",
"command.palette": "Paleta poleceń",
diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts
index d5a4014d3..e99abbd08 100644
--- a/packages/app/src/i18n/ru.ts
+++ b/packages/app/src/i18n/ru.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "Открыть настройки",
"command.session.previous": "Предыдущая сессия",
"command.session.next": "Следующая сессия",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "Архивировать сессию",
"command.palette": "Палитра команд",
diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts
index 1914b8e5b..0da6f9acc 100644
--- a/packages/app/src/i18n/th.ts
+++ b/packages/app/src/i18n/th.ts
@@ -28,6 +28,8 @@ export const dict = {
"command.settings.open": "เปิดการตั้งค่า",
"command.session.previous": "เซสชันก่อนหน้า",
"command.session.next": "เซสชันถัดไป",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "จัดเก็บเซสชัน",
"command.palette": "คำสั่งค้นหา",
diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts
index b9d539573..a7e1659ec 100644
--- a/packages/app/src/i18n/zh.ts
+++ b/packages/app/src/i18n/zh.ts
@@ -32,6 +32,8 @@ export const dict = {
"command.settings.open": "打开设置",
"command.session.previous": "上一个会话",
"command.session.next": "下一个会话",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "归档会话",
"command.palette": "命令面板",
diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts
index 23d3d80e1..7b8849b9a 100644
--- a/packages/app/src/i18n/zht.ts
+++ b/packages/app/src/i18n/zht.ts
@@ -32,6 +32,8 @@ export const dict = {
"command.settings.open": "開啟設定",
"command.session.previous": "上一個工作階段",
"command.session.next": "下一個工作階段",
+ "command.session.previous.unseen": "Previous unread session",
+ "command.session.next.unseen": "Next unread session",
"command.session.archive": "封存工作階段",
"command.palette": "命令面板",
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
index 845a4fc83..a970bf667 100644
--- a/packages/app/src/pages/layout.tsx
+++ b/packages/app/src/pages/layout.tsx
@@ -886,6 +886,52 @@ export default function Layout(props: ParentProps) {
queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
}
+ function navigateSessionByUnseen(offset: number) {
+ const sessions = currentSessions()
+ if (sessions.length === 0) return
+
+ const hasUnseen = sessions.some((session) => notification.session.unseen(session.id).length > 0)
+ if (!hasUnseen) return
+
+ const activeIndex = params.id ? sessions.findIndex((s) => s.id === params.id) : -1
+ const start = activeIndex === -1 ? (offset > 0 ? -1 : 0) : activeIndex
+
+ for (let i = 1; i <= sessions.length; i++) {
+ const index = offset > 0 ? (start + i) % sessions.length : (start - i + sessions.length) % sessions.length
+ const session = sessions[index]
+ if (!session) continue
+ if (notification.session.unseen(session.id).length === 0) continue
+
+ prefetchSession(session, "high")
+
+ const next = sessions[(index + 1) % sessions.length]
+ const prev = sessions[(index - 1 + sessions.length) % sessions.length]
+
+ if (offset > 0) {
+ if (next) prefetchSession(next, "high")
+ if (prev) prefetchSession(prev)
+ }
+
+ if (offset < 0) {
+ if (prev) prefetchSession(prev, "high")
+ if (next) prefetchSession(next)
+ }
+
+ if (import.meta.env.DEV) {
+ navStart({
+ dir: base64Encode(session.directory),
+ from: params.id,
+ to: session.id,
+ trigger: offset > 0 ? "shift+alt+arrowdown" : "shift+alt+arrowup",
+ })
+ }
+
+ navigateToSession(session)
+ queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
+ return
+ }
+ }
+
async function archiveSession(session: Session) {
const [store, setStore] = globalSync.child(session.directory)
const sessions = store.session ?? []
@@ -1025,6 +1071,20 @@ export default function Layout(props: ParentProps) {
onSelect: () => navigateSessionByOffset(1),
},
{
+ id: "session.previous.unseen",
+ title: language.t("command.session.previous.unseen"),
+ category: language.t("command.category.session"),
+ keybind: "shift+alt+arrowup",
+ onSelect: () => navigateSessionByUnseen(-1),
+ },
+ {
+ id: "session.next.unseen",
+ title: language.t("command.session.next.unseen"),
+ category: language.t("command.category.session"),
+ keybind: "shift+alt+arrowdown",
+ onSelect: () => navigateSessionByUnseen(1),
+ },
+ {
id: "session.archive",
title: language.t("command.session.archive"),
category: language.t("command.category.session"),