@anchrd/intel-ui 0.38.0 → 0.40.0

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/src/i18n/es.json CHANGED
@@ -33,8 +33,15 @@
33
33
  "auth.signOutFailed": "El cierre de sesión ha fallado. Comprueba tu conexión e inténtalo de nuevo.",
34
34
  "board.addCard": "+ Tarea",
35
35
  "board.addCardIn": "Añadir una tarea a {column}",
36
- "board.cardLabel": "{title}, en {column}. Mantén Alt y usa las flechas para moverla.",
36
+ "board.addLabel": "Añadir etiqueta",
37
+ "board.addLink": "Vínculo",
38
+ "board.cardLabel": "Abrir {title}, en {column}. Alt y una flecha la mueve.",
39
+ "board.column.archive": "Archivo",
37
40
  "board.column.assignee": "Asignada a",
41
+ "board.column.default.backlog": "Backlog",
42
+ "board.column.default.doing": "En curso",
43
+ "board.column.default.done": "Hecho",
44
+ "board.column.default.todo": "Pendiente",
38
45
  "board.column.dependsOn": "Espera a",
39
46
  "board.column.due": "Vence",
40
47
  "board.column.labels": "Etiquetas",
@@ -42,17 +49,51 @@
42
49
  "board.column.title": "Título",
43
50
  "board.columnEmpty": "Aquí todavía no hay nada.",
44
51
  "board.createFailed": "No se pudo crear la tarea.",
52
+ "board.drag.lifted": "{card} recogida",
53
+ "board.drag.moved": "{card} movida a {column}",
54
+ "board.drag.putBack": "{card} devuelta",
55
+ "board.dragInstructions": "Arrastra una tarjeta con el ratón para moverla. Sin puntero: mantén Alt y pulsa una flecha — izquierda y derecha cambian de columna, arriba y abajo mueven dentro de una.",
45
56
  "board.failed": "No se pudo cargar este tablero.",
46
57
  "board.filter.all": "Todas las columnas",
47
58
  "board.filter.status": "Mostrar columna",
48
59
  "board.filterEmpty": "Ninguna tarjeta coincide con este filtro.",
49
- "board.group.assignee": "Asignada a",
60
+ "board.fromDate": "desde {date}",
61
+ "board.group.empty": "Sin valor",
50
62
  "board.group.none": "Nada",
51
- "board.group.status": "Columna",
52
63
  "board.groupBy": "Agrupar por",
64
+ "board.link.blocker": "Espera a",
65
+ "board.link.outside": "Fuera de este tablero",
66
+ "board.link.subtask": "Subtarea",
67
+ "board.links": "Vinculado",
68
+ "board.moveTo": "Mover a una columna",
69
+ "board.progress": "{done} de {total} hechas",
70
+ "board.removeLabel": "Quitar la etiqueta {label}",
71
+ "board.settings.addColumn": "+ Columna",
72
+ "board.settings.columnName": "Nombre de la columna {column}",
73
+ "board.settings.description": "Columnas y lo que muestra el tablero.",
74
+ "board.settings.duplicateName": "Dos columnas se llaman {column}. Los nombres deben distinguirlas.",
75
+ "board.settings.failed": "No se pudieron guardar los ajustes.",
76
+ "board.settings.moveDown": "Bajar {column}",
77
+ "board.settings.moveUp": "Subir {column}",
78
+ "board.settings.newColumn": "Nueva columna",
79
+ "board.settings.open": "Ajustes del tablero",
80
+ "board.settings.remove": "Quitar {column}",
81
+ "board.settings.removeBlocked": "{column} no está vacía. Mueve sus tarjetas primero.",
82
+ "board.settings.showArchive": "Mostrar la columna de archivo",
83
+ "board.settings.showArchiveHint": "Está en todos los tableros. Oculta, sus tarjetas desaparecen de todas las vistas.",
84
+ "board.settings.title": "Ajustes del tablero",
85
+ "board.stripes.root": "Nivel {level}, tiene subtareas",
86
+ "board.stripes.under": "Nivel {level} · superior en {column}",
87
+ "board.table.collapse": "Ocultar lo que hay bajo {row}",
88
+ "board.table.columns": "Columnas",
89
+ "board.table.expand": "Mostrar lo que hay bajo {row}",
90
+ "board.table.filteredBy": "solo {column}",
91
+ "board.table.groupedBy": "agrupado por {column}",
53
92
  "board.tableEmpty": "Este tablero aún no tiene tarjetas.",
