paseo-kanban 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OVERVIEW.md +35 -0
- package/README.md +22 -50
- package/README.zh-CN.md +21 -51
- package/client/i18n.tsx +61 -11
- package/client/kanban-board.tsx +103 -29
- package/client/kanban-card.tsx +120 -38
- package/client/kanban-drag.ts +34 -33
- package/client/kanban-lane.tsx +27 -8
- package/client/kanban-session.ts +121 -27
- package/client/kanban-workspace-panel.tsx +13 -0
- package/client/lane-modal.tsx +29 -6
- package/client/task-modal.tsx +20 -1
- package/index.client.tsx +28 -16
- package/package.json +3 -1
- package/shared/kanban.ts +237 -61
package/OVERVIEW.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Kanban
|
|
2
|
+
|
|
3
|
+
A lightweight, responsive Kanban board plugin for Paseo workspaces.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Flexible swimlanes**: Add, delete, and rename lanes.
|
|
8
|
+
- **Rich task cards**: Edit task titles and multi-line descriptions, manage subtask checklists, and link tasks to Paseo projects.
|
|
9
|
+
- **Task completion**: Check a card or drag it into the completion lane to finish; uncheck or drag out to restore.
|
|
10
|
+
- **Workspace tabs and splits**: Open the board beside an agent or terminal with Paseo's native split controls, initially filtered to the workspace's project, or use the sidebar entry.
|
|
11
|
+
- **Smooth drag and drop**: Support intra-lane reordering and cross-lane movement.
|
|
12
|
+
|
|
13
|
+
## Storage and requirements
|
|
14
|
+
|
|
15
|
+
- **Data and privacy**: Board data is stored locally in host-scoped plugin settings with revision checks for concurrent edits. No accounts, tokens, or external network requests are required.
|
|
16
|
+
- **Host requirement**: Paseo 0.8.0 or later.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# 看板 (Kanban)
|
|
21
|
+
|
|
22
|
+
专为 Paseo 工作区打造的轻量响应式看板插件。
|
|
23
|
+
|
|
24
|
+
## 核心功能
|
|
25
|
+
|
|
26
|
+
- **灵活的泳道管理**:支持泳道增删与改名。
|
|
27
|
+
- **丰富的任务卡片**:支持任务标题与多行描述编辑、子步骤清单管理,以及关联 Paseo 项目。
|
|
28
|
+
- **任务完成与恢复**:通过卡片勾选或拖入完成泳道标记完成;取消勾选或拖出即可恢复。
|
|
29
|
+
- **工作区标签页与分屏**:支持通过 Paseo 原生分屏控件与 Agent、Terminal 并排打开,默认筛选工作区所属项目,或使用侧边栏入口。
|
|
30
|
+
- **流畅拖拽交互**:支持同泳道排序与跨泳道状态流转。
|
|
31
|
+
|
|
32
|
+
## 存储与要求
|
|
33
|
+
|
|
34
|
+
- **数据与隐私**:看板数据保存在宿主本地插件设置中,具备版本并发冲突保护(CAS)。无需账号、Token 或任何外部网络请求。
|
|
35
|
+
- **宿主要求**:Paseo 0.8.0 或更高版本。
|
package/README.md
CHANGED
|
@@ -2,27 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) workspaces.
|
|
5
|
+
A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) workspaces.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Flexible Swimlanes**:
|
|
11
|
+
- **Flexible Swimlanes**: Add, delete, and rename lanes.
|
|
12
12
|
- **Rich Task Cards**:
|
|
13
|
-
- Task title and multi-line
|
|
14
|
-
- Subtasks checklist
|
|
15
|
-
-
|
|
16
|
-
- **
|
|
17
|
-
- **Smooth Drag-and-Drop**:
|
|
18
|
-
- **Versioned State Persistence**: Persists board data through Paseo's settings API with optimistic concurrency control (CAS) to prevent race conditions and accidental overwrites.
|
|
13
|
+
- Task title and multi-line description editing.
|
|
14
|
+
- Subtasks checklist.
|
|
15
|
+
- Support linking tasks to projects created in Paseo.
|
|
16
|
+
- **Workspace Tabs and Splits**: Open the board beside an agent or terminal, initially filtered to the workspace's project, or use the sidebar entry.
|
|
17
|
+
- **Smooth Drag-and-Drop**: Support intra-lane reordering and cross-lane movement.
|
|
19
18
|
|
|
20
19
|
---
|
|
21
20
|
|
|
22
21
|
## Requirements
|
|
23
22
|
|
|
24
|
-
- **Paseo
|
|
25
|
-
- **Development
|
|
23
|
+
- **Paseo host**: `>= 0.8.0` (declared in `paseo-plugin.json`). The host runs the plugin.
|
|
24
|
+
- **Development and CI**: Node.js 24 (pinned in `.nvmrc` and `.node-version`) for checks, TypeScript stripping, and native tests.
|
|
26
25
|
|
|
27
26
|
---
|
|
28
27
|
|
|
@@ -30,7 +29,7 @@ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) work
|
|
|
30
29
|
|
|
31
30
|
### Quick Install (Recommended)
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
Install directly from npm or GitHub:
|
|
34
33
|
|
|
35
34
|
**Via NPM (Release package):**
|
|
36
35
|
|
|
@@ -56,7 +55,10 @@ Verify that the plugin is running:
|
|
|
56
55
|
paseo plugin ls
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
Open the board from either entry:
|
|
59
|
+
|
|
60
|
+
- **Sidebar → Kanban**: shows all tasks by default.
|
|
61
|
+
- **Workspace → `+` → Kanban**: initially filters to the workspace's project, with other filters available; use Paseo's native split controls to place it beside an agent or terminal.
|
|
60
62
|
|
|
61
63
|
### Local Development
|
|
62
64
|
|
|
@@ -66,7 +68,7 @@ To contribute or debug locally:
|
|
|
66
68
|
# 1. Clone repository and install dependencies
|
|
67
69
|
git clone https://github.com/breathi3552/paseo-kanban.git
|
|
68
70
|
cd paseo-kanban
|
|
69
|
-
npm
|
|
71
|
+
npm ci
|
|
70
72
|
|
|
71
73
|
# 2. Link this directory into your local Paseo daemon
|
|
72
74
|
paseo plugin link .
|
|
@@ -76,56 +78,26 @@ paseo plugin link .
|
|
|
76
78
|
|
|
77
79
|
## Development & Testing
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
Install dependencies and run the full quality check:
|
|
80
82
|
|
|
81
83
|
```bash
|
|
82
|
-
npm install
|
|
83
|
-
# or clean install:
|
|
84
84
|
npm ci
|
|
85
|
+
npm run check
|
|
85
86
|
```
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
Individual commands (`npm test`, `npm run typecheck`, `npm run lint`, `npm run format:check`, `npm run check:package`) are defined in [`package.json`](./package.json). For tag-based publishing, release sources of truth, recovery, and host acceptance, see the [development guide](./docs/development.md#21-标签发布github-actions).
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
---
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
npm run check
|
|
93
|
-
```
|
|
92
|
+
## Releases
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **Package Verification**: Validates release package contents, entrypoints, and TypeScript AST relative imports:
|
|
98
|
-
```bash
|
|
99
|
-
npm run check:package
|
|
100
|
-
```
|
|
101
|
-
- **Run Tests**: Cross-platform auto-discovery of all `test/*.test.mjs` suites:
|
|
102
|
-
```bash
|
|
103
|
-
npm test
|
|
104
|
-
```
|
|
105
|
-
- **Type Checking**: Validates TypeScript types across client and server entry points:
|
|
106
|
-
```bash
|
|
107
|
-
npm run typecheck
|
|
108
|
-
```
|
|
109
|
-
- **Linting**: Static code analysis with ESLint:
|
|
110
|
-
```bash
|
|
111
|
-
npm run lint
|
|
112
|
-
```
|
|
113
|
-
- **Formatting**: Check or format code style with Prettier:
|
|
114
|
-
```bash
|
|
115
|
-
npm run format:check
|
|
116
|
-
npm run format
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Maintainers can publish a new GitHub Release and npm package in one run of the **Release to GitHub and npm** GitHub Action: select `patch`, `minor`, or `major`. Configure `NPM_TOKEN` and repository write permissions first. For setup, recovery, and manual host acceptance, see the [Development & Acceptance Guide](./docs/development.md#24-一键发布github-actions).
|
|
94
|
+
See the [0.1.4 release notes](./docs/releases/0.1.4.md). Each release's npm package and GitHub Release share the same version tag; GitHub includes the verified npm tarball. `main` may contain changes beyond the latest release.
|
|
120
95
|
|
|
121
96
|
---
|
|
122
97
|
|
|
123
98
|
## Architecture & Design
|
|
124
99
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- **Interactive Architecture Viewer**: Open [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) in your browser.
|
|
128
|
-
- **Architecture Schema & Model**: [`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json).
|
|
100
|
+
Core terminology and design decisions are documented in [`GLOSSARY.md`](./GLOSSARY.md) and [`docs/adr/`](./docs/adr/).
|
|
129
101
|
|
|
130
102
|
---
|
|
131
103
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,27 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
[English](./README.md)
|
|
4
4
|
|
|
5
|
-
专为 [Paseo](https://paseo.sh)
|
|
5
|
+
专为 [Paseo](https://paseo.sh) 工作区打造的轻量响应式看板插件。
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## 核心功能
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- **灵活的泳道管理**:支持泳道增删与改名。
|
|
12
12
|
- **丰富的任务卡片**:
|
|
13
13
|
- 任务标题与多行描述编辑。
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **版本化数据持久化**:基于 Paseo 原生 settings API 存储,内置乐观并发版本控制(CAS),杜绝多会话覆写与状态不一致。
|
|
14
|
+
- 子步骤清单。
|
|
15
|
+
- 支持关联 Paseo 中创建的项目。
|
|
16
|
+
- **工作区标签页与分屏**:与 Agent、Terminal 并排打开看板,默认筛选工作区所属项目;或使用侧边栏入口。
|
|
17
|
+
- **流畅拖拽交互**:支持同泳道排序与跨泳道状态流转。
|
|
19
18
|
|
|
20
19
|
---
|
|
21
20
|
|
|
22
21
|
## 环境要求
|
|
23
22
|
|
|
24
|
-
- **Paseo
|
|
25
|
-
- **开发与 CI
|
|
23
|
+
- **Paseo 宿主**:`>= 0.8.0`(声明于 `paseo-plugin.json`),由 Paseo 运行插件。
|
|
24
|
+
- **开发与 CI**:使用 Node.js 24(声明于 `.nvmrc` 与 `.node-version`)执行质量检查、TypeScript 类型擦除和原生测试。
|
|
26
25
|
|
|
27
26
|
---
|
|
28
27
|
|
|
@@ -30,7 +29,7 @@
|
|
|
30
29
|
|
|
31
30
|
### 快速安装(推荐)
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
通过 Paseo CLI 从 npm 或 GitHub 安装:
|
|
34
33
|
|
|
35
34
|
**方式一:通过 NPM 官方包安装(推荐)**
|
|
36
35
|
|
|
@@ -56,7 +55,10 @@ paseo plugin add breathi3552/paseo-kanban --ref main
|
|
|
56
55
|
paseo plugin ls
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
可从两个入口打开看板:
|
|
59
|
+
|
|
60
|
+
- **侧边栏 → 看板**:默认展示全部任务。
|
|
61
|
+
- **工作区 → `+` → 看板**:默认筛选工作区所属项目,可切换范围;使用 Paseo 原生分屏操作与 Agent、Terminal 等并排显示。
|
|
60
62
|
|
|
61
63
|
### 本地开发与调试
|
|
62
64
|
|
|
@@ -66,7 +68,7 @@ paseo plugin ls
|
|
|
66
68
|
# 1. 克隆代码仓库并安装依赖
|
|
67
69
|
git clone https://github.com/breathi3552/paseo-kanban.git
|
|
68
70
|
cd paseo-kanban
|
|
69
|
-
npm
|
|
71
|
+
npm ci
|
|
70
72
|
|
|
71
73
|
# 2. 将当前开发目录软链接至本地 Paseo 守护进程
|
|
72
74
|
paseo plugin link .
|
|
@@ -76,58 +78,26 @@ paseo plugin link .
|
|
|
76
78
|
|
|
77
79
|
## 开发与测试
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
安装依赖并运行完整检查:
|
|
80
82
|
|
|
81
83
|
```bash
|
|
82
|
-
npm install
|
|
83
|
-
# 或干净安装验证:
|
|
84
84
|
npm ci
|
|
85
|
+
npm run check
|
|
85
86
|
```
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
单项命令(`npm test`、`npm run typecheck`、`npm run lint`、`npm run format:check`、`npm run check:package`)见 [`package.json`](./package.json)。标签发布、事实来源、失败重试与宿主验收见[开发指南](./docs/development.md#21-标签发布github-actions)。
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
---
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
npm run check
|
|
93
|
-
```
|
|
92
|
+
## 版本发布
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **发布包完整性检查**:静态校验发布包产物清单、入口完整性与 TypeScript AST 相对导入闭包:
|
|
98
|
-
```bash
|
|
99
|
-
npm run check:package
|
|
100
|
-
```
|
|
101
|
-
- **运行单元测试**:跨平台自动发现并执行所有 `test/*.test.mjs` 测试套件:
|
|
102
|
-
```bash
|
|
103
|
-
npm test
|
|
104
|
-
```
|
|
105
|
-
- **类型检查**:校验前端组件与服务端扩展的 TypeScript 类型完整性:
|
|
106
|
-
```bash
|
|
107
|
-
npm run typecheck
|
|
108
|
-
```
|
|
109
|
-
- **代码规范检查 (Lint)**:基于 ESLint 开展轻量静态检查:
|
|
110
|
-
```bash
|
|
111
|
-
npm run lint
|
|
112
|
-
```
|
|
113
|
-
- **代码格式检查与格式化 (Format)**:基于 Prettier 校验或自动格式化:
|
|
114
|
-
```bash
|
|
115
|
-
npm run format:check
|
|
116
|
-
npm run format
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
维护者可在 GitHub Actions 的 **Release to GitHub and npm** 工作流中选择 `patch` / `minor` / `major` 一键发布 GitHub Release 与 npm 包;首次使用需配置 `NPM_TOKEN` 和仓库写入权限。操作及失败重试说明见 [开发与宿主验收指南](./docs/development.md#24-一键发布github-actions)。
|
|
120
|
-
|
|
121
|
-
详细开发贡献流程、发布前检查机制与真实宿主环境手工验收指南,请参阅 [开发与宿主验收指南](./docs/development.md)。
|
|
94
|
+
参见 [0.1.4 版本说明](./docs/releases/0.1.4.md)。每版 npm 包与 GitHub Release 对应同一个版本 tag,GitHub 附带经过验证的 npm tarball。`main` 可能包含最新发布版之后的改动。
|
|
122
95
|
|
|
123
96
|
---
|
|
124
97
|
|
|
125
98
|
## 架构设计
|
|
126
99
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- **交互式架构全景图**:直接使用浏览器打开 [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) 查看。
|
|
130
|
-
- **架构定义元数据**:[`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json)。
|
|
100
|
+
核心术语和架构决策见 [`GLOSSARY.md`](./GLOSSARY.md) 与 [`docs/adr/`](./docs/adr/)。
|
|
131
101
|
|
|
132
102
|
---
|
|
133
103
|
|
package/client/i18n.tsx
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { useState, useEffect, useMemo } from "react";
|
|
1
|
+
import { useState, useEffect, useMemo, createContext, useContext } from "react";
|
|
2
2
|
|
|
3
3
|
export type SupportedLanguage = "zh" | "en";
|
|
4
4
|
|
|
5
|
+
export const I18nLanguageContext = createContext<SupportedLanguage | null>(
|
|
6
|
+
null,
|
|
7
|
+
);
|
|
8
|
+
|
|
5
9
|
export type TranslationParams = Record<
|
|
6
10
|
string,
|
|
7
11
|
string | number | boolean | null | undefined
|
|
@@ -9,6 +13,19 @@ export type TranslationParams = Record<
|
|
|
9
13
|
|
|
10
14
|
export const translations = {
|
|
11
15
|
zh: {
|
|
16
|
+
"notification.taskCreated": "任务已创建",
|
|
17
|
+
"notification.taskUpdated": "任务已更新",
|
|
18
|
+
"notification.taskDeleted": "任务已删除",
|
|
19
|
+
"notification.laneCreated": "泳道已创建",
|
|
20
|
+
"notification.laneRenamed": "泳道已重命名",
|
|
21
|
+
"notification.laneDeleted": "泳道已删除",
|
|
22
|
+
"notification.taskSaveFailed": "任务保存失败,草稿已保留,请核实最新数据。",
|
|
23
|
+
"notification.taskDeleteFailed": "任务删除失败,请核实最新数据。",
|
|
24
|
+
"notification.laneSaveFailed": "泳道保存失败,草稿已保留,请核实最新数据。",
|
|
25
|
+
"notification.laneDeleteFailed": "泳道删除失败,请核实最新数据。",
|
|
26
|
+
"notification.taskReorderFailed": "任务移动失败,请刷新最新数据后重试。",
|
|
27
|
+
"notification.taskCompletionFailed":
|
|
28
|
+
"任务完成状态保存失败,请核实最新状态。",
|
|
12
29
|
"kanban.sidebarTitle": "看板",
|
|
13
30
|
"kanban.title": "任务看板",
|
|
14
31
|
"kanban.loading": "正在加载看板数据...",
|
|
@@ -31,13 +48,18 @@ export const translations = {
|
|
|
31
48
|
"lane.add": "+ 添加",
|
|
32
49
|
"lane.manage": "管理",
|
|
33
50
|
"lane.emptyHint": "暂无卡片,可点击右上角添加或拖动卡片至此",
|
|
51
|
+
"lane.emptyCompletionHint": "暂无已完成任务,可勾选任务或将卡片拖入此泳道",
|
|
52
|
+
"card.completeTask": "完成任务:{title}",
|
|
53
|
+
"card.reopenTask": "取消完成:{title}",
|
|
34
54
|
"card.dragHandle": "拖动手柄",
|
|
35
55
|
"card.subtasksCount": "子步骤 {completed}/{total}",
|
|
36
56
|
"laneModal.titleEdit": "管理泳道",
|
|
37
57
|
"laneModal.titleCreate": "新增泳道",
|
|
38
58
|
"laneModal.nameLabel": "泳道名称 *",
|
|
39
59
|
"laneModal.namePlaceholder": "例如:待测试、发布中...",
|
|
40
|
-
"laneModal.cannotDeleteLast":
|
|
60
|
+
"laneModal.cannotDeleteLast":
|
|
61
|
+
"看板必须至少保留一条普通泳道,无法删除此泳道。",
|
|
62
|
+
"laneModal.cannotDeleteCompletion": "完成泳道不可删除,可以修改名称。",
|
|
41
63
|
"laneModal.cannotDeleteHasTasks":
|
|
42
64
|
"此泳道当前包含 {count} 个任务,需清空或移走任务后方可删除。",
|
|
43
65
|
"laneModal.deleteLane": "删除此泳道",
|
|
@@ -69,6 +91,24 @@ export const translations = {
|
|
|
69
91
|
"taskModal.submitCreate": "创建",
|
|
70
92
|
},
|
|
71
93
|
en: {
|
|
94
|
+
"notification.taskCreated": "Task created",
|
|
95
|
+
"notification.taskUpdated": "Task updated",
|
|
96
|
+
"notification.taskDeleted": "Task deleted",
|
|
97
|
+
"notification.laneCreated": "Lane created",
|
|
98
|
+
"notification.laneRenamed": "Lane renamed",
|
|
99
|
+
"notification.laneDeleted": "Lane deleted",
|
|
100
|
+
"notification.taskSaveFailed":
|
|
101
|
+
"Task save failed. Draft preserved; check the latest data.",
|
|
102
|
+
"notification.taskDeleteFailed":
|
|
103
|
+
"Task deletion failed. Check the latest data.",
|
|
104
|
+
"notification.laneSaveFailed":
|
|
105
|
+
"Lane save failed. Draft preserved; check the latest data.",
|
|
106
|
+
"notification.laneDeleteFailed":
|
|
107
|
+
"Lane deletion failed. Check the latest data.",
|
|
108
|
+
"notification.taskReorderFailed":
|
|
109
|
+
"Task move failed. Refresh the latest data and try again.",
|
|
110
|
+
"notification.taskCompletionFailed":
|
|
111
|
+
"Task completion change failed. Check the latest state.",
|
|
72
112
|
"kanban.sidebarTitle": "Kanban",
|
|
73
113
|
"kanban.title": "Task Kanban",
|
|
74
114
|
"kanban.loading": "Loading kanban board data...",
|
|
@@ -92,6 +132,10 @@ export const translations = {
|
|
|
92
132
|
"lane.manage": "Manage",
|
|
93
133
|
"lane.emptyHint":
|
|
94
134
|
"No cards yet. Click '+' in the top right or drag cards here.",
|
|
135
|
+
"lane.emptyCompletionHint":
|
|
136
|
+
"No completed tasks. Check a task or drag it into this lane.",
|
|
137
|
+
"card.completeTask": "Mark {title} complete",
|
|
138
|
+
"card.reopenTask": "Mark {title} incomplete",
|
|
95
139
|
"card.dragHandle": "Drag handle",
|
|
96
140
|
"card.subtasksCount": "Subtasks {completed}/{total}",
|
|
97
141
|
"laneModal.titleEdit": "Manage Lane",
|
|
@@ -99,7 +143,9 @@ export const translations = {
|
|
|
99
143
|
"laneModal.nameLabel": "Lane Name *",
|
|
100
144
|
"laneModal.namePlaceholder": "e.g., Testing, In Review...",
|
|
101
145
|
"laneModal.cannotDeleteLast":
|
|
102
|
-
"A kanban board must retain at least one lane. Cannot delete this lane.",
|
|
146
|
+
"A kanban board must retain at least one ordinary lane. Cannot delete this lane.",
|
|
147
|
+
"laneModal.cannotDeleteCompletion":
|
|
148
|
+
"The completion lane cannot be deleted. You can rename it.",
|
|
103
149
|
"laneModal.cannotDeleteHasTasks":
|
|
104
150
|
"This lane currently contains {count} tasks. Clear or move tasks before deleting.",
|
|
105
151
|
"laneModal.deleteLane": "Delete Lane",
|
|
@@ -172,6 +218,7 @@ interface EnvironmentGlobals {
|
|
|
172
218
|
};
|
|
173
219
|
navigator?: {
|
|
174
220
|
language?: string;
|
|
221
|
+
languages?: readonly string[];
|
|
175
222
|
};
|
|
176
223
|
window?: {
|
|
177
224
|
addEventListener(
|
|
@@ -214,6 +261,12 @@ export function detectPaseoLanguage(
|
|
|
214
261
|
} catch {}
|
|
215
262
|
}
|
|
216
263
|
|
|
264
|
+
// Match Paseo's web system-language source before page/Intl defaults.
|
|
265
|
+
const navLocale = env.navigator?.languages?.[0] || env.navigator?.language;
|
|
266
|
+
if (navLocale) {
|
|
267
|
+
return normalizeLanguage(navLocale);
|
|
268
|
+
}
|
|
269
|
+
|
|
217
270
|
const docLang = env.document?.documentElement?.lang;
|
|
218
271
|
if (docLang) {
|
|
219
272
|
return normalizeLanguage(docLang);
|
|
@@ -232,11 +285,6 @@ export function detectPaseoLanguage(
|
|
|
232
285
|
return normalizeLanguage(intlLocale);
|
|
233
286
|
}
|
|
234
287
|
|
|
235
|
-
const navLocale = env.navigator?.language;
|
|
236
|
-
if (navLocale) {
|
|
237
|
-
return normalizeLanguage(navLocale);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
288
|
return "en";
|
|
241
289
|
}
|
|
242
290
|
|
|
@@ -323,6 +371,7 @@ export interface I18nContextValue {
|
|
|
323
371
|
}
|
|
324
372
|
|
|
325
373
|
export function useI18n(hostProps?: DetectLanguageOptions): I18nContextValue {
|
|
374
|
+
const inheritedLanguage = useContext(I18nLanguageContext);
|
|
326
375
|
const hostLocale =
|
|
327
376
|
hostProps?.locale ??
|
|
328
377
|
hostProps?.language ??
|
|
@@ -341,14 +390,15 @@ export function useI18n(hostProps?: DetectLanguageOptions): I18nContextValue {
|
|
|
341
390
|
});
|
|
342
391
|
}, [hostLocale, hostProps]);
|
|
343
392
|
|
|
393
|
+
const language = hostLocale ? lang : (inheritedLanguage ?? lang);
|
|
344
394
|
const tBound = useMemo(
|
|
345
395
|
() => (key: TranslationKey, params?: TranslationParams) =>
|
|
346
|
-
t(key,
|
|
347
|
-
[
|
|
396
|
+
t(key, language, params),
|
|
397
|
+
[language],
|
|
348
398
|
);
|
|
349
399
|
|
|
350
400
|
return {
|
|
351
|
-
language
|
|
401
|
+
language,
|
|
352
402
|
t: tBound,
|
|
353
403
|
};
|
|
354
404
|
}
|