@veluai/velu 0.2.47 → 0.2.49
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/cli.js +51 -46
- package/docs/mintlify-migration.md +4 -2
- package/package.json +1 -1
- package/runtime/velu-ui/components/ApiReferencePage.jsx +46 -18
- package/runtime/velu-ui/components/CodeBlock.jsx +222 -39
- package/runtime/velu-ui/components/code-block.css +125 -6
- package/runtime/velu-ui/index.js +11 -0
- package/runtime/velu-ui/lib/page-feedback.js +22 -2
- package/runtime/velu-ui/lib/reader-user.js +135 -0
- package/runtime/velu-ui/themes/thulir.css +3 -1
- package/src/navigation.js +4 -0
- package/src/runtime/App.jsx +119 -8
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/** Identified-reader personalization (Mintlify-compatible `user` + playground). */
|
|
2
|
+
|
|
3
|
+
export function emptyReaderIdentity() {
|
|
4
|
+
return { user: {}, groups: [], apiPlaygroundInputs: {} };
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function identityFromUserData(data) {
|
|
8
|
+
const empty = emptyReaderIdentity();
|
|
9
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) return empty;
|
|
10
|
+
if (typeof data.expiresAt === 'number' && data.expiresAt * 1000 <= Date.now()) return empty;
|
|
11
|
+
const groups = Array.isArray(data.groups)
|
|
12
|
+
? [...new Set(data.groups.filter((g) => typeof g === 'string' && g.trim()).map((g) => g.trim()))].slice(0, 200)
|
|
13
|
+
: [];
|
|
14
|
+
const user = data.content && typeof data.content === 'object' && !Array.isArray(data.content) ? data.content : {};
|
|
15
|
+
const apiPlaygroundInputs =
|
|
16
|
+
data.apiPlaygroundInputs && typeof data.apiPlaygroundInputs === 'object' && !Array.isArray(data.apiPlaygroundInputs)
|
|
17
|
+
? data.apiPlaygroundInputs
|
|
18
|
+
: {};
|
|
19
|
+
return { user, groups, apiPlaygroundInputs };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function pageRequiredGroups(page) {
|
|
23
|
+
const fromFrontmatter = page?.frontmatter?.groups;
|
|
24
|
+
if (Array.isArray(fromFrontmatter) && fromFrontmatter.length) return fromFrontmatter;
|
|
25
|
+
const fromOperation = page?.operation?.groups;
|
|
26
|
+
if (Array.isArray(fromOperation) && fromOperation.length) return fromOperation;
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function filterSidebarSections(sections = [], groups = getReaderGroups(), pagesMap = {}) {
|
|
31
|
+
const keepItems = (items) =>
|
|
32
|
+
(items || []).flatMap((item) => {
|
|
33
|
+
if (item?.items) {
|
|
34
|
+
const nested = keepItems(item.items);
|
|
35
|
+
return nested.length ? [{ ...item, items: nested }] : [];
|
|
36
|
+
}
|
|
37
|
+
const required = Array.isArray(item?.groups) && item.groups.length
|
|
38
|
+
? item.groups
|
|
39
|
+
: pageRequiredGroups(pagesMap[item?.href]);
|
|
40
|
+
return visibleToGroups(required, groups) ? [item] : [];
|
|
41
|
+
});
|
|
42
|
+
return (sections || [])
|
|
43
|
+
.map((section) => {
|
|
44
|
+
const items = keepItems(section.items);
|
|
45
|
+
return items.length ? { ...section, items } : null;
|
|
46
|
+
})
|
|
47
|
+
.filter(Boolean);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function setReaderIdentity(identity = {}) {
|
|
51
|
+
const next = {
|
|
52
|
+
user: identity.user && typeof identity.user === 'object' && !Array.isArray(identity.user) ? identity.user : {},
|
|
53
|
+
groups: Array.isArray(identity.groups) ? identity.groups.filter((g) => typeof g === 'string') : [],
|
|
54
|
+
apiPlaygroundInputs:
|
|
55
|
+
identity.apiPlaygroundInputs && typeof identity.apiPlaygroundInputs === 'object' && !Array.isArray(identity.apiPlaygroundInputs)
|
|
56
|
+
? identity.apiPlaygroundInputs
|
|
57
|
+
: {},
|
|
58
|
+
};
|
|
59
|
+
if (typeof globalThis === 'undefined') return next;
|
|
60
|
+
globalThis.velu = { ...(globalThis.velu || {}), ...next };
|
|
61
|
+
globalThis.mintlify = { ...(globalThis.mintlify || {}), user: next.user };
|
|
62
|
+
if (typeof globalThis.dispatchEvent === 'function' && typeof globalThis.Event === 'function') {
|
|
63
|
+
globalThis.dispatchEvent(new Event('velu:user'));
|
|
64
|
+
globalThis.dispatchEvent(new Event('mintlify:user'));
|
|
65
|
+
}
|
|
66
|
+
return next;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getReaderUser() {
|
|
70
|
+
return globalThis.velu?.user && typeof globalThis.velu.user === 'object' ? globalThis.velu.user : {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getReaderGroups() {
|
|
74
|
+
return Array.isArray(globalThis.velu?.groups) ? globalThis.velu.groups : [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getPlaygroundInputs() {
|
|
78
|
+
const inputs = globalThis.velu?.apiPlaygroundInputs;
|
|
79
|
+
return inputs && typeof inputs === 'object' ? inputs : {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function visibleToGroups(required, groups = getReaderGroups()) {
|
|
83
|
+
if (!Array.isArray(required) || required.length === 0) return true;
|
|
84
|
+
return groups.some((g) => required.includes(g));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function initialPlaygroundValues(operation) {
|
|
88
|
+
const inputs = getPlaygroundInputs();
|
|
89
|
+
const values = { auth: {}, path: {}, query: {}, header: {}, cookie: {} };
|
|
90
|
+
for (const a of operation?.auth || []) {
|
|
91
|
+
const raw = inputs.header?.[a.name];
|
|
92
|
+
if (typeof raw !== 'string' || !raw) continue;
|
|
93
|
+
values.auth[a.name] = a.prefix && raw.startsWith(`${a.prefix} `) ? raw.slice(a.prefix.length + 1) : raw;
|
|
94
|
+
}
|
|
95
|
+
for (const loc of ['path', 'query', 'header', 'cookie']) {
|
|
96
|
+
for (const p of operation?.parameters?.[loc] || []) {
|
|
97
|
+
const raw = inputs[loc]?.[p.name];
|
|
98
|
+
if (typeof raw === 'string') values[loc][p.name] = raw;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (typeof globalThis.localStorage === 'undefined') return values;
|
|
102
|
+
try {
|
|
103
|
+
const stored = JSON.parse(globalThis.localStorage.getItem(`velu-playground:${operation?.id}`) || 'null');
|
|
104
|
+
if (stored && typeof stored === 'object') {
|
|
105
|
+
for (const loc of Object.keys(values)) {
|
|
106
|
+
values[loc] = { ...values[loc], ...(stored[loc] || {}) };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
/* ignore malformed local overrides */
|
|
111
|
+
}
|
|
112
|
+
return values;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function persistPlaygroundValues(operationId, values) {
|
|
116
|
+
if (typeof globalThis.localStorage === 'undefined' || !operationId) return;
|
|
117
|
+
try {
|
|
118
|
+
globalThis.localStorage.setItem(`velu-playground:${operationId}`, JSON.stringify(values || {}));
|
|
119
|
+
} catch {
|
|
120
|
+
/* quota / private mode */
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function personalizedServer(fallback) {
|
|
125
|
+
const vars = getPlaygroundInputs().server || {};
|
|
126
|
+
let url = (typeof vars.baseUrl === 'string' && vars.baseUrl)
|
|
127
|
+
|| (typeof vars.url === 'string' && vars.url)
|
|
128
|
+
|| fallback
|
|
129
|
+
|| '';
|
|
130
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
131
|
+
if (key === 'baseUrl' || key === 'url' || typeof value !== 'string') continue;
|
|
132
|
+
url = url.replaceAll(`{${key}}`, value);
|
|
133
|
+
}
|
|
134
|
+
return url;
|
|
135
|
+
}
|
|
@@ -304,7 +304,9 @@
|
|
|
304
304
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block { border-radius: 16px; border-color: rgb(from var(--vepa-gray-950) r g b / 10%); }
|
|
305
305
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block :is(pre,code) { font: 400 14px/24px var(--font-mono); }
|
|
306
306
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__body { padding: 16px; border-radius: 16px; }
|
|
307
|
-
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-
|
|
307
|
+
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__actions { top: 12px; right: 12px; }
|
|
308
|
+
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__copy,
|
|
309
|
+
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__report-btn { border: 0; background: transparent; width: 24px; height: 24px; }
|
|
308
310
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__header { height: 36px; padding: 0 12px; align-items: stretch; }
|
|
309
311
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__tabs { gap: 16px; }
|
|
310
312
|
:is([data-site-theme='thulir'],[data-site-theme='aalam'],[data-site-theme='nila'],[data-site-theme='kadhir']) .velu-code-block__tab { padding: 0 6px; border-radius: 0; font: 400 12px/20px var(--font-sans); height: 36px; }
|
package/src/navigation.js
CHANGED
|
@@ -478,5 +478,9 @@ function itemFor(pageNode, pagesMap, ctx) {
|
|
|
478
478
|
}
|
|
479
479
|
const method = pageNode.method ?? pagesMap[href]?.operation?.method;
|
|
480
480
|
if (method) item.method = method;
|
|
481
|
+
const groups = pageNode.groups
|
|
482
|
+
?? (Array.isArray(fm?.groups) && fm.groups.length ? fm.groups : undefined)
|
|
483
|
+
?? pagesMap[href]?.operation?.groups;
|
|
484
|
+
if (Array.isArray(groups) && groups.length) item.groups = groups;
|
|
481
485
|
return item;
|
|
482
486
|
}
|
package/src/runtime/App.jsx
CHANGED
|
@@ -58,6 +58,10 @@ import {
|
|
|
58
58
|
ApiReferencePage,
|
|
59
59
|
NotFound,
|
|
60
60
|
VeluMark,
|
|
61
|
+
setReaderIdentity,
|
|
62
|
+
emptyReaderIdentity,
|
|
63
|
+
identityFromUserData,
|
|
64
|
+
filterSidebarSections,
|
|
61
65
|
} from 'velu-ui';
|
|
62
66
|
import { X, ChevronDown } from 'lucide-react';
|
|
63
67
|
import ErrorBoundary from './ErrorBoundary.jsx';
|
|
@@ -107,14 +111,29 @@ function sectionToEndpoints(items) {
|
|
|
107
111
|
else
|
|
108
112
|
out.push({
|
|
109
113
|
method: it.method,
|
|
110
|
-
|
|
114
|
+
name: it.label,
|
|
111
115
|
href: it.href,
|
|
112
|
-
icon: it.icon,
|
|
113
116
|
});
|
|
114
117
|
}
|
|
115
118
|
return out;
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
function flattenSidebarPages(sections) {
|
|
122
|
+
const out = [];
|
|
123
|
+
const walk = (items) => {
|
|
124
|
+
for (const it of items ?? []) {
|
|
125
|
+
if (it.items) walk(it.items);
|
|
126
|
+
else {
|
|
127
|
+
const page = { label: it.label, href: it.href };
|
|
128
|
+
if (it.description) page.description = it.description;
|
|
129
|
+
out.push(page);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
for (const section of sections ?? []) walk(section.items);
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
const CALLOUT_TYPES = [
|
|
119
138
|
'note',
|
|
120
139
|
'warning',
|
|
@@ -788,6 +807,53 @@ function DocsPage() {
|
|
|
788
807
|
const location = useLocation();
|
|
789
808
|
const navigate = useNavigate();
|
|
790
809
|
const pathname = normalizeUrl(location.pathname);
|
|
810
|
+
const [readerUser, setReaderUser] = React.useState(() =>
|
|
811
|
+
typeof window === 'undefined' ? {} : window.velu?.user || {},
|
|
812
|
+
);
|
|
813
|
+
const [readerGroups, setReaderGroups] = React.useState(() =>
|
|
814
|
+
typeof window === 'undefined' ? [] : window.velu?.groups || [],
|
|
815
|
+
);
|
|
816
|
+
const [sharedSession, setSharedSession] = React.useState(null);
|
|
817
|
+
React.useEffect(() => {
|
|
818
|
+
const sync = () => {
|
|
819
|
+
setReaderUser(window.velu?.user || {});
|
|
820
|
+
setReaderGroups(Array.isArray(window.velu?.groups) ? window.velu.groups : []);
|
|
821
|
+
};
|
|
822
|
+
sync();
|
|
823
|
+
window.addEventListener('velu:user', sync);
|
|
824
|
+
return () => window.removeEventListener('velu:user', sync);
|
|
825
|
+
}, []);
|
|
826
|
+
React.useEffect(() => {
|
|
827
|
+
if (IS_DEV_PREVIEW || site.readerPrivate || site.guarded) return undefined;
|
|
828
|
+
let alive = true;
|
|
829
|
+
(async () => {
|
|
830
|
+
try {
|
|
831
|
+
const config = await fetch(`${BASE_PATH}/@velu-reader/personalization`, {
|
|
832
|
+
credentials: 'same-origin',
|
|
833
|
+
cache: 'no-store',
|
|
834
|
+
}).then((response) => (response.ok ? response.json() : null));
|
|
835
|
+
if (!alive || config?.method !== 'shared_session' || !config.infoUrl) return;
|
|
836
|
+
setSharedSession({ loginUrl: config.loginUrl || null, identified: false });
|
|
837
|
+
const response = await fetch(config.infoUrl, { credentials: 'include', cache: 'no-store' });
|
|
838
|
+
if (!alive) return;
|
|
839
|
+
if (!response.ok) {
|
|
840
|
+
setReaderIdentity(emptyReaderIdentity());
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const identity = identityFromUserData(await response.json());
|
|
844
|
+
setReaderIdentity(identity);
|
|
845
|
+
setSharedSession({
|
|
846
|
+
loginUrl: config.loginUrl || null,
|
|
847
|
+
identified: identity.groups.length > 0 || Object.keys(identity.user).length > 0,
|
|
848
|
+
});
|
|
849
|
+
} catch {
|
|
850
|
+
if (alive) setReaderIdentity(emptyReaderIdentity());
|
|
851
|
+
}
|
|
852
|
+
})();
|
|
853
|
+
return () => {
|
|
854
|
+
alive = false;
|
|
855
|
+
};
|
|
856
|
+
}, []);
|
|
791
857
|
const entry = pages[pathname];
|
|
792
858
|
// `navigation`/`pages` are module constants in dev/build (the deps never
|
|
793
859
|
// change there); the instant preview's virtual-site substitute reassigns
|
|
@@ -797,6 +863,18 @@ function DocsPage() {
|
|
|
797
863
|
() => resolve(pathname, navigation, pages),
|
|
798
864
|
[pathname, navigation, pages],
|
|
799
865
|
);
|
|
866
|
+
const visibleNav = React.useMemo(() => {
|
|
867
|
+
if (!nav || site.readerPrivate || site.guarded) return nav;
|
|
868
|
+
const sidebarSections = filterSidebarSections(nav.sidebarSections, readerGroups, pages);
|
|
869
|
+
const ordered = flattenSidebarPages(sidebarSections);
|
|
870
|
+
const idx = ordered.findIndex((page) => page.href === pathname);
|
|
871
|
+
return {
|
|
872
|
+
...nav,
|
|
873
|
+
sidebarSections,
|
|
874
|
+
prev: idx > 0 ? ordered[idx - 1] : undefined,
|
|
875
|
+
next: idx >= 0 && idx < ordered.length - 1 ? ordered[idx + 1] : undefined,
|
|
876
|
+
};
|
|
877
|
+
}, [nav, pathname, readerGroups]);
|
|
800
878
|
|
|
801
879
|
// Search source: Pagefind for content/excerpts, but resolve each result's
|
|
802
880
|
// breadcrumb from the real NAVIGATION (a page's nav group can differ from its
|
|
@@ -849,6 +927,31 @@ function DocsPage() {
|
|
|
849
927
|
return createPageFeedback({ apiBase, host: site.assistant?.host });
|
|
850
928
|
}, []);
|
|
851
929
|
|
|
930
|
+
React.useEffect(() => {
|
|
931
|
+
if (IS_DEV_PREVIEW) return undefined;
|
|
932
|
+
const onReport = (e) => {
|
|
933
|
+
const d = e.detail || {};
|
|
934
|
+
pageFeedback?.submit({
|
|
935
|
+
helpful: false,
|
|
936
|
+
reason: 'Incorrect code example',
|
|
937
|
+
detail: d.body || d.detail || '',
|
|
938
|
+
});
|
|
939
|
+
};
|
|
940
|
+
window.addEventListener('velu:report-code', onReport);
|
|
941
|
+
return () => window.removeEventListener('velu:report-code', onReport);
|
|
942
|
+
}, [pageFeedback]);
|
|
943
|
+
|
|
944
|
+
React.useEffect(() => {
|
|
945
|
+
if (IS_DEV_PREVIEW || !pageFeedback?.config) return undefined;
|
|
946
|
+
let alive = true;
|
|
947
|
+
pageFeedback.config().then((cfg) => {
|
|
948
|
+
if (!alive || !cfg.codeReportsEnabled) return;
|
|
949
|
+
document.documentElement.dataset.veluCodeReports = 'on';
|
|
950
|
+
window.dispatchEvent(new Event('velu:code-reports-enabled'));
|
|
951
|
+
}).catch(() => {});
|
|
952
|
+
return () => { alive = false; };
|
|
953
|
+
}, [pageFeedback]);
|
|
954
|
+
|
|
852
955
|
const frontmatter = entry?.frontmatter ?? {};
|
|
853
956
|
const PageComponent = entry?.Component ?? null;
|
|
854
957
|
const pageToc = entry?.toc ?? [];
|
|
@@ -1232,6 +1335,14 @@ function DocsPage() {
|
|
|
1232
1335
|
kind: 'outlined',
|
|
1233
1336
|
component: 'logout-link',
|
|
1234
1337
|
});
|
|
1338
|
+
} else if (sharedSession?.loginUrl && !sharedSession.identified) {
|
|
1339
|
+
navActions.push({
|
|
1340
|
+
label: 'Log in',
|
|
1341
|
+
href: sharedSession.loginUrl,
|
|
1342
|
+
kind: 'outlined',
|
|
1343
|
+
external: true,
|
|
1344
|
+
component: 'login-link',
|
|
1345
|
+
});
|
|
1235
1346
|
}
|
|
1236
1347
|
|
|
1237
1348
|
// Callback ref so this rebinds when the footer mounts/unmounts.
|
|
@@ -1651,7 +1762,7 @@ function DocsPage() {
|
|
|
1651
1762
|
the sidebar shape). */}
|
|
1652
1763
|
{nav?.sidebarHasApi ? (
|
|
1653
1764
|
<ApiSidebar
|
|
1654
|
-
sections={(
|
|
1765
|
+
sections={(visibleNav?.sidebarSections ?? []).map((s) => ({
|
|
1655
1766
|
title: s.title,
|
|
1656
1767
|
icon: s.icon,
|
|
1657
1768
|
endpoints: sectionToEndpoints(s.items),
|
|
@@ -1661,7 +1772,7 @@ function DocsPage() {
|
|
|
1661
1772
|
/>
|
|
1662
1773
|
) : (
|
|
1663
1774
|
<Sidebar
|
|
1664
|
-
sections={
|
|
1775
|
+
sections={visibleNav?.sidebarSections ?? []}
|
|
1665
1776
|
activeHref={pathname}
|
|
1666
1777
|
linkComponent={RouterLink}
|
|
1667
1778
|
/>
|
|
@@ -1852,7 +1963,7 @@ function DocsPage() {
|
|
|
1852
1963
|
<mdx-content key={site.theme === 'vepa' ? pathname : undefined} id={(site.theme === 'vepa' || ['thulir', 'aalam', 'nila', 'kadhir'].includes(site.theme)) && !entry?.api ? 'content' : undefined} class="velu-prose">
|
|
1853
1964
|
{PageComponent ? (
|
|
1854
1965
|
<ErrorBoundary key={pathname} file={entry?.relPath}>
|
|
1855
|
-
{entry?.mdxApi ? <ApiReferencePage {...entry.mdxApi} preset={site.theme}><PageComponent /></ApiReferencePage> : <PageComponent />}
|
|
1966
|
+
{entry?.mdxApi ? <ApiReferencePage {...entry.mdxApi} preset={site.theme}><PageComponent user={readerUser} /></ApiReferencePage> : <PageComponent user={readerUser} />}
|
|
1856
1967
|
</ErrorBoundary>
|
|
1857
1968
|
) : (
|
|
1858
1969
|
<p style={{ color: 'var(--muted-color)' }}>
|
|
@@ -1885,14 +1996,14 @@ function DocsPage() {
|
|
|
1885
1996
|
sidebar reading order of the active section. The wrapper
|
|
1886
1997
|
doubles as the AskBar fade anchor on themes without a
|
|
1887
1998
|
PageFeedback widget (see the observer above). */}
|
|
1888
|
-
{chrome.articleChrome && !frontmatter.hidePagination && (
|
|
1999
|
+
{chrome.articleChrome && !frontmatter.hidePagination && (visibleNav?.prev || visibleNav?.next) && (
|
|
1889
2000
|
<div ref={setNavAnchorEl}>
|
|
1890
2001
|
<PageNav
|
|
1891
2002
|
id="pagination"
|
|
1892
2003
|
style={['thulir', 'aalam', 'nila', 'kadhir'].includes(site.theme) ? undefined : { marginTop: 'var(--s2)' }}
|
|
1893
2004
|
variant={site.theme === 'aalam' ? 'aalam' : 'default'}
|
|
1894
|
-
prev={
|
|
1895
|
-
next={
|
|
2005
|
+
prev={visibleNav?.prev}
|
|
2006
|
+
next={visibleNav?.next}
|
|
1896
2007
|
linkComponent={RouterLink}
|
|
1897
2008
|
/>
|
|
1898
2009
|
</div>
|