Skip to content

Commit 93f0d44

Browse files
committed
feat: add functionality for getting previous page
1 parent a8454d3 commit 93f0d44

File tree

4 files changed

+112
-17
lines changed

4 files changed

+112
-17
lines changed

app/[[...path]]/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getCurrentPlatformOrGuide,
1515
getDocsRootNode,
1616
getNextNode,
17+
getPreviousNode,
1718
nodeForPath,
1819
} from 'sentry-docs/docTree';
1920
import {isDeveloperDocs} from 'sentry-docs/isDeveloperDocs';
@@ -43,8 +44,8 @@ export const dynamic = 'force-static';
4344

4445
const mdxComponentsWithWrapper = mdxComponents(
4546
{Include, PlatformContent},
46-
({children, frontMatter, nextPage}) => (
47-
<DocPage frontMatter={frontMatter} nextPage={nextPage}>
47+
({children, frontMatter, nextPage, previousPage}) => (
48+
<DocPage frontMatter={frontMatter} nextPage={nextPage} previousPage={previousPage}>
4849
{children}
4950
</DocPage>
5051
)
@@ -101,9 +102,13 @@ export default async function Page({params}: {params: {path?: string[]}}) {
101102

102103
const pageNode = nodeForPath(rootNode, params.path);
103104
const nextNode = pageNode ? getNextNode(pageNode) : undefined;
105+
const previousNode = pageNode ? getPreviousNode(pageNode) : undefined;
104106
const nextPage = nextNode
105107
? {path: nextNode.path, title: nextNode.frontmatter.title}
106108
: undefined;
109+
const previousPage = previousNode
110+
? {path: previousNode.path, title: previousNode.frontmatter.title}
111+
: undefined;
107112

108113
if (!pageNode) {
109114
// eslint-disable-next-line no-console
@@ -135,6 +140,7 @@ export default async function Page({params}: {params: {path?: string[]}}) {
135140
mdxSource={mdxSource}
136141
frontMatter={{...frontMatter, versions}}
137142
nextPage={nextPage}
143+
previousPage={previousPage}
138144
/>
139145
);
140146
}

src/components/sidebar/sidebarLinks.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {NavNode} from './types';
1111
import {docNodeToNavNode, getNavNodes} from './utils';
1212

1313
/** a root of `"some-root"` maps to the `/some-root/` url */
14+
// we should probably get rid of this
1415
const productSidebarItems = [
1516
{
1617
title: 'Account Settings',

src/docTree.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
DocNode,
55
getCurrentPlatformOrGuide,
66
getNextNode,
7+
getPreviousNode,
78
isRootGuidePath,
89
isRootPlatformPath,
910
nodeForPath,
@@ -211,6 +212,62 @@ describe('docTree', () => {
211212
});
212213
});
213214

215+
describe('getPreviousNode', () => {
216+
const root = createRootNode();
217+
218+
const a = createNode('a', 'A');
219+
const a1 = createNode('a1', 'A1');
220+
const a2 = createNode('a2', 'A2');
221+
a.children = [a1, a2];
222+
a.children.forEach(child => {
223+
child.parent = a;
224+
});
225+
226+
const b = createNode('b', 'B');
227+
const c = createNode('c', 'C');
228+
root.children = [a, b, c];
229+
root.children.forEach(child => {
230+
child.parent = root;
231+
});
232+
233+
test('should return previous child of parent', () => {
234+
expect(getPreviousNode(c)).toBe(b);
235+
});
236+
237+
test('should return previous sibling if previous sibling has children', () => {
238+
expect(getPreviousNode(b)).toBe(a);
239+
});
240+
241+
test('should return undefined if no children or siblings', () => {
242+
expect(getPreviousNode(createNode('d', 'D'))).toBeUndefined();
243+
});
244+
245+
test('should return parent for first child', () => {
246+
expect(getPreviousNode(a1)).toBe(a);
247+
});
248+
249+
test('should respect sidebar order for sorting', () => {
250+
const xRoot = createRootNode();
251+
const xA = createNode('a', 'A', {sidebar_order: 2} as FrontMatter);
252+
const xB = createNode('b', 'B', {sidebar_order: 1} as FrontMatter);
253+
xRoot.children = [xA, xB];
254+
xRoot.children.forEach(child => {
255+
child.parent = xRoot;
256+
});
257+
258+
expect(getPreviousNode(xA)).toBe(xB);
259+
});
260+
261+
test('should not return siblings for root platform or guide paths', () => {
262+
expect(
263+
getPreviousNode(createNode('platforms/javascript', 'JavaScript'))
264+
).toBeUndefined();
265+
expect(
266+
getPreviousNode(createNode('platforms/javascript/guides/nextjs', 'Next.js'))
267+
).toBeUndefined();
268+
});
269+
});
270+
214271
describe('isRootPlatformPath', () => {
215272
test('should return true for root platform path', () => {
216273
expect(isRootPlatformPath('platforms/javascript')).toBe(true);

src/docTree.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,52 @@ export const getNextNode = (node: DocNode): DocNode | undefined => {
181181
return undefined;
182182
};
183183

184+
/**
185+
* Returns the previous node in the tree, which is either the last child of the parent,
186+
* the previous sibling, or the previous sibling of a parent node.
187+
*/
188+
export const getPreviousNode = (node: DocNode): DocNode | undefined => {
189+
const previousSibling = getPreviousSiblingNode(node);
190+
if (previousSibling) {
191+
return previousSibling;
192+
}
193+
return node.parent;
194+
};
195+
196+
const getNextSiblingNode = (node: DocNode): DocNode | undefined => {
197+
if (!node.parent) {
198+
return undefined;
199+
}
200+
201+
const siblings = node.parent.children
202+
.sort(sortSiblingsByOrder)
203+
.filter(filterVisibleSiblings);
204+
205+
const index = siblings.indexOf(node);
206+
if (index < siblings.length - 1) {
207+
return siblings[index + 1];
208+
}
209+
210+
return undefined;
211+
};
212+
213+
const getPreviousSiblingNode = (node: DocNode): DocNode | undefined => {
214+
if (!node.parent) {
215+
return undefined;
216+
}
217+
218+
const siblings = node.parent.children
219+
.sort(sortSiblingsByOrder)
220+
.filter(filterVisibleSiblings);
221+
222+
const index = siblings.indexOf(node);
223+
if (index > 0) {
224+
return siblings[index - 1];
225+
}
226+
227+
return undefined;
228+
};
229+
184230
const sortSiblingsByOrder = (a: DocNode, b: DocNode) =>
185231
(a.frontmatter.sidebar_order ?? 10) - (b.frontmatter.sidebar_order ?? 10);
186232

@@ -190,21 +236,6 @@ const filterVisibleSiblings = (s: DocNode) =>
190236
!s.frontmatter.draft &&
191237
s.path;
192238

193-
const getNextSiblingNode = (node: DocNode): DocNode | undefined => {
194-
// filter out root platform and guide paths as these siblings do not make sense in navigation
195-
if (node.parent) {
196-
const siblings = node.parent.children
197-
.sort(sortSiblingsByOrder)
198-
.filter(filterVisibleSiblings);
199-
200-
const index = siblings.indexOf(node);
201-
if (index < siblings.length - 1) {
202-
return siblings[index + 1];
203-
}
204-
}
205-
return undefined;
206-
};
207-
208239
function nodeToPlatform(n: DocNode): Platform {
209240
const platformData = platformsData()[n.slug];
210241
const caseStyle = platformData?.case_style || n.frontmatter.caseStyle;

0 commit comments

Comments
 (0)