@skillcdn/console 0.1.9 → 0.1.10
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/README.md +5 -5
- package/dist/api.d.ts +5 -5
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -4
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +255 -10
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts +9 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +80 -0
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +62 -7
- package/dist/cli/help.js.map +1 -1
- package/dist/client.d.ts +31 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +19 -3
- package/dist/client.js.map +1 -1
- package/dist/components/board.d.ts +27 -1
- package/dist/components/board.d.ts.map +1 -1
- package/dist/components/board.js +75 -7
- package/dist/components/board.js.map +1 -1
- package/dist/components/calendar.d.ts +34 -0
- package/dist/components/calendar.d.ts.map +1 -0
- package/dist/components/calendar.js +96 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/categories.d.ts +13 -0
- package/dist/components/categories.d.ts.map +1 -0
- package/dist/components/categories.js +52 -0
- package/dist/components/categories.js.map +1 -0
- package/dist/components/decision-list.d.ts +10 -0
- package/dist/components/decision-list.d.ts.map +1 -1
- package/dist/components/decision-list.js +14 -1
- package/dist/components/decision-list.js.map +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +12 -0
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/goals.d.ts +35 -0
- package/dist/components/goals.d.ts.map +1 -0
- package/dist/components/goals.js +45 -0
- package/dist/components/goals.js.map +1 -0
- package/dist/components/task-form.d.ts +5 -1
- package/dist/components/task-form.d.ts.map +1 -1
- package/dist/components/task-form.js +13 -1
- package/dist/components/task-form.js.map +1 -1
- package/dist/components/task-list.d.ts +16 -0
- package/dist/components/task-list.d.ts.map +1 -0
- package/dist/components/task-list.js +14 -0
- package/dist/components/task-list.js.map +1 -0
- package/dist/components/task-view.d.ts +9 -1
- package/dist/components/task-view.d.ts.map +1 -1
- package/dist/components/task-view.js +10 -4
- package/dist/components/task-view.js.map +1 -1
- package/dist/components/ui.d.ts +30 -1
- package/dist/components/ui.d.ts.map +1 -1
- package/dist/components/ui.js +60 -0
- package/dist/components/ui.js.map +1 -1
- package/dist/components/work.d.ts +10 -0
- package/dist/components/work.d.ts.map +1 -0
- package/dist/components/work.js +29 -0
- package/dist/components/work.js.map +1 -0
- package/dist/console.css +511 -0
- package/dist/console.d.ts +8 -0
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +124 -8
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +14 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +36 -2
- package/dist/data.js.map +1 -1
- package/dist/dates.d.ts +39 -0
- package/dist/dates.d.ts.map +1 -0
- package/dist/dates.js +120 -0
- package/dist/dates.js.map +1 -0
- package/dist/i18n/en.d.ts +162 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +174 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +169 -1
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +5 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +5 -0
- package/dist/limits.js.map +1 -1
- package/dist/router.d.ts +50 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +74 -1
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +7 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +9 -0
- package/dist/routes.js.map +1 -1
- package/dist/schemas.d.ts +366 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +112 -3
- package/dist/schemas.js.map +1 -1
- package/dist/vocabulary.d.ts +15 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +26 -0
- package/dist/vocabulary.js.map +1 -1
- package/docs/specs/cli.md +11 -4
- package/docs/specs/rest.md +33 -8
- package/package.json +1 -1
- package/skills/working-the-board/SKILL.md +7 -6
- package/src/api.ts +30 -0
- package/src/cli/cli.ts +311 -10
- package/src/cli/format.ts +88 -0
- package/src/cli/help.ts +69 -7
- package/src/client.ts +70 -2
- package/src/components/board.tsx +205 -12
- package/src/components/calendar.tsx +255 -0
- package/src/components/categories.tsx +209 -0
- package/src/components/decision-list.tsx +62 -5
- package/src/components/event-feed.tsx +12 -0
- package/src/components/goals.tsx +264 -0
- package/src/components/task-form.tsx +78 -1
- package/src/components/task-list.tsx +61 -0
- package/src/components/task-view.tsx +74 -3
- package/src/components/ui.tsx +116 -1
- package/src/components/work.tsx +83 -0
- package/src/console.tsx +337 -4
- package/src/data.ts +63 -8
- package/src/dates.ts +143 -0
- package/src/i18n/en.ts +184 -1
- package/src/i18n/ko.ts +175 -1
- package/src/index.ts +58 -1
- package/src/limits.ts +5 -0
- package/src/router.ts +119 -6
- package/src/routes.ts +10 -0
- package/src/schemas.ts +141 -1
- package/src/styles/console.css +511 -0
- package/src/vocabulary.ts +33 -0
package/src/dates.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Days, as the plan is made in (ADR-0019): `2026-10-20`, read and written as the strings they
|
|
2
|
+
// are, so that a deadline is the same day wherever the people are. The browser's own clock says
|
|
3
|
+
// which day is today; nothing here looks at it unless asked.
|
|
4
|
+
|
|
5
|
+
const DAY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
6
|
+
|
|
7
|
+
/** Whether a string is a day as the API spells one. */
|
|
8
|
+
export function isDay(value: string | null | undefined): value is string {
|
|
9
|
+
return value !== null && value !== undefined && DAY.test(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A day from a local date: the date the browser's clock shows, not the UTC one. */
|
|
13
|
+
export function dayOf(date: Date): string {
|
|
14
|
+
const year = String(date.getFullYear()).padStart(4, "0");
|
|
15
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
16
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
17
|
+
return `${year}-${month}-${day}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Today, by the browser's clock. */
|
|
21
|
+
export function today(now: Date = new Date()): string {
|
|
22
|
+
return dayOf(now);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A local date at noon of the day, so that a daylight-saving change never moves it a day. */
|
|
26
|
+
export function dateOf(day: string): Date {
|
|
27
|
+
const match = DAY.exec(day);
|
|
28
|
+
if (match === null) {
|
|
29
|
+
return new Date(Number.NaN);
|
|
30
|
+
}
|
|
31
|
+
return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]), 12);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The day `count` days after `day`; negative counts go back. */
|
|
35
|
+
export function addDays(day: string, count: number): string {
|
|
36
|
+
const date = dateOf(day);
|
|
37
|
+
date.setDate(date.getDate() + count);
|
|
38
|
+
return dayOf(date);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** How many days `to` is after `from`; negative when it is before. */
|
|
42
|
+
export function daysBetween(from: string, to: string): number {
|
|
43
|
+
const millis = dateOf(to).getTime() - dateOf(from).getTime();
|
|
44
|
+
return Math.round(millis / 86_400_000);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The month a day is in: `2026-10`. */
|
|
48
|
+
export function monthOf(day: string): string {
|
|
49
|
+
return day.slice(0, 7);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Whether a string is a month as the calendar's address spells one. */
|
|
53
|
+
export function isMonth(value: string | null | undefined): value is string {
|
|
54
|
+
return value !== null && value !== undefined && /^\d{4}-(0[1-9]|1[0-2])$/.test(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The month `count` months after `month`; negative counts go back. */
|
|
58
|
+
export function addMonths(month: string, count: number): string {
|
|
59
|
+
const year = Number(month.slice(0, 4));
|
|
60
|
+
const index = Number(month.slice(5, 7)) - 1 + count;
|
|
61
|
+
const date = new Date(year, index, 1, 12);
|
|
62
|
+
return `${String(date.getFullYear()).padStart(4, "0")}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The weekday a week begins on where the language is spoken: 1 for Monday, 7 for Sunday. */
|
|
66
|
+
export function firstDayOfWeek(language: string): number {
|
|
67
|
+
try {
|
|
68
|
+
const locale = new Intl.Locale(language) as Intl.Locale & {
|
|
69
|
+
readonly weekInfo?: { readonly firstDay: number };
|
|
70
|
+
readonly getWeekInfo?: () => { readonly firstDay: number };
|
|
71
|
+
};
|
|
72
|
+
const info = locale.getWeekInfo?.() ?? locale.weekInfo;
|
|
73
|
+
if (info !== undefined && info.firstDay >= 1 && info.firstDay <= 7) {
|
|
74
|
+
return info.firstDay;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// A tag the browser does not know: the week begins on Monday.
|
|
78
|
+
}
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One cell of a month's grid: the day, and whether it is of the month shown or a neighbour's. */
|
|
83
|
+
export interface GridDay {
|
|
84
|
+
readonly day: string;
|
|
85
|
+
readonly inMonth: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The weeks of a month as a calendar shows them: full weeks, beginning on `firstDay` (1 for
|
|
90
|
+
* Monday, 7 for Sunday), with the neighbouring months' days filling the first and the last.
|
|
91
|
+
*/
|
|
92
|
+
export function monthGrid(month: string, firstDay = 1): GridDay[][] {
|
|
93
|
+
const first = `${month}-01`;
|
|
94
|
+
const start = dateOf(first);
|
|
95
|
+
// getDay: 0 for Sunday; the grid counts Monday as 1 and Sunday as 7.
|
|
96
|
+
const weekday = start.getDay() === 0 ? 7 : start.getDay();
|
|
97
|
+
const back = (weekday - firstDay + 7) % 7;
|
|
98
|
+
let cursor = addDays(first, -back);
|
|
99
|
+
const weeks: GridDay[][] = [];
|
|
100
|
+
do {
|
|
101
|
+
const week: GridDay[] = [];
|
|
102
|
+
for (let column = 0; column < 7; column += 1) {
|
|
103
|
+
week.push({ day: cursor, inMonth: monthOf(cursor) === month });
|
|
104
|
+
cursor = addDays(cursor, 1);
|
|
105
|
+
}
|
|
106
|
+
weeks.push(week);
|
|
107
|
+
} while (monthOf(cursor) === month);
|
|
108
|
+
return weeks;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** The weekdays in the order a week is shown, from `firstDay`, as the grid counts them. */
|
|
112
|
+
export function weekdays(firstDay = 1): number[] {
|
|
113
|
+
return Array.from({ length: 7 }, (_, index) => ((firstDay - 1 + index) % 7) + 1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** A day as people read one in a language: the month and the day, with the year when it is not this year's. */
|
|
117
|
+
export function formatDay(day: string, language?: string, now: Date = new Date()): string {
|
|
118
|
+
const date = dateOf(day);
|
|
119
|
+
if (Number.isNaN(date.getTime())) {
|
|
120
|
+
return day;
|
|
121
|
+
}
|
|
122
|
+
return date.toLocaleDateString(language, {
|
|
123
|
+
month: "short",
|
|
124
|
+
day: "numeric",
|
|
125
|
+
...(date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" }),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** A month as people read one: the month and the year. */
|
|
130
|
+
export function formatMonth(month: string, language?: string): string {
|
|
131
|
+
const date = dateOf(`${month}-01`);
|
|
132
|
+
if (Number.isNaN(date.getTime())) {
|
|
133
|
+
return month;
|
|
134
|
+
}
|
|
135
|
+
return date.toLocaleDateString(language, { month: "long", year: "numeric" });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** A weekday as people read one, short, as the grid counts them: 1 for Monday, 7 for Sunday. */
|
|
139
|
+
export function formatWeekday(weekday: number, language?: string): string {
|
|
140
|
+
// The week of 2024-01-01 began on a Monday.
|
|
141
|
+
const date = new Date(2024, 0, weekday, 12);
|
|
142
|
+
return date.toLocaleDateString(language, { weekday: "short" });
|
|
143
|
+
}
|
package/src/i18n/en.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { SignInFailure } from "../routes.js";
|
|
2
2
|
import type {
|
|
3
|
+
CategoryColor,
|
|
4
|
+
GoalState,
|
|
3
5
|
PersonRole,
|
|
4
6
|
ProjectRole,
|
|
5
7
|
ProjectVisibility,
|
|
@@ -47,6 +49,22 @@ export const en = {
|
|
|
47
49
|
failed: "Failed",
|
|
48
50
|
abandoned: "Abandoned",
|
|
49
51
|
} satisfies Record<RunStatus, string>,
|
|
52
|
+
goalState: {
|
|
53
|
+
planned: "Planned",
|
|
54
|
+
active: "Active",
|
|
55
|
+
done: "Reached",
|
|
56
|
+
dropped: "Dropped",
|
|
57
|
+
} satisfies Record<GoalState, string>,
|
|
58
|
+
categoryColor: {
|
|
59
|
+
gray: "Gray",
|
|
60
|
+
blue: "Blue",
|
|
61
|
+
green: "Green",
|
|
62
|
+
orange: "Orange",
|
|
63
|
+
pink: "Pink",
|
|
64
|
+
purple: "Purple",
|
|
65
|
+
teal: "Teal",
|
|
66
|
+
yellow: "Yellow",
|
|
67
|
+
} satisfies Record<CategoryColor, string>,
|
|
50
68
|
},
|
|
51
69
|
|
|
52
70
|
common: {
|
|
@@ -81,9 +99,13 @@ export const en = {
|
|
|
81
99
|
|
|
82
100
|
nav: {
|
|
83
101
|
projects: "Projects",
|
|
102
|
+
work: "My work",
|
|
84
103
|
people: "People",
|
|
85
104
|
agents: "Agents",
|
|
105
|
+
categories: "Categories",
|
|
86
106
|
board: "Board",
|
|
107
|
+
roadmap: "Roadmap",
|
|
108
|
+
calendar: "Calendar",
|
|
87
109
|
docs: "Docs",
|
|
88
110
|
decisions: "Decisions",
|
|
89
111
|
feed: "Feed",
|
|
@@ -187,7 +209,25 @@ export const en = {
|
|
|
187
209
|
decisionsTitle: "Decisions waiting for a person",
|
|
188
210
|
agentAtWork: "agent at work",
|
|
189
211
|
agentAtWorkTitle: "An agent is at work on it",
|
|
190
|
-
|
|
212
|
+
agentSince: (agent: string, since: string) => `${agent}, at work since ${since}`,
|
|
213
|
+
filters: {
|
|
214
|
+
aria: "Narrow the board",
|
|
215
|
+
everyone: "Everyone",
|
|
216
|
+
mine: "Mine",
|
|
217
|
+
anyCategory: "Any category",
|
|
218
|
+
noCategory: "No category",
|
|
219
|
+
anyGoal: "Any goal",
|
|
220
|
+
noGoal: "No goal",
|
|
221
|
+
clear: "Show everything",
|
|
222
|
+
showing: (n: number, of: number) => `${n} of ${count(of, "task", "tasks")}`,
|
|
223
|
+
},
|
|
224
|
+
due: {
|
|
225
|
+
overdue: (days: number) => `${count(days, "day", "days")} overdue`,
|
|
226
|
+
today: "Due today",
|
|
227
|
+
tomorrow: "Due tomorrow",
|
|
228
|
+
inDays: (days: number) => `Due in ${count(days, "day", "days")}`,
|
|
229
|
+
on: (day: string) => `Due ${day}`,
|
|
230
|
+
},
|
|
191
231
|
},
|
|
192
232
|
|
|
193
233
|
task: {
|
|
@@ -213,6 +253,19 @@ export const en = {
|
|
|
213
253
|
history: "What happened",
|
|
214
254
|
subtasks: "Subtasks",
|
|
215
255
|
partOfIt: "Part of it",
|
|
256
|
+
category: "Category",
|
|
257
|
+
goal: "Goal",
|
|
258
|
+
plan: "Plan",
|
|
259
|
+
planned: (from: string | undefined, to: string | undefined) =>
|
|
260
|
+
from !== undefined && to !== undefined
|
|
261
|
+
? `${from} to ${to}`
|
|
262
|
+
: from !== undefined
|
|
263
|
+
? `from ${from}`
|
|
264
|
+
: to !== undefined
|
|
265
|
+
? `by ${to}`
|
|
266
|
+
: "",
|
|
267
|
+
started: "Started",
|
|
268
|
+
done: "Done",
|
|
216
269
|
form: {
|
|
217
270
|
title: "Title",
|
|
218
271
|
body: "Body",
|
|
@@ -221,6 +274,12 @@ export const en = {
|
|
|
221
274
|
priority: "Priority",
|
|
222
275
|
assignee: "Assignee",
|
|
223
276
|
partOf: "Part of",
|
|
277
|
+
category: "Category",
|
|
278
|
+
noCategory: "No category",
|
|
279
|
+
goal: "Goal",
|
|
280
|
+
noGoal: "No goal",
|
|
281
|
+
startsOn: "Starts on",
|
|
282
|
+
dueOn: "Due on",
|
|
224
283
|
links: "Links",
|
|
225
284
|
label: "Label",
|
|
226
285
|
addLink: "Add a link",
|
|
@@ -244,6 +303,10 @@ export const en = {
|
|
|
244
303
|
},
|
|
245
304
|
waiting: "Waiting",
|
|
246
305
|
answered: "Answered",
|
|
306
|
+
record: "The record",
|
|
307
|
+
recordLead:
|
|
308
|
+
"Every decision answered, newest first: what was asked, what was chosen, by whom. Open one for its context, its rationale and what followed.",
|
|
309
|
+
openRecord: "Open",
|
|
247
310
|
waitingForPerson: "Waiting for a person.",
|
|
248
311
|
options: "Options",
|
|
249
312
|
notePlaceholder: "A word about it, if any",
|
|
@@ -271,6 +334,112 @@ export const en = {
|
|
|
271
334
|
},
|
|
272
335
|
},
|
|
273
336
|
|
|
337
|
+
calendar: {
|
|
338
|
+
title: "Calendar",
|
|
339
|
+
lead: "The tasks by the day they are due. A task with a start is shown from it; one with no day waits at the bottom to be given one.",
|
|
340
|
+
grid: "The month",
|
|
341
|
+
previous: "The month before",
|
|
342
|
+
next: "The month after",
|
|
343
|
+
thisMonth: "This month",
|
|
344
|
+
nothingDue: "Nothing is due this month.",
|
|
345
|
+
overdue: "Overdue",
|
|
346
|
+
nothingOverdue: "Nothing is overdue.",
|
|
347
|
+
unscheduled: "No day set",
|
|
348
|
+
allScheduled: "Every open task has a day.",
|
|
349
|
+
starts: "starts",
|
|
350
|
+
workload: {
|
|
351
|
+
title: "Who has what",
|
|
352
|
+
lead: "The open tasks of each person, and what of them is late or due within the week.",
|
|
353
|
+
person: "Person",
|
|
354
|
+
open: "Open",
|
|
355
|
+
inProgress: "In progress",
|
|
356
|
+
dueSoon: "Due in 7 days",
|
|
357
|
+
overdue: "Overdue",
|
|
358
|
+
unassigned: "Nobody's yet",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
roadmap: {
|
|
363
|
+
title: "Roadmap",
|
|
364
|
+
lead: "What the project works towards: each goal with the day it is meant to be reached by, and how far its tasks are. Progress is read from the board as it stands.",
|
|
365
|
+
setGoal: "Set a goal",
|
|
366
|
+
setGoalAria: "Set a goal",
|
|
367
|
+
editAria: "Change the goal",
|
|
368
|
+
one: "Goal",
|
|
369
|
+
all: "All goals",
|
|
370
|
+
empty: {
|
|
371
|
+
title: "No goal is set yet",
|
|
372
|
+
body: "An owner sets the first one: what to reach, and by when. Tasks are then written towards it.",
|
|
373
|
+
},
|
|
374
|
+
noSuch: {
|
|
375
|
+
title: "No such goal",
|
|
376
|
+
body: "It may belong to another project, or the link is wrong.",
|
|
377
|
+
},
|
|
378
|
+
onlyOwner: {
|
|
379
|
+
title: "Only an owner sets the roadmap",
|
|
380
|
+
body: "Ask one of the project's owners, or a workspace administrator.",
|
|
381
|
+
},
|
|
382
|
+
progress: (done: number, of: number) => `${done} of ${count(of, "task", "tasks")} done`,
|
|
383
|
+
inProgress: (n: number) => `${n} in progress`,
|
|
384
|
+
noTasks: "No task works towards it yet.",
|
|
385
|
+
tasks: "Tasks",
|
|
386
|
+
target: "Target",
|
|
387
|
+
noTarget: "No target day",
|
|
388
|
+
setBy: "Set by",
|
|
389
|
+
state: "State",
|
|
390
|
+
nothingMore: "Nothing more was written about it.",
|
|
391
|
+
form: {
|
|
392
|
+
title: "Title",
|
|
393
|
+
body: "What reaching it means",
|
|
394
|
+
bodyPlaceholder: "What is true once the goal is reached, in Markdown.",
|
|
395
|
+
state: "State",
|
|
396
|
+
dueOn: "Target day",
|
|
397
|
+
set: "Set the goal",
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
work: {
|
|
402
|
+
title: "My work",
|
|
403
|
+
lead: "What is on your plate across your projects: the open tasks assigned to you, by the day they are due, and the decisions that wait for a person.",
|
|
404
|
+
loading: "Loading your work",
|
|
405
|
+
couldNotLoad: "Your work could not be loaded.",
|
|
406
|
+
empty: {
|
|
407
|
+
title: "Nothing is assigned to you",
|
|
408
|
+
body: "A task assigned to you in any project you may see shows up here.",
|
|
409
|
+
},
|
|
410
|
+
overdue: "Overdue",
|
|
411
|
+
thisWeek: "Due this week",
|
|
412
|
+
later: "Later",
|
|
413
|
+
noDay: "No day set",
|
|
414
|
+
decisions: "Decisions waiting for a person",
|
|
415
|
+
noDecisions: "No decision waits.",
|
|
416
|
+
inProject: (project: string) => `in ${project}`,
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
categories: {
|
|
420
|
+
title: "Categories",
|
|
421
|
+
lead: "The kinds of work tasks are sorted into, the same in every project. A task carries one, the board is narrowed by one, and an administrator keeps the list.",
|
|
422
|
+
onlyAdmin: "An administrator adds, changes and removes them; everyone else reads them here.",
|
|
423
|
+
list: "Categories",
|
|
424
|
+
add: "Add a category",
|
|
425
|
+
addAria: "Add a category",
|
|
426
|
+
empty: {
|
|
427
|
+
title: "No categories",
|
|
428
|
+
body: "An administrator adds the first one here.",
|
|
429
|
+
},
|
|
430
|
+
inUse: "A category tasks are sorted into cannot be removed until they are moved out of it.",
|
|
431
|
+
form: {
|
|
432
|
+
name: "Name",
|
|
433
|
+
key: "Key",
|
|
434
|
+
keyHint:
|
|
435
|
+
"Lowercase letters, digits and hyphens: what the command and the filters say. It does not change.",
|
|
436
|
+
color: "Colour",
|
|
437
|
+
add: "Add",
|
|
438
|
+
},
|
|
439
|
+
nameOf: (key: string) => `Name of ${key}`,
|
|
440
|
+
colorOf: (key: string) => `Colour of ${key}`,
|
|
441
|
+
},
|
|
442
|
+
|
|
274
443
|
feed: {
|
|
275
444
|
title: "What happened",
|
|
276
445
|
list: "What happened",
|
|
@@ -284,6 +453,8 @@ export const en = {
|
|
|
284
453
|
something: "something",
|
|
285
454
|
aQuestion: "a question",
|
|
286
455
|
aFile: "a file",
|
|
456
|
+
aGoal: "a goal",
|
|
457
|
+
aCategory: "a category",
|
|
287
458
|
thePage: (name: string) => `the page ${name}`.trimEnd(),
|
|
288
459
|
role: {
|
|
289
460
|
admin: "an administrator",
|
|
@@ -303,6 +474,12 @@ export const en = {
|
|
|
303
474
|
visibility: "who is a member",
|
|
304
475
|
skillsAddress: "the skills address",
|
|
305
476
|
outcome: "what followed",
|
|
477
|
+
category: "the category",
|
|
478
|
+
goalId: "the goal",
|
|
479
|
+
startsOn: "the start",
|
|
480
|
+
dueOn: "the due date",
|
|
481
|
+
state: "the state",
|
|
482
|
+
color: "the colour",
|
|
306
483
|
} as Readonly<Record<string, string>>,
|
|
307
484
|
event: {
|
|
308
485
|
personJoined: () => "joined the board",
|
|
@@ -315,6 +492,12 @@ export const en = {
|
|
|
315
492
|
memberChanged: (login: string, role: string, project: string) =>
|
|
316
493
|
`made ${login} ${role} of ${project}`,
|
|
317
494
|
memberRemoved: (login: string, project: string) => `removed ${login} from ${project}`,
|
|
495
|
+
categoryCreated: (category: string) => `made the category ${category}`,
|
|
496
|
+
categoryUpdated: (fields: string, category: string) =>
|
|
497
|
+
`changed ${fields} of the category ${category}`,
|
|
498
|
+
categoryRemoved: (category: string) => `removed the category ${category}`,
|
|
499
|
+
goalCreated: (goal: string) => `set the goal ${goal}`,
|
|
500
|
+
goalUpdated: (fields: string, goal: string) => `changed ${fields} of the goal ${goal}`,
|
|
318
501
|
taskCreated: (task: string) => `wrote ${task}`,
|
|
319
502
|
taskMoved: (task: string, from: string, to: string) => `moved ${task} from ${from} to ${to}`,
|
|
320
503
|
taskUpdated: (fields: string, task: string) => `changed ${fields} of ${task}`,
|
package/src/i18n/ko.ts
CHANGED
|
@@ -27,6 +27,17 @@ export const ko: Messages = {
|
|
|
27
27
|
failed: "실패",
|
|
28
28
|
abandoned: "중단됨",
|
|
29
29
|
},
|
|
30
|
+
goalState: { planned: "계획됨", active: "진행 중", done: "달성", dropped: "중단" },
|
|
31
|
+
categoryColor: {
|
|
32
|
+
gray: "회색",
|
|
33
|
+
blue: "파랑",
|
|
34
|
+
green: "초록",
|
|
35
|
+
orange: "주황",
|
|
36
|
+
pink: "분홍",
|
|
37
|
+
purple: "보라",
|
|
38
|
+
teal: "청록",
|
|
39
|
+
yellow: "노랑",
|
|
40
|
+
},
|
|
30
41
|
},
|
|
31
42
|
|
|
32
43
|
common: {
|
|
@@ -61,9 +72,13 @@ export const ko: Messages = {
|
|
|
61
72
|
|
|
62
73
|
nav: {
|
|
63
74
|
projects: "프로젝트",
|
|
75
|
+
work: "내 작업",
|
|
64
76
|
people: "사람들",
|
|
65
77
|
agents: "에이전트",
|
|
78
|
+
categories: "카테고리",
|
|
66
79
|
board: "보드",
|
|
80
|
+
roadmap: "로드맵",
|
|
81
|
+
calendar: "캘린더",
|
|
67
82
|
docs: "문서",
|
|
68
83
|
decisions: "결정",
|
|
69
84
|
feed: "피드",
|
|
@@ -166,7 +181,25 @@ export const ko: Messages = {
|
|
|
166
181
|
decisionsTitle: "사람을 기다리는 결정",
|
|
167
182
|
agentAtWork: "에이전트 작업 중",
|
|
168
183
|
agentAtWorkTitle: "에이전트가 이 작업을 하고 있습니다",
|
|
169
|
-
|
|
184
|
+
agentSince: (agent, since) => `${agent}, ${since}부터 작업 중`,
|
|
185
|
+
filters: {
|
|
186
|
+
aria: "보드 좁혀 보기",
|
|
187
|
+
everyone: "모두",
|
|
188
|
+
mine: "내 작업",
|
|
189
|
+
anyCategory: "모든 카테고리",
|
|
190
|
+
noCategory: "카테고리 없음",
|
|
191
|
+
anyGoal: "모든 목표",
|
|
192
|
+
noGoal: "목표 없음",
|
|
193
|
+
clear: "전체 보기",
|
|
194
|
+
showing: (n, of) => `작업 ${of}개 중 ${n}개`,
|
|
195
|
+
},
|
|
196
|
+
due: {
|
|
197
|
+
overdue: (days) => `${days}일 지남`,
|
|
198
|
+
today: "오늘 마감",
|
|
199
|
+
tomorrow: "내일 마감",
|
|
200
|
+
inDays: (days) => `${days}일 남음`,
|
|
201
|
+
on: (day) => `${day} 마감`,
|
|
202
|
+
},
|
|
170
203
|
},
|
|
171
204
|
|
|
172
205
|
task: {
|
|
@@ -192,6 +225,19 @@ export const ko: Messages = {
|
|
|
192
225
|
history: "일어난 일",
|
|
193
226
|
subtasks: "하위 작업",
|
|
194
227
|
partOfIt: "하위 작업",
|
|
228
|
+
category: "카테고리",
|
|
229
|
+
goal: "목표",
|
|
230
|
+
plan: "일정",
|
|
231
|
+
planned: (from, to) =>
|
|
232
|
+
from !== undefined && to !== undefined
|
|
233
|
+
? `${from}부터 ${to}까지`
|
|
234
|
+
: from !== undefined
|
|
235
|
+
? `${from}부터`
|
|
236
|
+
: to !== undefined
|
|
237
|
+
? `${to}까지`
|
|
238
|
+
: "",
|
|
239
|
+
started: "시작",
|
|
240
|
+
done: "완료",
|
|
195
241
|
form: {
|
|
196
242
|
title: "제목",
|
|
197
243
|
body: "본문",
|
|
@@ -200,6 +246,12 @@ export const ko: Messages = {
|
|
|
200
246
|
priority: "우선순위",
|
|
201
247
|
assignee: "배정",
|
|
202
248
|
partOf: "상위 작업",
|
|
249
|
+
category: "카테고리",
|
|
250
|
+
noCategory: "카테고리 없음",
|
|
251
|
+
goal: "목표",
|
|
252
|
+
noGoal: "목표 없음",
|
|
253
|
+
startsOn: "시작일",
|
|
254
|
+
dueOn: "기한",
|
|
203
255
|
links: "링크",
|
|
204
256
|
label: "이름",
|
|
205
257
|
addLink: "링크 추가",
|
|
@@ -223,6 +275,10 @@ export const ko: Messages = {
|
|
|
223
275
|
},
|
|
224
276
|
waiting: "대기 중",
|
|
225
277
|
answered: "답변됨",
|
|
278
|
+
record: "기록",
|
|
279
|
+
recordLead:
|
|
280
|
+
"답변된 모든 결정, 최신순. 무엇을 물었고, 무엇을 골랐고, 누가 골랐는지. 맥락과 근거, 그 뒤에 일어난 일은 각 결정을 열어 봅니다.",
|
|
281
|
+
openRecord: "열기",
|
|
226
282
|
waitingForPerson: "사람을 기다리는 중입니다.",
|
|
227
283
|
options: "선택지",
|
|
228
284
|
notePlaceholder: "덧붙일 말이 있다면",
|
|
@@ -250,6 +306,111 @@ export const ko: Messages = {
|
|
|
250
306
|
},
|
|
251
307
|
},
|
|
252
308
|
|
|
309
|
+
calendar: {
|
|
310
|
+
title: "캘린더",
|
|
311
|
+
lead: "작업을 기한일에 놓고 봅니다. 시작일이 있는 작업은 그날부터 보이고, 날짜가 없는 작업은 아래에서 날짜를 기다립니다.",
|
|
312
|
+
grid: "이 달",
|
|
313
|
+
previous: "이전 달",
|
|
314
|
+
next: "다음 달",
|
|
315
|
+
thisMonth: "이번 달",
|
|
316
|
+
nothingDue: "이 달에 마감인 작업이 없습니다.",
|
|
317
|
+
overdue: "기한 지남",
|
|
318
|
+
nothingOverdue: "기한이 지난 작업이 없습니다.",
|
|
319
|
+
unscheduled: "날짜 없음",
|
|
320
|
+
allScheduled: "열린 작업마다 날짜가 있습니다.",
|
|
321
|
+
starts: "시작",
|
|
322
|
+
workload: {
|
|
323
|
+
title: "누가 무엇을",
|
|
324
|
+
lead: "사람마다 열린 작업과, 그중 늦은 것과 일주일 안에 마감인 것.",
|
|
325
|
+
person: "사람",
|
|
326
|
+
open: "열림",
|
|
327
|
+
inProgress: "진행 중",
|
|
328
|
+
dueSoon: "7일 내 마감",
|
|
329
|
+
overdue: "기한 지남",
|
|
330
|
+
unassigned: "아직 배정 없음",
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
roadmap: {
|
|
335
|
+
title: "로드맵",
|
|
336
|
+
lead: "프로젝트가 향하는 것. 목표마다 달성 목표일과, 그 아래 작업들이 어디까지 왔는지. 진행은 보드의 현재 상태에서 그대로 읽습니다.",
|
|
337
|
+
setGoal: "목표 세우기",
|
|
338
|
+
setGoalAria: "목표 세우기",
|
|
339
|
+
editAria: "목표 바꾸기",
|
|
340
|
+
one: "목표",
|
|
341
|
+
all: "모든 목표",
|
|
342
|
+
empty: {
|
|
343
|
+
title: "아직 세운 목표가 없습니다",
|
|
344
|
+
body: "소유자가 첫 목표를 세웁니다. 무엇을, 언제까지. 그 뒤 작업을 그 목표를 향해 씁니다.",
|
|
345
|
+
},
|
|
346
|
+
noSuch: {
|
|
347
|
+
title: "그런 목표가 없습니다",
|
|
348
|
+
body: "다른 프로젝트의 것이거나, 링크가 잘못됐습니다.",
|
|
349
|
+
},
|
|
350
|
+
onlyOwner: {
|
|
351
|
+
title: "로드맵은 소유자만 세웁니다",
|
|
352
|
+
body: "프로젝트 소유자나 워크스페이스 관리자에게 요청하세요.",
|
|
353
|
+
},
|
|
354
|
+
progress: (done, of) => `작업 ${of}개 중 ${done}개 완료`,
|
|
355
|
+
inProgress: (n) => `${n}개 진행 중`,
|
|
356
|
+
noTasks: "아직 이 목표를 향한 작업이 없습니다.",
|
|
357
|
+
tasks: "작업",
|
|
358
|
+
target: "목표일",
|
|
359
|
+
noTarget: "목표일 없음",
|
|
360
|
+
setBy: "세운 사람",
|
|
361
|
+
state: "상태",
|
|
362
|
+
nothingMore: "더 적힌 내용이 없습니다.",
|
|
363
|
+
form: {
|
|
364
|
+
title: "제목",
|
|
365
|
+
body: "달성의 의미",
|
|
366
|
+
bodyPlaceholder: "목표를 이루면 무엇이 참이 되는지, Markdown으로.",
|
|
367
|
+
state: "상태",
|
|
368
|
+
dueOn: "목표일",
|
|
369
|
+
set: "목표 세우기",
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
work: {
|
|
374
|
+
title: "내 작업",
|
|
375
|
+
lead: "내 프로젝트들에 걸쳐 내게 놓인 일. 내게 배정된 열린 작업을 기한순으로, 그리고 사람을 기다리는 결정.",
|
|
376
|
+
loading: "내 작업을 불러오는 중",
|
|
377
|
+
couldNotLoad: "내 작업을 불러올 수 없습니다.",
|
|
378
|
+
empty: {
|
|
379
|
+
title: "내게 배정된 작업이 없습니다",
|
|
380
|
+
body: "볼 수 있는 어느 프로젝트에서든 내게 배정된 작업이 여기에 나타납니다.",
|
|
381
|
+
},
|
|
382
|
+
overdue: "기한 지남",
|
|
383
|
+
thisWeek: "이번 주 마감",
|
|
384
|
+
later: "그 뒤",
|
|
385
|
+
noDay: "날짜 없음",
|
|
386
|
+
decisions: "사람을 기다리는 결정",
|
|
387
|
+
noDecisions: "기다리는 결정이 없습니다.",
|
|
388
|
+
inProject: (project) => `${project}에서`,
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
categories: {
|
|
392
|
+
title: "카테고리",
|
|
393
|
+
lead: "작업을 나누는 일의 종류이며, 모든 프로젝트에서 같습니다. 작업은 하나를 가지고, 보드는 하나로 좁혀 보며, 관리자가 목록을 관리합니다.",
|
|
394
|
+
onlyAdmin: "관리자가 추가하고 바꾸고 제거합니다. 다른 사람은 여기서 읽습니다.",
|
|
395
|
+
list: "카테고리",
|
|
396
|
+
add: "카테고리 추가",
|
|
397
|
+
addAria: "카테고리 추가",
|
|
398
|
+
empty: {
|
|
399
|
+
title: "카테고리가 없습니다",
|
|
400
|
+
body: "관리자가 여기서 첫 카테고리를 추가합니다.",
|
|
401
|
+
},
|
|
402
|
+
inUse: "작업이 속해 있는 카테고리는 그 작업들을 옮기기 전에는 제거할 수 없습니다.",
|
|
403
|
+
form: {
|
|
404
|
+
name: "이름",
|
|
405
|
+
key: "키",
|
|
406
|
+
keyHint: "소문자, 숫자, 하이픈. 명령과 필터가 부르는 이름이며 바뀌지 않습니다.",
|
|
407
|
+
color: "색",
|
|
408
|
+
add: "추가",
|
|
409
|
+
},
|
|
410
|
+
nameOf: (key) => `${key}의 이름`,
|
|
411
|
+
colorOf: (key) => `${key}의 색`,
|
|
412
|
+
},
|
|
413
|
+
|
|
253
414
|
feed: {
|
|
254
415
|
title: "일어난 일",
|
|
255
416
|
list: "일어난 일",
|
|
@@ -263,6 +424,8 @@ export const ko: Messages = {
|
|
|
263
424
|
something: "무언가",
|
|
264
425
|
aQuestion: "질문",
|
|
265
426
|
aFile: "파일",
|
|
427
|
+
aGoal: "목표",
|
|
428
|
+
aCategory: "카테고리",
|
|
266
429
|
thePage: (name) => `페이지 ${name}`.trimEnd(),
|
|
267
430
|
role: {
|
|
268
431
|
admin: "관리자",
|
|
@@ -282,6 +445,12 @@ export const ko: Messages = {
|
|
|
282
445
|
visibility: "멤버 범위",
|
|
283
446
|
skillsAddress: "스킬 주소",
|
|
284
447
|
outcome: "그 뒤에 일어난 일",
|
|
448
|
+
category: "카테고리",
|
|
449
|
+
goalId: "목표",
|
|
450
|
+
startsOn: "시작일",
|
|
451
|
+
dueOn: "기한",
|
|
452
|
+
state: "상태",
|
|
453
|
+
color: "색",
|
|
285
454
|
},
|
|
286
455
|
event: {
|
|
287
456
|
personJoined: () => "보드에 들어왔습니다",
|
|
@@ -293,6 +462,11 @@ export const ko: Messages = {
|
|
|
293
462
|
memberChanged: (login, role, project) =>
|
|
294
463
|
`${login}을(를) ${project}의 ${role}(으)로 지정했습니다`,
|
|
295
464
|
memberRemoved: (login, project) => `${login}을(를) ${project}에서 제외했습니다`,
|
|
465
|
+
categoryCreated: (category) => `카테고리 ${category}을(를) 만들었습니다`,
|
|
466
|
+
categoryUpdated: (fields, category) => `카테고리 ${category}의 ${fields}을(를) 바꿨습니다`,
|
|
467
|
+
categoryRemoved: (category) => `카테고리 ${category}을(를) 제거했습니다`,
|
|
468
|
+
goalCreated: (goal) => `목표 ${goal}을(를) 세웠습니다`,
|
|
469
|
+
goalUpdated: (fields, goal) => `목표 ${goal}의 ${fields}을(를) 바꿨습니다`,
|
|
296
470
|
taskCreated: (task) => `${task}을(를) 썼습니다`,
|
|
297
471
|
taskMoved: (task, from, to) => `${task}을(를) ${from}에서 ${to}(으)로 옮겼습니다`,
|
|
298
472
|
taskUpdated: (fields, task) => `${task}의 ${fields}을(를) 바꿨습니다`,
|