@anchrd/intel-ui 0.42.0 → 0.43.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
CHANGED
|
@@ -105,8 +105,6 @@ export function AttachmentViewer({ document }: { document: NodeDocument }) {
|
|
|
105
105
|
const kind = document.version
|
|
106
106
|
? attachmentPreviewKind(document.node.title, document.version.mediaType)
|
|
107
107
|
: "unsupported";
|
|
108
|
-
const hasViewerControls = kind !== "image" && kind !== "unsupported";
|
|
109
|
-
|
|
110
108
|
return (
|
|
111
109
|
<div className="flex min-h-0 flex-1 flex-col px-6 pb-6">
|
|
112
110
|
<ActionSlot name="title-actions">
|
|
@@ -115,12 +113,21 @@ export function AttachmentViewer({ document }: { document: NodeDocument }) {
|
|
|
115
113
|
aria-label={i18n.t(detailsOpen ? "attachment.detailsHide" : "attachment.detailsShow")}
|
|
116
114
|
aria-expanded={detailsOpen}
|
|
117
115
|
onClick={() => setDetailsOpen((current) => !current)}
|
|
118
|
-
className=
|
|
116
|
+
className={cn(
|
|
117
|
+
"inline-flex size-8 shrink-0 items-center justify-center rounded-md bg-transparent outline-none hover:bg-accent focus-visible:bg-accent focus-visible:ring-2 focus-visible:ring-ring",
|
|
118
|
+
detailsOpen && "bg-accent",
|
|
119
|
+
)}
|
|
119
120
|
>
|
|
120
121
|
<Info aria-hidden="true" className="size-4" />
|
|
121
122
|
</button>
|
|
122
123
|
</ActionSlot>
|
|
123
|
-
<div
|
|
124
|
+
<div
|
|
125
|
+
data-preview-kind={kind}
|
|
126
|
+
className={cn(
|
|
127
|
+
"relative flex min-h-0 flex-1 overflow-hidden rounded-xl",
|
|
128
|
+
kind === "image" ? "bg-muted/40" : "border bg-background",
|
|
129
|
+
)}
|
|
130
|
+
>
|
|
124
131
|
<div className="relative min-h-0 min-w-0 flex-1 bg-muted/40">
|
|
125
132
|
{document.version === null ? (
|
|
126
133
|
<PreviewMessage message={i18n.t("attachment.empty")} />
|
|
@@ -147,17 +154,10 @@ export function AttachmentViewer({ document }: { document: NodeDocument }) {
|
|
|
147
154
|
<AttachmentDetails
|
|
148
155
|
document={document}
|
|
149
156
|
file={file}
|
|
150
|
-
footerInset={hasViewerControls}
|
|
151
157
|
kind={kind}
|
|
152
158
|
close={() => setDetailsOpen(false)}
|
|
153
159
|
/>
|
|
154
160
|
) : null}
|
|
155
|
-
{detailsOpen && hasViewerControls ? (
|
|
156
|
-
<div
|
|
157
|
-
aria-hidden="true"
|
|
158
|
-
className="pointer-events-none absolute inset-x-0 bottom-14 z-10 hidden border-t md:block"
|
|
159
|
-
/>
|
|
160
|
-
) : null}
|
|
161
161
|
</div>
|
|
162
162
|
</div>
|
|
163
163
|
);
|
|
@@ -212,13 +212,11 @@ function ImagePreview({ file, title }: { file: File; title: string }) {
|
|
|
212
212
|
function AttachmentDetails({
|
|
213
213
|
document,
|
|
214
214
|
file,
|
|
215
|
-
footerInset,
|
|
216
215
|
kind,
|
|
217
216
|
close,
|
|
218
217
|
}: {
|
|
219
218
|
document: NodeDocument;
|
|
220
219
|
file: File | null;
|
|
221
|
-
footerInset: boolean;
|
|
222
220
|
kind: AttachmentPreviewKind;
|
|
223
221
|
close(): void;
|
|
224
222
|
}) {
|
|
@@ -257,11 +255,7 @@ function AttachmentDetails({
|
|
|
257
255
|
return (
|
|
258
256
|
<aside
|
|
259
257
|
aria-label={i18n.t("attachment.details.title")}
|
|
260
|
-
className=
|
|
261
|
-
"absolute inset-x-0 bottom-0 z-10 max-h-[80%] overflow-auto border-t bg-background shadow-lg md:static md:z-auto md:w-80 md:max-h-none md:shrink-0 md:border-l md:border-t-0 md:shadow-none",
|
|
262
|
-
// File renderers keep their controls in a shared footer; the panel ends beside that footer.
|
|
263
|
-
footerInset && "md:mb-14",
|
|
264
|
-
)}
|
|
258
|
+
className="absolute inset-x-0 bottom-0 z-10 max-h-[80%] overflow-auto border-t bg-background shadow-lg md:static md:z-auto md:w-80 md:max-h-none md:shrink-0 md:border-l md:border-t-0 md:shadow-none"
|
|
265
259
|
>
|
|
266
260
|
<div className="flex items-center justify-between border-b px-5 py-4">
|
|
267
261
|
<h3 className="font-semibold">{i18n.t("attachment.details.title")}</h3>
|
|
@@ -35,12 +35,14 @@ const viewerTheme = `
|
|
|
35
35
|
}
|
|
36
36
|
.pdf-shell,.pdf-wrapper{background:var(--muted)!important;color:var(--foreground)!important}
|
|
37
37
|
.pdf-nav-pane,.pdf-nav-tabs,.pdf-nav-head{background:var(--background)!important;border-color:var(--border)!important}
|
|
38
|
-
.pdf-
|
|
39
|
-
.pdf-nav-tabs
|
|
38
|
+
@media (min-width:721px){.pdf-shell:not(.pdf-shell--nav-hidden) .pdf-content{grid-template-columns:6rem minmax(0,1fr)!important}}
|
|
39
|
+
.pdf-nav-head{display:none!important}.pdf-nav-tabs{display:flex!important;justify-content:center;padding:6px!important}
|
|
40
|
+
.pdf-nav-tabs:not([data-outline-available="true"]){display:none!important}.pdf-nav-tabs button.active{display:none!important}
|
|
41
|
+
.pdf-nav-tabs button{width:30px;min-width:30px;padding:0;border:0!important;box-shadow:none!important;font-size:0;color:var(--muted-foreground)!important}
|
|
40
42
|
.pdf-nav-tabs button svg{width:15px;height:15px;margin:auto;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
|
41
|
-
.pdf-nav-tabs button:hover,.pdf-nav-tabs button.active{background:var(--accent)!important;border
|
|
42
|
-
.pdf-page-list{gap:4px!important;padding:6px!important}.pdf-page-button{display:flex!important;min-height:
|
|
43
|
-
.pdf-page-button:hover,.pdf-page-button--active{background:var(--accent)!important;border
|
|
43
|
+
.pdf-nav-tabs button:hover,.pdf-nav-tabs button.active{background:var(--accent)!important;border:0!important;color:var(--accent-foreground)!important}
|
|
44
|
+
.pdf-page-list{gap:4px!important;padding:6px!important}.pdf-page-button{display:flex!important;width:32px!important;min-width:32px!important;height:32px!important;min-height:32px!important;margin-inline:auto!important;padding:0!important;border:0!important;box-shadow:none!important;background:transparent!important;color:var(--foreground)!important;justify-content:center!important}
|
|
45
|
+
.pdf-page-button:hover,.pdf-page-button--active{background:var(--accent)!important;border:0!important;box-shadow:none!important}
|
|
44
46
|
.pdf-page-thumb{width:28px!important;height:28px!important;border:0!important;background:transparent!important;color:var(--foreground)!important}
|
|
45
47
|
.pdf-page-label{display:none!important}.pdf-outline-button{color:var(--foreground)!important}.pdf-outline-button:hover{background:var(--accent)!important;border-color:var(--border)!important}
|
|
46
48
|
`;
|
|
@@ -92,35 +94,83 @@ export function FilePreviewView({
|
|
|
92
94
|
style.dataset.intelViewerTheme = "true";
|
|
93
95
|
style.textContent = viewerTheme;
|
|
94
96
|
root.append(style);
|
|
95
|
-
const
|
|
97
|
+
const adaptNavigation = () => {
|
|
96
98
|
for (const button of root.querySelectorAll<HTMLButtonElement>(".pdf-page-button")) {
|
|
97
99
|
const label = button.querySelector(".pdf-page-label")?.textContent?.trim();
|
|
98
100
|
if (label) button.title = label;
|
|
99
101
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
const tabs = root.querySelector<HTMLElement>(".pdf-nav-tabs");
|
|
103
|
+
const buttons = tabs?.querySelectorAll<HTMLButtonElement>("button");
|
|
104
|
+
if (tabs && buttons?.length === 2) {
|
|
105
|
+
tabs.setAttribute("role", "group");
|
|
106
|
+
for (const [index, button] of buttons.entries()) {
|
|
107
|
+
button.setAttribute("role", "button");
|
|
108
|
+
button.removeAttribute("aria-selected");
|
|
109
|
+
if (!button.querySelector("[data-intel-navigation-icon]")) {
|
|
110
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
111
|
+
svg.dataset.intelNavigationIcon = "true";
|
|
112
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
113
|
+
svg.setAttribute("aria-hidden", "true");
|
|
114
|
+
const paths =
|
|
115
|
+
index === 0
|
|
116
|
+
? ["M8 6h13M8 12h13M8 18h13", "M3 6h.01M3 12h.01M3 18h.01"]
|
|
117
|
+
: ["M4 6h7M9 12h11M13 18h7", "M4 6v12h9M9 6v6M13 12v6"];
|
|
118
|
+
for (const pathData of paths) {
|
|
119
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
120
|
+
path.setAttribute("d", pathData);
|
|
121
|
+
svg.append(path);
|
|
122
|
+
}
|
|
123
|
+
button.prepend(svg);
|
|
124
|
+
}
|
|
125
|
+
if (button.dataset.intelNavigationAdapted !== "true") {
|
|
126
|
+
button.dataset.intelNavigationAdapted = "true";
|
|
127
|
+
button.addEventListener("click", () => {
|
|
128
|
+
if (root.activeElement === button) buttons[index === 0 ? 1 : 0]?.focus();
|
|
129
|
+
for (const tabButton of buttons) tabButton.removeAttribute("aria-selected");
|
|
130
|
+
});
|
|
131
|
+
}
|
|
116
132
|
}
|
|
117
|
-
button.prepend(svg);
|
|
118
133
|
}
|
|
119
134
|
};
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
let outlineObserver: MutationObserver;
|
|
136
|
+
let outlineTarget: HTMLElement | null = null;
|
|
137
|
+
const probeOutline = () => {
|
|
138
|
+
const tabs = root.querySelector<HTMLElement>(".pdf-nav-tabs");
|
|
139
|
+
const [pagesTab, outlineTab] = tabs?.querySelectorAll<HTMLButtonElement>("button") ?? [];
|
|
140
|
+
const navPane = root.querySelector<HTMLElement>(".pdf-nav-pane");
|
|
141
|
+
const navList = root.querySelector<HTMLElement>(".pdf-page-list,.pdf-outline-list");
|
|
142
|
+
if (!tabs || !pagesTab || !outlineTab || !navPane || !navList) return;
|
|
143
|
+
|
|
144
|
+
outlineObserver.disconnect();
|
|
145
|
+
const startedInOutline = outlineTab.classList.contains("active");
|
|
146
|
+
if (!startedInOutline) {
|
|
147
|
+
navPane.style.visibility = "hidden";
|
|
148
|
+
outlineTab.click();
|
|
149
|
+
}
|
|
150
|
+
tabs.dataset.outlineAvailable = String(root.querySelector(".pdf-outline-button") !== null);
|
|
151
|
+
if (!startedInOutline) pagesTab.click();
|
|
152
|
+
navPane.style.removeProperty("visibility");
|
|
153
|
+
adaptNavigation();
|
|
154
|
+
outlineTarget = navList;
|
|
155
|
+
outlineObserver.observe(navList, { childList: true });
|
|
156
|
+
};
|
|
157
|
+
adaptNavigation();
|
|
158
|
+
const observer = new MutationObserver(() => {
|
|
159
|
+
adaptNavigation();
|
|
160
|
+
if (!outlineTarget || !root.contains(outlineTarget)) probeOutline();
|
|
161
|
+
});
|
|
122
162
|
observer.observe(root, { childList: true, subtree: true });
|
|
123
|
-
|
|
163
|
+
outlineObserver = new MutationObserver(() => {
|
|
164
|
+
const tabs = root.querySelector<HTMLElement>(".pdf-nav-tabs");
|
|
165
|
+
if (tabs?.dataset.outlineAvailable !== "true") probeOutline();
|
|
166
|
+
});
|
|
167
|
+
// The pinned renderer exposes no outline count. Probe synchronously between paints, then let
|
|
168
|
+
// direct navigation-list mutations trigger another probe whenever a late outline read lands.
|
|
169
|
+
probeOutline();
|
|
170
|
+
return () => {
|
|
171
|
+
observer.disconnect();
|
|
172
|
+
outlineObserver.disconnect();
|
|
173
|
+
};
|
|
124
174
|
}, [state?.ready]);
|
|
125
175
|
|
|
126
176
|
useEffect(() => {
|
|
@@ -152,7 +202,7 @@ export function FilePreviewView({
|
|
|
152
202
|
</button>
|
|
153
203
|
</ActionSlot>
|
|
154
204
|
) : null}
|
|
155
|
-
<div className="absolute inset-
|
|
205
|
+
<div className="absolute inset-0 min-h-0">
|
|
156
206
|
<FileViewer
|
|
157
207
|
ref={viewer}
|
|
158
208
|
file={file}
|
|
@@ -165,7 +215,11 @@ export function FilePreviewView({
|
|
|
165
215
|
<div
|
|
166
216
|
role="toolbar"
|
|
167
217
|
aria-label={i18n.t("attachment.viewer.controls")}
|
|
168
|
-
className=
|
|
218
|
+
className={`absolute right-3 bottom-2 left-3 z-[5] mx-auto flex min-h-10 w-fit max-w-[calc(100%-1.5rem)] items-center gap-1 rounded-full border bg-background/80 p-1 shadow-lg backdrop-blur-md ${
|
|
219
|
+
viewState?.navigation?.visible
|
|
220
|
+
? "[@media(max-width:720px)]:hidden min-[721px]:left-[calc(6rem+0.75rem)]"
|
|
221
|
+
: ""
|
|
222
|
+
}`}
|
|
169
223
|
>
|
|
170
224
|
<span role="status" aria-live="polite" aria-atomic="true" className="sr-only">
|
|
171
225
|
{search?.query
|