@anchrd/intel-ui 0.39.0 → 0.41.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/package.json +13 -2
- package/src/access-summary/access-summary.tsx +1 -11
- package/src/app/app-tree/app-tree.tsx +58 -0
- package/src/attachment-viewer/attachment-viewer.tsx +304 -0
- package/src/board/board-assignee/board-assignee.ts +18 -0
- package/src/board/board-crumbs/board-crumbs.ts +56 -0
- package/src/board/board-crumbs/board-crumbs.tsx +108 -0
- package/src/board/board-data/board-data.ts +31 -5
- package/src/board/board-data/board-data.types.ts +10 -1
- package/src/board/board-kanban/board-kanban.ts +63 -9
- package/src/board/board-kanban/board-kanban.tsx +409 -66
- package/src/board/board-open-task/board-open-task.ts +32 -0
- package/src/board/board-panel/board-panel.tsx +202 -31
- package/src/board/board-settings/board-settings.tsx +209 -0
- package/src/board/board-stripes/board-stripes.ts +128 -0
- package/src/board/board-table/board-table.ts +23 -105
- package/src/board/board-table/board-table.tsx +436 -135
- package/src/board/board-task/board-task.ts +105 -0
- package/src/board/board-task/board-task.tsx +396 -0
- package/src/board/board-title-row/board-title-row.tsx +68 -0
- package/src/file-preview/file-preview-view.tsx +28 -0
- package/src/file-preview/file-preview.tsx +28 -0
- package/src/file-preview/pdf-file-preview.tsx +5 -0
- package/src/file-preview/presentation-file-preview.tsx +21 -0
- package/src/file-preview/spreadsheet-file-preview.tsx +5 -0
- package/src/file-preview/word-file-preview.tsx +5 -0
- package/src/i18n/de.json +81 -7
- package/src/i18n/en.json +81 -7
- package/src/i18n/es.json +81 -7
- package/src/nodes/nodes.tsx +26 -52
- package/src/resource-menu/resource-menu.tsx +18 -12
- package/src/router/selection-search.ts +17 -2
- package/src/styles.css +29 -25
- package/src/title-row/title-row.tsx +33 -6
- package/src/user-name/user-name.ts +17 -0
- package/vite.config.ts +111 -3
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
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
⚠️
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
--board-
|
|
60
|
-
--board-
|
|
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-
|
|
94
|
-
--board-
|
|
95
|
-
--board-
|
|
96
|
-
--board-
|
|
97
|
-
--board-
|
|
98
|
-
--board-
|
|
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-
|
|
134
|
-
--color-board-
|
|
135
|
-
--color-board-
|
|
136
|
-
--color-board-
|
|
137
|
-
--color-board-
|
|
138
|
-
--color-board-
|
|
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 {
|
|
@@ -67,14 +67,36 @@ export function TitleRowScrollArea({
|
|
|
67
67
|
*/
|
|
68
68
|
export function TitleRow({
|
|
69
69
|
title,
|
|
70
|
+
crumbs,
|
|
70
71
|
description,
|
|
71
72
|
target,
|
|
72
73
|
separated,
|
|
73
74
|
children,
|
|
74
75
|
}: {
|
|
76
|
+
/**
|
|
77
|
+
* ⚠️ **Not drawn while `crumbs` is set** — the path names the thing then, and nothing falls back
|
|
78
|
+
* to this. It stays required all the same, so every caller has to state in one word what the row
|
|
79
|
+
* is about: the next reader of this call site should not have to follow a component two files
|
|
80
|
+
* away to find out.
|
|
81
|
+
*/
|
|
75
82
|
title: string;
|
|
83
|
+
/**
|
|
84
|
+
* A path that stands in for the name.
|
|
85
|
+
*
|
|
86
|
+
* ⚠️ **It REPLACES the heading, it does not join it.** An open board card carries its name in the
|
|
87
|
+
* path already, and the same sentence twice above one another says nothing twice (#692). The row
|
|
88
|
+
* itself, its menu order and its slots stay exactly as they are: only what identifies the thing
|
|
89
|
+
* changes, because for a card the answer is "where it sits", not just "what it is called".
|
|
90
|
+
*/
|
|
91
|
+
crumbs?: ReactNode;
|
|
76
92
|
description?: string | null;
|
|
77
|
-
|
|
93
|
+
/**
|
|
94
|
+
* What the three-dot menu acts on. ⚠️ **Absent means NO menu**, and that is a real state rather
|
|
95
|
+
* than an oversight: a card whose node has not arrived yet has nothing the menu could rename,
|
|
96
|
+
* move or archive, and pointing it at the container instead would archive the wrong thing without
|
|
97
|
+
* asking (#692).
|
|
98
|
+
*/
|
|
99
|
+
target?: ResourceTarget;
|
|
78
100
|
/**
|
|
79
101
|
* A separator that does NOT wait for a scroll.
|
|
80
102
|
*
|
|
@@ -89,7 +111,8 @@ export function TitleRow({
|
|
|
89
111
|
}) {
|
|
90
112
|
const scroll = useContext(TitleRowScrollContext);
|
|
91
113
|
const setScrolled = scroll?.setScrolled;
|
|
92
|
-
const targetId =
|
|
114
|
+
const targetId =
|
|
115
|
+
target === undefined ? undefined : target.type === "flow" ? target.flow.id : target.node.id;
|
|
93
116
|
useEffect(() => {
|
|
94
117
|
void targetId;
|
|
95
118
|
setScrolled?.(false);
|
|
@@ -105,13 +128,17 @@ export function TitleRow({
|
|
|
105
128
|
<div className="flex min-w-0 items-center gap-3">
|
|
106
129
|
<div className="min-w-0">
|
|
107
130
|
<div className="flex min-w-0 flex-wrap items-baseline gap-x-3">
|
|
108
|
-
|
|
109
|
-
|
|
131
|
+
{crumbs === undefined ? (
|
|
132
|
+
<h2 className="truncate text-lg font-semibold">{title}</h2>
|
|
133
|
+
) : (
|
|
134
|
+
crumbs
|
|
135
|
+
)}
|
|
136
|
+
{target?.type === "node" && target.node.kind === "folder" ? (
|
|
110
137
|
<ResourceAccessSummary resourceId={target.node.id} ownerId={target.node.ownerId} />
|
|
111
138
|
) : null}
|
|
112
139
|
{/* A flow carries its own grants since #530, so who reaches it is worth showing where
|
|
113
140
|
it stands — the same question the folder above already answers here. */}
|
|
114
|
-
{target
|
|
141
|
+
{target?.type === "flow" ? (
|
|
115
142
|
<ResourceAccessSummary
|
|
116
143
|
kind="flow"
|
|
117
144
|
resourceId={target.flow.id}
|
|
@@ -129,7 +156,7 @@ export function TitleRow({
|
|
|
129
156
|
<div className="flex shrink-0 items-center gap-2">
|
|
130
157
|
<div data-slot="title-actions" className="flex items-center gap-2" />
|
|
131
158
|
{children}
|
|
132
|
-
<ResourceMenu target={target} variant="title" />
|
|
159
|
+
{target === undefined ? null : <ResourceMenu target={target} variant="title" />}
|
|
133
160
|
</div>
|
|
134
161
|
</div>
|
|
135
162
|
);
|
|
@@ -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
|
+
}
|
package/vite.config.ts
CHANGED
|
@@ -1,11 +1,119 @@
|
|
|
1
|
+
import { copyFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
1
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { fileViewerRenderers } from "@file-viewer/vite-plugin";
|
|
2
6
|
import tailwindcss from "@tailwindcss/vite";
|
|
3
7
|
import react from "@vitejs/plugin-react";
|
|
4
|
-
import { defineConfig } from "vite";
|
|
8
|
+
import { defineConfig, type Plugin } from "vite";
|
|
9
|
+
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
|
|
12
|
+
function fileViewerLicenses(): Plugin {
|
|
13
|
+
let outDir = "dist";
|
|
14
|
+
return {
|
|
15
|
+
name: "file-viewer-licenses",
|
|
16
|
+
configResolved(config) {
|
|
17
|
+
outDir = config.build.outDir;
|
|
18
|
+
},
|
|
19
|
+
writeBundle() {
|
|
20
|
+
const target = resolve(outDir, "licenses/file-viewer");
|
|
21
|
+
const reactPackage = require.resolve("@file-viewer/react/package.json");
|
|
22
|
+
const rendererPdfPackage = require.resolve("@file-viewer/renderer-pdf/package.json");
|
|
23
|
+
const rendererPresentationPackage = require.resolve(
|
|
24
|
+
"@file-viewer/renderer-presentation/package.json",
|
|
25
|
+
);
|
|
26
|
+
const rendererWordPackage = require.resolve("@file-viewer/renderer-word/package.json");
|
|
27
|
+
const packageLicenses = [
|
|
28
|
+
["@file-viewer/react", reactPackage],
|
|
29
|
+
[
|
|
30
|
+
"@file-viewer/core",
|
|
31
|
+
createRequire(reactPackage).resolve("@file-viewer/core/package.json"),
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
"@file-viewer/doc",
|
|
35
|
+
createRequire(rendererWordPackage).resolve("@file-viewer/doc/package.json"),
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
"@file-viewer/docx",
|
|
39
|
+
createRequire(rendererWordPackage).resolve("@file-viewer/docx/package.json"),
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"@file-viewer/ppt",
|
|
43
|
+
resolve(
|
|
44
|
+
dirname(createRequire(rendererPresentationPackage).resolve("@file-viewer/ppt")),
|
|
45
|
+
"package.json",
|
|
46
|
+
),
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
"@file-viewer/pptx",
|
|
50
|
+
createRequire(rendererPresentationPackage).resolve("@file-viewer/pptx/package.json"),
|
|
51
|
+
],
|
|
52
|
+
["@file-viewer/renderer-pdf", rendererPdfPackage],
|
|
53
|
+
["@file-viewer/renderer-presentation", rendererPresentationPackage],
|
|
54
|
+
[
|
|
55
|
+
"@file-viewer/renderer-spreadsheet",
|
|
56
|
+
require.resolve("@file-viewer/renderer-spreadsheet/package.json"),
|
|
57
|
+
],
|
|
58
|
+
["@file-viewer/renderer-word", rendererWordPackage],
|
|
59
|
+
["@file-viewer/vite-plugin", require.resolve("@file-viewer/vite-plugin/package.json")],
|
|
60
|
+
["pdfjs-dist", createRequire(rendererPdfPackage).resolve("pdfjs-dist/package.json")],
|
|
61
|
+
] as const;
|
|
62
|
+
mkdirSync(target, { recursive: true });
|
|
63
|
+
for (const [name, packageJson] of packageLicenses) {
|
|
64
|
+
copyFileSync(
|
|
65
|
+
resolve(dirname(packageJson), "LICENSE"),
|
|
66
|
+
resolve(target, `${name.replace("@file-viewer/", "")}.LICENSE`),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
writeFileSync(
|
|
70
|
+
resolve(target, "THIRD_PARTY_NOTICES.txt"),
|
|
71
|
+
[
|
|
72
|
+
"File Viewer packages used by Intel",
|
|
73
|
+
"",
|
|
74
|
+
"Apache-2.0:",
|
|
75
|
+
"@file-viewer/react",
|
|
76
|
+
"@file-viewer/core",
|
|
77
|
+
"@file-viewer/docx",
|
|
78
|
+
"@file-viewer/pptx",
|
|
79
|
+
"@file-viewer/renderer-pdf",
|
|
80
|
+
"@file-viewer/renderer-presentation",
|
|
81
|
+
"@file-viewer/renderer-spreadsheet",
|
|
82
|
+
"@file-viewer/renderer-word",
|
|
83
|
+
"@file-viewer/vite-plugin",
|
|
84
|
+
"pdfjs-dist",
|
|
85
|
+
"",
|
|
86
|
+
"MIT:",
|
|
87
|
+
"@file-viewer/doc",
|
|
88
|
+
"",
|
|
89
|
+
"Package-specific license (bundled transitively, not exposed by Intel; see ppt.LICENSE):",
|
|
90
|
+
"@file-viewer/ppt",
|
|
91
|
+
"",
|
|
92
|
+
"The complete license text for every package is stored beside this notice.",
|
|
93
|
+
"",
|
|
94
|
+
].join("\n"),
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
5
99
|
|
|
6
100
|
export default defineConfig({
|
|
7
|
-
plugins: [
|
|
8
|
-
|
|
101
|
+
plugins: [
|
|
102
|
+
react(),
|
|
103
|
+
tailwindcss(),
|
|
104
|
+
fileViewerRenderers({
|
|
105
|
+
formats: ["pdf", "docx", "xlsx", "pptx"],
|
|
106
|
+
inject: false,
|
|
107
|
+
chunkStrategy: "renderer",
|
|
108
|
+
}),
|
|
109
|
+
fileViewerLicenses(),
|
|
110
|
+
],
|
|
111
|
+
resolve: {
|
|
112
|
+
alias: {
|
|
113
|
+
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
|
114
|
+
stream: "readable-stream",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
9
117
|
server: {
|
|
10
118
|
proxy: {
|
|
11
119
|
"/api": { target: "http://localhost:8788", changeOrigin: true },
|