93
+ "board.taskGone": "Esta tarjeta ya no está en este tablero. O está archivada, o ya no existe.",
54
94
  "board.unassigned": "Nadie todavía",
55
95
  "board.unknownColumn": "no está en este tablero",
96
+ "board.untilDate": "vence {date}",
56
97
  "board.view.kanban": "Kanban",
57
98
  "board.view.table": "Tabla",
58
99
  "common.cancel": "Cancelar",
@@ -7,6 +7,14 @@ export type IntelView = (typeof IntelViews)[number];
7
7
  export type SelectionSearch = Record<string, unknown> & {
8
8
  select?: string;
9
9
  view?: Exclude<IntelView, "editor">;
10
+ /**
11
+ * The card of the selected board that is open, by its node id.
12
+ *
13
+ * ⚠️ **Beside `select`, not instead of it.** A task is not a level of the tree the sidebar can
14
+ * select; it is something shown INSIDE the board that is selected. Carrying it as `select` would
15
+ * make the tree try to reveal a node it does not draw, and the back button would leave the board.
16
+ */
17
+ task?: string;
10
18
  };
11
19
 
12
20
  // One search parameter carries "open this one" into an area: the header search names a hit, the
@@ -20,10 +28,12 @@ export type SelectionSearch = Record<string, unknown> & {
20
28
  // ⚠️ Unknown parameters are passed through rather than dropped. The portal's connect flow returns
21
29
  // to `/tools` with its own marker, and a validator that kept only what it knows would delete it.
22
30
  export function selectionSearch(search: Record<string, unknown>): SelectionSearch {
23
- const { select, view, ...rest } = search;
31
+ const { select, view, task, ...rest } = search;
24
32
  const withSelect =
25
33
  typeof select === "string" && select.length > 0 ? { ...rest, select } : { ...rest };
26
- return view === "graph" || view === "runs" ? { ...withSelect, view } : withSelect;
34
+ const withTask =
35
+ typeof task === "string" && task.length > 0 ? { ...withSelect, task } : withSelect;
36
+ return view === "graph" || view === "runs" ? { ...withTask, view } : withTask;
27
37
  }
28
38
 
29
39
  // Screens are lazy route components with no route object at hand, so they read the parameter off
@@ -41,3 +51,8 @@ export function viewFrom(search: unknown): IntelView {
41
51
  export function graphViewFrom(search: unknown): boolean {
42
52
  return viewFrom(search) === "graph";
43
53
  }
54
+
55
+ export function openTaskFrom(search: unknown): string | null {
56
+ const task = (search as { task?: unknown } | null)?.task;
57
+ return typeof task === "string" && task.length > 0 ? task : null;
58
+ }
package/src/styles.css CHANGED
@@ -44,20 +44,24 @@
44
44
  grid of achromatic dots codes nothing, and neither does a graph whose blocked node looks like
45
45
  its neighbour.
46
46
 
47
- ⚠️ A step of the ramp belongs to a POSITION, never to a status id. A board's status list is
48
- configured per board renamed, extended, reordered (`board_configure`) so `done` is not a
49
- colour any more than `column four` is a name. The n-th status takes the n-th step and the ramp
50
- wraps; `archived` is the exception and always takes `--muted-foreground`, because a shelf is
51
- not a stage (see `board-status.ts`).
47
+ ⚠️ **A step belongs to a FAMILY, not to a status and not to a depth.** Every card descending
48
+ from the same root task takes the same step, whatever column it sits in and however deep it
49
+ hangs that is what lets somebody see that the card in `Backlog` belongs to the one in
50
+ `In progress`. Depth is carried by the NUMBER of stripes, never by the hue: two channels for
51
+ two questions.
52
52
 
53
- ⚠️ Colour is never the only channel. Every place these are used names the status in text as
54
- well, so a reader who does not see the difference reads it instead. */
55
- --board-status-1: oklch(0.58 0.02 260);
56
- --board-status-2: oklch(0.55 0.16 255);
57
- --board-status-3: oklch(0.65 0.15 65);
58
- --board-status-4: oklch(0.55 0.14 150);
59
- --board-status-5: oklch(0.53 0.18 305);
60
- --board-status-6: oklch(0.56 0.15 20);
53
+ ⚠️ **Six, and then they repeat.** Two families sharing a step is not a fault. At twenty root
54
+ tasks every other answer is a palette nobody can tell apart, and a colour that cannot be told
55
+ apart says less than none.
56
+
57
+ ⚠️ Colour is never the only channel. Every card that carries stripes also names its level and
58
+ where its parent sits, in text, so a reader who does not see the difference reads it instead. */
59
+ --board-family-1: oklch(0.58 0.02 260);
60
+ --board-family-2: oklch(0.55 0.16 255);
61
+ --board-family-3: oklch(0.65 0.15 65);
62
+ --board-family-4: oklch(0.55 0.14 150);
63
+ --board-family-5: oklch(0.53 0.18 305);
64
+ --board-family-6: oklch(0.56 0.15 20);
61
65
  }
62
66
 
63
67
  .dark {
@@ -90,12 +94,12 @@
90
94
  --sidebar-ring: oklch(0.556 0 0);
91
95
  /* The same six steps, lifted for a dark surface. Same hues, same order — a board must not change
92
96
  which colour a column has when the reader switches the appearance. */
93
- --board-status-1: oklch(0.72 0.02 260);
94
- --board-status-2: oklch(0.7 0.14 255);
95
- --board-status-3: oklch(0.78 0.13 65);
96
- --board-status-4: oklch(0.72 0.13 150);
97
- --board-status-5: oklch(0.7 0.16 305);
98
- --board-status-6: oklch(0.71 0.14 20);
97
+ --board-family-1: oklch(0.72 0.02 260);
98
+ --board-family-2: oklch(0.7 0.14 255);
99
+ --board-family-3: oklch(0.78 0.13 65);
100
+ --board-family-4: oklch(0.72 0.13 150);
101
+ --board-family-5: oklch(0.7 0.16 305);
102
+ --board-family-6: oklch(0.71 0.14 20);
99
103
  }
100
104
 
101
105
  @theme inline {
@@ -130,12 +134,12 @@
130
134
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
131
135
  --color-sidebar-border: var(--sidebar-border);
132
136
  --color-sidebar-ring: var(--sidebar-ring);
133
- --color-board-status-1: var(--board-status-1);
134
- --color-board-status-2: var(--board-status-2);
135
- --color-board-status-3: var(--board-status-3);
136
- --color-board-status-4: var(--board-status-4);
137
- --color-board-status-5: var(--board-status-5);
138
- --color-board-status-6: var(--board-status-6);
137
+ --color-board-family-1: var(--board-family-1);
138
+ --color-board-family-2: var(--board-family-2);
139
+ --color-board-family-3: var(--board-family-3);
140
+ --color-board-family-4: var(--board-family-4);
141
+ --color-board-family-5: var(--board-family-5);
142
+ --color-board-family-6: var(--board-family-6);
139
143
  }
140
144
 
141
145
  @layer base {
@@ -39,3 +39,20 @@ export function useUserName(userId: string | null): string | null {
39
39
  if (userId === null || me === null || me.id !== userId) return null;
40
40
  return displayNameOf(me);
41
41
  }
42
+
43
+ /**
44
+ * The one or two letters that stand for a name in a circle.
45
+ *
46
+ * ⚠️ Lives here rather than beside the circle that first needed it: two surfaces now draw the same
47
+ * circle — the access summary and a task's assignee — and two copies of this would drift into two
48
+ * different abbreviations of the same person.
49
+ */
50
+ export function initials(value: string): string {
51
+ const parts = value
52
+ .replace(/@.*$/, "")
53
+ .split(/[\s._+-]+/)
54
+ .filter(Boolean);
55
+ if (parts.length === 0) return "?";
56
+ if (parts.length === 1) return (parts[0]?.slice(0, 2) ?? "?").toUpperCase();
57
+ return `${parts[0]?.[0] ?? ""}${parts.at(-1)?.[0] ?? ""}`.toUpperCase();
58
+ }