@uipath/apollo-vertex 1.3.0 → 1.4.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/dist/lib/i18n.d.ts +8 -0
- package/dist/locales/en.json +4 -0
- package/dist/registry/shell/shell-company.js +2 -1
- package/dist/registry/shell/shell-locale-provider.d.ts +2 -1
- package/dist/registry/shell/shell-locale-provider.js +12 -8
- package/dist/registry/shell/shell-minimal-nav-item.d.ts +4 -3
- package/dist/registry/shell/shell-minimal-nav-item.js +3 -7
- package/dist/registry/shell/shell-nav-active.d.ts +12 -0
- package/dist/registry/shell/shell-nav-active.js +24 -0
- package/dist/registry/shell/shell-nav-label.d.ts +7 -0
- package/dist/registry/shell/shell-nav-label.js +54 -0
- package/dist/registry/shell/shell-sidebar.js +126 -114
- package/dist/registry/shell/shell-text.d.ts +2 -2
- package/dist/registry/shell/shell-text.js +3 -2
- package/dist/registry/shell/shell-translation-key.d.ts +5 -0
- package/dist/registry/shell/shell.d.ts +6 -3
- package/dist/registry/shell/shell.js +18 -13
- package/package.json +1 -1
package/dist/lib/i18n.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare const localeLoaders: {
|
|
|
6
6
|
access_denied: string;
|
|
7
7
|
access_denied_description: string;
|
|
8
8
|
actions: string;
|
|
9
|
+
active: string;
|
|
9
10
|
actual_input: string;
|
|
10
11
|
actual_output: string;
|
|
11
12
|
add_attachment: string;
|
|
@@ -27,6 +28,7 @@ declare const localeLoaders: {
|
|
|
27
28
|
analytics: string;
|
|
28
29
|
apollo_vertex: string;
|
|
29
30
|
apollo_vertex_description: string;
|
|
31
|
+
archive: string;
|
|
30
32
|
are_you_sure: string;
|
|
31
33
|
asc: string;
|
|
32
34
|
ask_ai: string;
|
|
@@ -189,6 +191,8 @@ declare const localeLoaders: {
|
|
|
189
191
|
more_pages: string;
|
|
190
192
|
multi_line_too_few_metrics: string;
|
|
191
193
|
my_template: string;
|
|
194
|
+
nav_collapse: string;
|
|
195
|
+
nav_expand: string;
|
|
192
196
|
need_help: string;
|
|
193
197
|
new_conversation: string;
|
|
194
198
|
new_conversation_confirm_description: string;
|
|
@@ -373,6 +377,7 @@ declare const localeLoaders: {
|
|
|
373
377
|
access_denied: string;
|
|
374
378
|
access_denied_description: string;
|
|
375
379
|
actions: string;
|
|
380
|
+
active: string;
|
|
376
381
|
actual_input: string;
|
|
377
382
|
actual_output: string;
|
|
378
383
|
add_attachment: string;
|
|
@@ -394,6 +399,7 @@ declare const localeLoaders: {
|
|
|
394
399
|
analytics: string;
|
|
395
400
|
apollo_vertex: string;
|
|
396
401
|
apollo_vertex_description: string;
|
|
402
|
+
archive: string;
|
|
397
403
|
are_you_sure: string;
|
|
398
404
|
asc: string;
|
|
399
405
|
ask_ai: string;
|
|
@@ -556,6 +562,8 @@ declare const localeLoaders: {
|
|
|
556
562
|
more_pages: string;
|
|
557
563
|
multi_line_too_few_metrics: string;
|
|
558
564
|
my_template: string;
|
|
565
|
+
nav_collapse: string;
|
|
566
|
+
nav_expand: string;
|
|
559
567
|
need_help: string;
|
|
560
568
|
new_conversation: string;
|
|
561
569
|
new_conversation_confirm_description: string;
|
package/dist/locales/en.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"access_denied": "Access Denied",
|
|
4
4
|
"access_denied_description": "You don't have access to this application. Ask your administrator to add you to the users group.",
|
|
5
5
|
"actions": "Actions",
|
|
6
|
+
"active": "Active",
|
|
6
7
|
"actual_input": "Actual input",
|
|
7
8
|
"actual_output": "Actual output",
|
|
8
9
|
"add_attachment": "Add attachment",
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"analytics": "Analytics",
|
|
25
26
|
"apollo_vertex": "Apollo Vertex",
|
|
26
27
|
"apollo_vertex_description": "- UiPath Apollo Vertex",
|
|
28
|
+
"archive": "Archive",
|
|
27
29
|
"are_you_sure": "Are you sure?",
|
|
28
30
|
"asc": "Asc",
|
|
29
31
|
"ask_ai": "Ask AI",
|
|
@@ -186,6 +188,8 @@
|
|
|
186
188
|
"more_pages": "More pages",
|
|
187
189
|
"multi_line_too_few_metrics": "Multi-line needs two distinct metrics, but the request resolved to fewer than two.",
|
|
188
190
|
"my_template": "My Template",
|
|
191
|
+
"nav_collapse": "Collapse {{label}}",
|
|
192
|
+
"nav_expand": "Expand {{label}}",
|
|
189
193
|
"need_help": "Need help? Contact your administrator",
|
|
190
194
|
"new_conversation": "New conversation",
|
|
191
195
|
"new_conversation_confirm_description": "This will clear all messages and cannot be undone.",
|
|
@@ -3,11 +3,11 @@ import { Link } from "@tanstack/react-router";
|
|
|
3
3
|
import { AnimatePresence, motion } from "framer-motion";
|
|
4
4
|
import { PanelLeft } from "lucide-react";
|
|
5
5
|
import { useState } from "react";
|
|
6
|
-
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
7
6
|
import { Button } from "../button/button.js";
|
|
8
7
|
import { useSidebar } from "../sidebar/sidebar.js";
|
|
9
8
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../tooltip/tooltip.js";
|
|
10
9
|
import { cn } from "../../lib/utils.js";
|
|
10
|
+
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
11
11
|
import { fastFadeTransition, iconHoverScale, scaleVariants, textFadeVariants } from "./shell-animations.js";
|
|
12
12
|
import { CompanyLogoIcon } from "./shell-company-logo.js";
|
|
13
13
|
function CollapsedLogo({ companyLogo, sidebarHovered, onExpand }) {
|
|
@@ -162,6 +162,7 @@ const Company = ({ companyName, productName, companyLogo, sidebarHovered = false
|
|
|
162
162
|
children: /*#__PURE__*/ jsx(Button, {
|
|
163
163
|
variant: "ghost",
|
|
164
164
|
size: "icon-sm",
|
|
165
|
+
"aria-label": t("close_sidebar"),
|
|
165
166
|
onClick: toggleSidebar,
|
|
166
167
|
className: "ml-auto shrink-0 text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-foreground cursor-pointer",
|
|
167
168
|
children: /*#__PURE__*/ jsx(PanelLeft, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type PropsWithChildren, type ReactNode } from "react";
|
|
2
2
|
interface LocaleProviderProps {
|
|
3
3
|
loadingElement?: ReactNode;
|
|
4
|
+
configureI18n?: () => Promise<void>;
|
|
4
5
|
}
|
|
5
6
|
export declare const LocaleProviderComponent: ({ children }: PropsWithChildren) => ReactNode;
|
|
6
|
-
export declare const LocaleProvider: ({ children, loadingElement, }: PropsWithChildren<LocaleProviderProps>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const LocaleProvider: ({ children, loadingElement, configureI18n, }: PropsWithChildren<LocaleProviderProps>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useEffectEvent, useState } from "react";
|
|
4
|
-
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
5
4
|
import { Spinner } from "../spinner/spinner.js";
|
|
6
5
|
import { configurei18n } from "../../lib/i18n.js";
|
|
6
|
+
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
7
7
|
import { LANGUAGE_CHANGED_EVENT } from "./shell-constants.js";
|
|
8
8
|
const LocaleProviderComponent = ({ children })=>{
|
|
9
9
|
const { i18n } = useVertexTranslation();
|
|
@@ -21,15 +21,19 @@ const LocaleProviderComponent = ({ children })=>{
|
|
|
21
21
|
}, []);
|
|
22
22
|
return children;
|
|
23
23
|
};
|
|
24
|
-
const LocaleProvider = ({ children, loadingElement })=>{
|
|
24
|
+
const LocaleProvider = ({ children, loadingElement, configureI18n = configurei18n })=>{
|
|
25
25
|
const [isConfigured, setIsConfigured] = useState(false);
|
|
26
|
-
const configure = async ()=>{
|
|
27
|
-
await configurei18n();
|
|
28
|
-
setIsConfigured(true);
|
|
29
|
-
};
|
|
30
26
|
useEffect(()=>{
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
let cancelled = false;
|
|
28
|
+
configureI18n().then(()=>{
|
|
29
|
+
if (!cancelled) setIsConfigured(true);
|
|
30
|
+
});
|
|
31
|
+
return ()=>{
|
|
32
|
+
cancelled = true;
|
|
33
|
+
};
|
|
34
|
+
}, [
|
|
35
|
+
configureI18n
|
|
36
|
+
]);
|
|
33
37
|
if (!isConfigured) return loadingElement ?? /*#__PURE__*/ jsx("div", {
|
|
34
38
|
className: "flex h-full w-full items-center justify-center",
|
|
35
39
|
children: /*#__PURE__*/ jsx(Spinner, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ShellNavLabel } from "./shell-translation-key";
|
|
2
2
|
interface MinimalNavItemProps {
|
|
3
3
|
to: string;
|
|
4
|
-
|
|
4
|
+
active: boolean;
|
|
5
|
+
label: ShellNavLabel;
|
|
5
6
|
}
|
|
6
|
-
export declare const MinimalNavItem: ({ to, label }: MinimalNavItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const MinimalNavItem: ({ to, active, label }: MinimalNavItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
export {};
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Link
|
|
2
|
+
import { Link } from "@tanstack/react-router";
|
|
3
3
|
import { cn } from "../../lib/utils.js";
|
|
4
4
|
import { Text } from "./shell-text.js";
|
|
5
|
-
const MinimalNavItem = ({ to, label })
|
|
6
|
-
const { pathname } = useLocation();
|
|
7
|
-
const isActive = pathname === to;
|
|
8
|
-
return /*#__PURE__*/ jsx(Link, {
|
|
5
|
+
const MinimalNavItem = ({ to, active, label })=>/*#__PURE__*/ jsx(Link, {
|
|
9
6
|
to: to,
|
|
10
|
-
className: cn("px-4 py-1.5 rounded-full text-sm font-medium transition-colors duration-200 shrink-0 whitespace-nowrap",
|
|
7
|
+
className: cn("px-4 py-1.5 rounded-full text-sm font-medium transition-colors duration-200 shrink-0 whitespace-nowrap", active ? "bg-[oklch(0.92_0.035_218)] dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 font-semibold" : "text-muted-foreground hover:text-foreground hover:bg-black/[0.04] dark:hover:bg-white/[0.06]"),
|
|
11
8
|
children: /*#__PURE__*/ jsx(Text, {
|
|
12
9
|
value: label
|
|
13
10
|
})
|
|
14
11
|
});
|
|
15
|
-
};
|
|
16
12
|
export { MinimalNavItem };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function navPathIsActive(pathname: string, path: string): boolean;
|
|
2
|
+
export declare function navItemIsCurrent(pathname: string, path: string, childPaths?: readonly string[]): boolean;
|
|
3
|
+
export declare function mostSpecificActivePath(pathname: string, paths: readonly string[]): string | null;
|
|
4
|
+
export declare function navItemState(pathname: string, item: {
|
|
5
|
+
path: string;
|
|
6
|
+
to?: string;
|
|
7
|
+
childPaths?: readonly string[];
|
|
8
|
+
}): {
|
|
9
|
+
href: string;
|
|
10
|
+
prefixActive: boolean;
|
|
11
|
+
current: boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function navPathIsActive(pathname, path) {
|
|
2
|
+
if ("/" === path) return "/" === pathname;
|
|
3
|
+
return pathname === path || pathname.startsWith(`${path}/`);
|
|
4
|
+
}
|
|
5
|
+
function navItemIsCurrent(pathname, path, childPaths = []) {
|
|
6
|
+
return navPathIsActive(pathname, path) && !childPaths.some((childPath)=>navPathIsActive(pathname, childPath));
|
|
7
|
+
}
|
|
8
|
+
function mostSpecificActivePath(pathname, paths) {
|
|
9
|
+
let match = null;
|
|
10
|
+
for (const path of paths)if (navPathIsActive(pathname, path)) {
|
|
11
|
+
if (null === match || path.length > match.length) match = path;
|
|
12
|
+
}
|
|
13
|
+
return match;
|
|
14
|
+
}
|
|
15
|
+
function navItemState(pathname, item) {
|
|
16
|
+
const childPaths = item.childPaths ?? [];
|
|
17
|
+
const childActive = childPaths.some((childPath)=>navPathIsActive(pathname, childPath));
|
|
18
|
+
return {
|
|
19
|
+
href: item.to ?? item.path,
|
|
20
|
+
prefixActive: navPathIsActive(pathname, item.path) || childActive,
|
|
21
|
+
current: navItemIsCurrent(pathname, item.path, childPaths)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export { mostSpecificActivePath, navItemIsCurrent, navItemState, navPathIsActive };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface NavCatalog {
|
|
2
|
+
namespaces: readonly string[];
|
|
3
|
+
exists: (key: string, namespace: string) => boolean;
|
|
4
|
+
translate: (key: string, namespace: string) => string;
|
|
5
|
+
}
|
|
6
|
+
export declare function navCatalogFromHook(i18n: object): NavCatalog;
|
|
7
|
+
export declare function readNavLabel(catalog: NavCatalog, key: string): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { VERTEX_NAMESPACE } from "../../lib/vertex-translation.js";
|
|
2
|
+
function configuredNamespaces(defaultNS) {
|
|
3
|
+
if ("string" == typeof defaultNS) return defaultNS.length > 0 ? [
|
|
4
|
+
defaultNS
|
|
5
|
+
] : [
|
|
6
|
+
"translation"
|
|
7
|
+
];
|
|
8
|
+
if (!Array.isArray(defaultNS)) return [
|
|
9
|
+
"translation"
|
|
10
|
+
];
|
|
11
|
+
const namespaces = [];
|
|
12
|
+
for (const namespace of defaultNS)if ("string" == typeof namespace && namespace.length > 0) namespaces.push(namespace);
|
|
13
|
+
return namespaces.length > 0 ? namespaces : [
|
|
14
|
+
"translation"
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
function lookupNamespaces(defaultNS) {
|
|
18
|
+
const configured = configuredNamespaces(defaultNS);
|
|
19
|
+
if (configured.includes(VERTEX_NAMESPACE)) return configured;
|
|
20
|
+
return [
|
|
21
|
+
...configured,
|
|
22
|
+
VERTEX_NAMESPACE
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function isNamespacedI18n(value) {
|
|
26
|
+
return "options" in value && "exists" in value && "function" == typeof value.exists && "t" in value && "function" == typeof value.t;
|
|
27
|
+
}
|
|
28
|
+
function navCatalogFromHook(i18n) {
|
|
29
|
+
if (!isNamespacedI18n(i18n)) return {
|
|
30
|
+
namespaces: [
|
|
31
|
+
"translation",
|
|
32
|
+
VERTEX_NAMESPACE
|
|
33
|
+
],
|
|
34
|
+
exists: ()=>false,
|
|
35
|
+
translate: (key)=>key
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
namespaces: lookupNamespaces(i18n.options.defaultNS),
|
|
39
|
+
exists: (key, namespace)=>i18n.exists(key, {
|
|
40
|
+
ns: namespace
|
|
41
|
+
}),
|
|
42
|
+
translate: (key, namespace)=>{
|
|
43
|
+
const value = i18n.t(key, {
|
|
44
|
+
ns: namespace
|
|
45
|
+
});
|
|
46
|
+
return "string" == typeof value ? value : key;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function readNavLabel(catalog, key) {
|
|
51
|
+
for (const namespace of catalog.namespaces)if (catalog.exists(key, namespace)) return catalog.translate(key, namespace);
|
|
52
|
+
return key;
|
|
53
|
+
}
|
|
54
|
+
export { navCatalogFromHook, readNavLabel };
|
|
@@ -4,45 +4,54 @@ import { Link, useLocation } from "@tanstack/react-router";
|
|
|
4
4
|
import { AnimatePresence, motion } from "framer-motion";
|
|
5
5
|
import { ChevronDown } from "lucide-react";
|
|
6
6
|
import { useEffect, useState } from "react";
|
|
7
|
-
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
8
7
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../collapsible/collapsible.js";
|
|
9
8
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, useSidebar } from "../sidebar/sidebar.js";
|
|
10
9
|
import { cn } from "../../lib/utils.js";
|
|
10
|
+
import { useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
11
11
|
import { fastFadeTransition, iconHoverScale, textFadeVariants } from "./shell-animations.js";
|
|
12
12
|
import { Company } from "./shell-company.js";
|
|
13
13
|
import { MinimalCompany } from "./shell-minimal-company.js";
|
|
14
14
|
import { MinimalNavItem } from "./shell-minimal-nav-item.js";
|
|
15
|
+
import { mostSpecificActivePath, navItemState } from "./shell-nav-active.js";
|
|
16
|
+
import { navCatalogFromHook, readNavLabel } from "./shell-nav-label.js";
|
|
15
17
|
import { Text } from "./shell-text.js";
|
|
16
18
|
import { UserProfile } from "./shell-user-profile.js";
|
|
17
19
|
const activeNavClass = "text-sidebar-foreground/85 hover:text-sidebar-foreground data-[active=true]:text-primary-700 dark:data-[active=true]:text-primary-400 data-[active=true]:font-semibold data-[active=true]:bg-primary-100/40 dark:data-[active=true]:bg-primary-900/30";
|
|
18
20
|
const navButtonClass = `font-medium ${activeNavClass}`;
|
|
19
21
|
const subButtonClass = activeNavClass;
|
|
22
|
+
const prefixActiveClass = "font-semibold text-primary-700 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-400 active:text-primary-700 dark:active:text-primary-400";
|
|
23
|
+
const currentPillClass = "bg-primary-100/40 dark:bg-primary-900/30";
|
|
20
24
|
const ShellSidebar = ({ companyName, productName, variant, companyLogo, navItems })=>{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
const { pathname } = useLocation();
|
|
26
|
+
if ("minimal" === variant) {
|
|
27
|
+
const activePath = mostSpecificActivePath(pathname, navItems.map((item)=>item.path));
|
|
28
|
+
return /*#__PURE__*/ jsxs("header", {
|
|
29
|
+
className: "relative flex items-center justify-between px-4 sm:px-6 lg:px-8 py-6 transition-[padding] duration-300 ease-in-out",
|
|
30
|
+
children: [
|
|
31
|
+
/*#__PURE__*/ jsx(MinimalCompany, {
|
|
32
|
+
companyName: companyName,
|
|
33
|
+
productName: productName,
|
|
34
|
+
companyLogo: companyLogo
|
|
35
|
+
}),
|
|
36
|
+
navItems.length > 0 && /*#__PURE__*/ jsx("nav", {
|
|
37
|
+
className: "absolute left-1/2 -translate-x-1/2 flex items-center bg-muted dark:bg-[oklch(0.24_0.033_254)] rounded-full p-1.5 overflow-x-auto scrollbar-thin",
|
|
38
|
+
children: navItems.map((item)=>/*#__PURE__*/ jsx(MinimalNavItem, {
|
|
39
|
+
to: item.to ?? item.path,
|
|
40
|
+
active: item.path === activePath,
|
|
41
|
+
label: item.label
|
|
42
|
+
}, item.path))
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ jsx("div", {
|
|
45
|
+
className: "flex items-center gap-2",
|
|
46
|
+
children: /*#__PURE__*/ jsx(UserProfile, {
|
|
47
|
+
isCollapsed: true,
|
|
48
|
+
collapsedMenuSide: "bottom",
|
|
49
|
+
collapsedMenuAlign: "end"
|
|
50
|
+
})
|
|
42
51
|
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
46
55
|
return /*#__PURE__*/ jsx(SidebarNav, {
|
|
47
56
|
companyName: companyName,
|
|
48
57
|
productName: productName,
|
|
@@ -51,8 +60,9 @@ const ShellSidebar = ({ companyName, productName, variant, companyLogo, navItems
|
|
|
51
60
|
});
|
|
52
61
|
};
|
|
53
62
|
function SidebarNav({ companyName, productName, companyLogo, navItems }) {
|
|
54
|
-
const { t } = useVertexTranslation();
|
|
55
|
-
const
|
|
63
|
+
const { t, i18n } = useVertexTranslation();
|
|
64
|
+
const catalog = navCatalogFromHook(i18n);
|
|
65
|
+
const { state } = useSidebar();
|
|
56
66
|
const { pathname } = useLocation();
|
|
57
67
|
const isCollapsed = "collapsed" === state;
|
|
58
68
|
const [sidebarHovered, setSidebarHovered] = useState(false);
|
|
@@ -75,24 +85,16 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
|
|
|
75
85
|
pathname,
|
|
76
86
|
navItems
|
|
77
87
|
]);
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
toggleSidebar();
|
|
81
|
-
setExpandedItems((prev)=>new Set(prev).add(path));
|
|
82
|
-
} else setExpandedItems((prev)=>{
|
|
88
|
+
const toggleGroup = (path)=>{
|
|
89
|
+
setExpandedItems((prev)=>{
|
|
83
90
|
const next = new Set(prev);
|
|
84
91
|
if (next.has(path)) next.delete(path);
|
|
85
92
|
else next.add(path);
|
|
86
93
|
return next;
|
|
87
94
|
});
|
|
88
95
|
};
|
|
89
|
-
const isActive = (path)=>{
|
|
90
|
-
if ("/" === path) return "/" === pathname;
|
|
91
|
-
return pathname === path || pathname.startsWith(`${path}/`);
|
|
92
|
-
};
|
|
93
|
-
const isParentActive = (item)=>item.subItems?.some((sub)=>isActive(sub.path)) ?? false;
|
|
94
96
|
const getTooltipText = (label)=>{
|
|
95
|
-
if ("string" == typeof label) return
|
|
97
|
+
if ("string" == typeof label) return readNavLabel(catalog, label);
|
|
96
98
|
return t(label.i18nKey, label.values);
|
|
97
99
|
};
|
|
98
100
|
return /*#__PURE__*/ jsxs(Sidebar, {
|
|
@@ -119,97 +121,107 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
|
|
|
119
121
|
children: /*#__PURE__*/ jsx(SidebarMenu, {
|
|
120
122
|
children: navItems.map((item)=>{
|
|
121
123
|
const Icon = item.icon;
|
|
122
|
-
const active = isActive(item.path);
|
|
123
|
-
const parentActive = isParentActive(item);
|
|
124
124
|
const isExpanded = expandedItems.has(item.path);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
125
|
+
const childPaths = item.subItems?.map((sub)=>sub.path) ?? [];
|
|
126
|
+
const row = navItemState(pathname, {
|
|
127
|
+
path: item.path,
|
|
128
|
+
to: item.to,
|
|
129
|
+
childPaths
|
|
130
|
+
});
|
|
131
|
+
if (item.subItems && item.subItems.length > 0) return /*#__PURE__*/ jsx(Collapsible, {
|
|
132
|
+
open: isExpanded && !isCollapsed,
|
|
133
|
+
onOpenChange: ()=>toggleGroup(item.path),
|
|
134
|
+
className: "group/collapsible",
|
|
135
|
+
children: /*#__PURE__*/ jsxs(SidebarMenuItem, {
|
|
136
|
+
children: [
|
|
137
|
+
/*#__PURE__*/ jsxs("div", {
|
|
138
|
+
className: cn("flex w-full min-w-0 items-center rounded-md", !isCollapsed && row.current && currentPillClass, !isCollapsed && !row.current && "hover:bg-sidebar-accent/50"),
|
|
139
|
+
children: [
|
|
140
|
+
/*#__PURE__*/ jsx(SidebarMenuButton, {
|
|
141
|
+
asChild: true,
|
|
136
142
|
tooltip: getTooltipText(item.label),
|
|
137
|
-
isActive:
|
|
138
|
-
className: navButtonClass,
|
|
139
|
-
children:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
/*#__PURE__*/ jsx(AnimatePresence, {
|
|
150
|
-
initial: false,
|
|
151
|
-
children: !isCollapsed && /*#__PURE__*/ jsx(motion.span, {
|
|
152
|
-
variants: textFadeVariants,
|
|
153
|
-
initial: "initial",
|
|
154
|
-
animate: "animate",
|
|
155
|
-
exit: "exit",
|
|
156
|
-
transition: fastFadeTransition,
|
|
157
|
-
className: "whitespace-nowrap truncate",
|
|
158
|
-
children: /*#__PURE__*/ jsx(Text, {
|
|
159
|
-
value: item.label
|
|
143
|
+
isActive: isCollapsed && row.current,
|
|
144
|
+
className: cn(navButtonClass, row.prefixActive && prefixActiveClass, !isCollapsed && "w-auto min-w-0 flex-1 bg-transparent hover:bg-transparent"),
|
|
145
|
+
children: /*#__PURE__*/ jsxs(Link, {
|
|
146
|
+
to: row.href,
|
|
147
|
+
children: [
|
|
148
|
+
/*#__PURE__*/ jsx(motion.span, {
|
|
149
|
+
className: "inline-flex items-center justify-center shrink-0",
|
|
150
|
+
...isCollapsed ? {
|
|
151
|
+
whileHover: iconHoverScale
|
|
152
|
+
} : {},
|
|
153
|
+
children: /*#__PURE__*/ jsx(Icon, {
|
|
154
|
+
className: "size-4 shrink-0"
|
|
160
155
|
})
|
|
161
|
-
},
|
|
156
|
+
}),
|
|
157
|
+
/*#__PURE__*/ jsx(AnimatePresence, {
|
|
158
|
+
initial: false,
|
|
159
|
+
children: !isCollapsed && /*#__PURE__*/ jsx(motion.span, {
|
|
160
|
+
variants: textFadeVariants,
|
|
161
|
+
initial: "initial",
|
|
162
|
+
animate: "animate",
|
|
163
|
+
exit: "exit",
|
|
164
|
+
transition: fastFadeTransition,
|
|
165
|
+
className: "whitespace-nowrap truncate",
|
|
166
|
+
children: /*#__PURE__*/ jsx(Text, {
|
|
167
|
+
value: item.label
|
|
168
|
+
})
|
|
169
|
+
}, "text")
|
|
170
|
+
})
|
|
171
|
+
]
|
|
172
|
+
})
|
|
173
|
+
}),
|
|
174
|
+
!isCollapsed && /*#__PURE__*/ jsx(CollapsibleTrigger, {
|
|
175
|
+
asChild: true,
|
|
176
|
+
children: /*#__PURE__*/ jsx("button", {
|
|
177
|
+
type: "button",
|
|
178
|
+
"aria-expanded": isExpanded,
|
|
179
|
+
"aria-label": t(isExpanded ? "nav_collapse" : "nav_expand", {
|
|
180
|
+
label: getTooltipText(item.label)
|
|
162
181
|
}),
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
variants: textFadeVariants,
|
|
167
|
-
initial: "initial",
|
|
168
|
-
animate: "animate",
|
|
169
|
-
exit: "exit",
|
|
170
|
-
transition: fastFadeTransition,
|
|
171
|
-
className: "ml-auto",
|
|
172
|
-
children: /*#__PURE__*/ jsx(ChevronDown, {
|
|
173
|
-
className: cn("size-4 transition-transform duration-200", isExpanded && "rotate-180")
|
|
174
|
-
})
|
|
175
|
-
}, "chevron")
|
|
182
|
+
className: "flex size-8 shrink-0 items-center justify-center text-sidebar-foreground/70 hover:text-sidebar-foreground",
|
|
183
|
+
children: /*#__PURE__*/ jsx(ChevronDown, {
|
|
184
|
+
className: cn("size-4 transition-transform duration-200", isExpanded && "rotate-180")
|
|
176
185
|
})
|
|
177
|
-
|
|
186
|
+
})
|
|
178
187
|
})
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
]
|
|
189
|
+
}),
|
|
190
|
+
/*#__PURE__*/ jsx(CollapsibleContent, {
|
|
191
|
+
children: /*#__PURE__*/ jsx(SidebarMenuSub, {
|
|
192
|
+
className: "ml-4 mr-0 mt-1 gap-0.5 pl-3 pr-0",
|
|
193
|
+
children: item.subItems.map((subItem)=>{
|
|
194
|
+
const sub = navItemState(pathname, {
|
|
195
|
+
path: subItem.path,
|
|
196
|
+
to: subItem.to
|
|
197
|
+
});
|
|
198
|
+
return /*#__PURE__*/ jsx(SidebarMenuSubItem, {
|
|
199
|
+
children: /*#__PURE__*/ jsx(SidebarMenuSubButton, {
|
|
200
|
+
asChild: true,
|
|
201
|
+
isActive: sub.current,
|
|
202
|
+
className: cn("cursor-pointer whitespace-nowrap", subButtonClass),
|
|
203
|
+
children: /*#__PURE__*/ jsx(Link, {
|
|
204
|
+
to: sub.href,
|
|
205
|
+
children: /*#__PURE__*/ jsx(Text, {
|
|
206
|
+
value: subItem.label
|
|
195
207
|
})
|
|
196
208
|
})
|
|
197
|
-
}
|
|
198
|
-
})
|
|
209
|
+
})
|
|
210
|
+
}, subItem.path);
|
|
199
211
|
})
|
|
200
212
|
})
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
}
|
|
213
|
+
})
|
|
214
|
+
]
|
|
215
|
+
})
|
|
216
|
+
}, item.path);
|
|
205
217
|
return /*#__PURE__*/ jsx(SidebarMenuItem, {
|
|
206
218
|
children: /*#__PURE__*/ jsx(SidebarMenuButton, {
|
|
207
219
|
tooltip: getTooltipText(item.label),
|
|
208
|
-
isActive:
|
|
220
|
+
isActive: row.current,
|
|
209
221
|
asChild: true,
|
|
210
222
|
className: navButtonClass,
|
|
211
223
|
children: /*#__PURE__*/ jsxs(Link, {
|
|
212
|
-
to:
|
|
224
|
+
to: row.href,
|
|
213
225
|
children: [
|
|
214
226
|
/*#__PURE__*/ jsx(motion.span, {
|
|
215
227
|
className: "inline-flex items-center justify-center shrink-0",
|
|
@@ -252,7 +264,7 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
|
|
|
252
264
|
/*#__PURE__*/ jsx("div", {
|
|
253
265
|
className: "absolute inset-0 pointer-events-none",
|
|
254
266
|
style: {
|
|
255
|
-
boxShadow: "inset -1px 0 0 0 color-mix(in srgb, var(--
|
|
267
|
+
boxShadow: "inset -1px 0 0 0 color-mix(in srgb, var(--border) 50%, transparent)"
|
|
256
268
|
}
|
|
257
269
|
})
|
|
258
270
|
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ShellNavLabel } from "./shell-translation-key";
|
|
2
2
|
export declare const Text: ({ value }: {
|
|
3
|
-
value:
|
|
3
|
+
value: ShellNavLabel;
|
|
4
4
|
}) => string | import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Trans } from "react-i18next";
|
|
3
3
|
import { VERTEX_NAMESPACE, useVertexTranslation } from "../../lib/vertex-translation.js";
|
|
4
|
+
import { navCatalogFromHook, readNavLabel } from "./shell-nav-label.js";
|
|
4
5
|
const Text = ({ value })=>{
|
|
5
|
-
const {
|
|
6
|
-
if ("string" == typeof value) return
|
|
6
|
+
const { i18n } = useVertexTranslation();
|
|
7
|
+
if ("string" == typeof value) return readNavLabel(navCatalogFromHook(i18n), value);
|
|
7
8
|
return /*#__PURE__*/ jsx(Trans, {
|
|
8
9
|
ns: VERTEX_NAMESPACE,
|
|
9
10
|
i18nKey: value.i18nKey,
|
|
@@ -5,3 +5,8 @@ export type TranslationKey = {
|
|
|
5
5
|
values: Record<string, string | number | string[]>;
|
|
6
6
|
components: Record<string, ReactElement>;
|
|
7
7
|
} | ParseKeys;
|
|
8
|
+
type TranslationObject = Extract<TranslationKey, {
|
|
9
|
+
i18nKey: ParseKeys;
|
|
10
|
+
}>;
|
|
11
|
+
export type ShellNavLabel = string | TranslationObject;
|
|
12
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { LucideIcon } from "lucide-react";
|
|
2
2
|
import type { FC, PropsWithChildren } from "react";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ShellNavLabel } from "./shell-translation-key";
|
|
4
4
|
export interface CompanyLogo {
|
|
5
5
|
url: string;
|
|
6
6
|
darkUrl?: string;
|
|
@@ -9,11 +9,13 @@ export interface CompanyLogo {
|
|
|
9
9
|
}
|
|
10
10
|
export interface ShellSubNavItem {
|
|
11
11
|
path: string;
|
|
12
|
-
|
|
12
|
+
to?: string;
|
|
13
|
+
label: ShellNavLabel;
|
|
13
14
|
}
|
|
14
15
|
export interface ShellNavItem {
|
|
15
16
|
path: string;
|
|
16
|
-
|
|
17
|
+
to?: string;
|
|
18
|
+
label: ShellNavLabel;
|
|
17
19
|
icon: LucideIcon;
|
|
18
20
|
subItems?: ShellSubNavItem[];
|
|
19
21
|
}
|
|
@@ -24,5 +26,6 @@ export interface ApolloShellProps extends PropsWithChildren {
|
|
|
24
26
|
companyLogo?: CompanyLogo;
|
|
25
27
|
navItems: ShellNavItem[];
|
|
26
28
|
loginDescription?: string;
|
|
29
|
+
configureI18n?: () => Promise<void>;
|
|
27
30
|
}
|
|
28
31
|
export declare const ApolloShell: FC<ApolloShellProps>;
|
|
@@ -7,9 +7,23 @@ import { ShellLayout } from "./shell-layout.js";
|
|
|
7
7
|
import { LocaleProvider } from "./shell-locale-provider.js";
|
|
8
8
|
import { ShellLogin } from "./shell-login.js";
|
|
9
9
|
import { ShellUserProvider } from "./shell-user-provider.js";
|
|
10
|
+
function ShellLoadingSkeleton() {
|
|
11
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
12
|
+
className: "flex h-screen gap-4 p-4 bg-background dark:bg-sidebar",
|
|
13
|
+
children: [
|
|
14
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
15
|
+
className: "h-full w-[280px]"
|
|
16
|
+
}),
|
|
17
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
18
|
+
className: "h-full flex-1 rounded-lg"
|
|
19
|
+
})
|
|
20
|
+
]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
10
23
|
const ApolloShellContent = ({ children, companyName, productName, companyLogo, variant, navItems, loginDescription })=>{
|
|
11
24
|
const authContext = useContext(AuthContext);
|
|
12
|
-
const { accessToken } = useAuth();
|
|
25
|
+
const { accessToken, isLoading } = useAuth();
|
|
26
|
+
if (authContext && isLoading) return /*#__PURE__*/ jsx(ShellLoadingSkeleton, {});
|
|
13
27
|
if (authContext && !accessToken) return /*#__PURE__*/ jsx(ShellLogin, {
|
|
14
28
|
title: productName,
|
|
15
29
|
description: loginDescription
|
|
@@ -25,18 +39,9 @@ const ApolloShellContent = ({ children, companyName, productName, companyLogo, v
|
|
|
25
39
|
})
|
|
26
40
|
});
|
|
27
41
|
};
|
|
28
|
-
const ApolloShell = ({ children, companyName, productName, companyLogo, variant, navItems, loginDescription })=>/*#__PURE__*/ jsx(LocaleProvider, {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
children: [
|
|
32
|
-
/*#__PURE__*/ jsx(Skeleton, {
|
|
33
|
-
className: "h-full w-[280px]"
|
|
34
|
-
}),
|
|
35
|
-
/*#__PURE__*/ jsx(Skeleton, {
|
|
36
|
-
className: "h-full flex-1 rounded-lg"
|
|
37
|
-
})
|
|
38
|
-
]
|
|
39
|
-
}),
|
|
42
|
+
const ApolloShell = ({ children, companyName, productName, companyLogo, variant, navItems, loginDescription, configureI18n })=>/*#__PURE__*/ jsx(LocaleProvider, {
|
|
43
|
+
configureI18n: configureI18n,
|
|
44
|
+
loadingElement: /*#__PURE__*/ jsx(ShellLoadingSkeleton, {}),
|
|
40
45
|
children: /*#__PURE__*/ jsx(ApolloShellContent, {
|
|
41
46
|
companyName: companyName,
|
|
42
47
|
productName: productName,
|