Skip to content

Commit 8edf33c

Browse files
committed
more cleanup, move tabs logic out a bit, update nav for layouts
1 parent a16dd50 commit 8edf33c

File tree

7 files changed

+113
-48
lines changed

7 files changed

+113
-48
lines changed

src/components/NavEntry.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ export const NavEntry = ({ entry, isActive }: NavEntryProps) => {
2020
const { id } = entry
2121
const { id: entryTitle, section } = entry.data
2222

23-
const _id = section === 'components' ? kebabCase(entryTitle) : id
23+
const _id =
24+
section === 'components' || section === 'layouts'
25+
? kebabCase(entryTitle)
26+
: id
2427
return (
2528
<NavItem
2629
itemId={_id}

src/components/NavSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const NavSection = ({
2323
const isActive = sortedNavEntries.some((entry) => entry.id === activeItem)
2424

2525
let navItems = sortedNavEntries
26-
if (sectionId === 'components') {
26+
if (sectionId === 'components' || sectionId === 'layouts') {
2727
// only display unique entry.data.id in the nav list if the section is components
2828
navItems = [
2929
...sortedNavEntries

src/components/Navigation.astro

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ import { content } from "../content"
88
const collections = await Promise.all(content.map(async (entry) => await getCollection(entry.name as 'textContent')))
99
1010
const navEntries = collections.flat();
11-
// filter out duplicate component entries - default to react path
12-
// use entry.data.id for links here instead of entry.id because of filepaths
13-
// note: filepaths may not be unique, may want to consider using package name as well
1411
---
1512

1613
<ReactNav client:only="react" navEntries={navEntries} transition:animate="fade" />

src/components/__tests__/NavSection.test.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ const mockEntries: TextContentEntry[] = [
2020
},
2121
]
2222

23+
const dupedEntries: TextContentEntry[] = [
24+
{
25+
id: 'entry1',
26+
data: { id: 'Entry1', section: 'components' },
27+
collection: 'react',
28+
},
29+
{
30+
id: 'entry2',
31+
data: { id: 'Entry1', section: 'components' },
32+
collection: 'react',
33+
},
34+
{
35+
id: 'entry3',
36+
data: { id: 'Entry2', section: 'components' },
37+
collection: 'react',
38+
},
39+
]
40+
2341
it('renders without crashing', () => {
2442
render(
2543
<NavSection
@@ -141,3 +159,45 @@ it('matches snapshot', () => {
141159
)
142160
expect(asFragment()).toMatchSnapshot()
143161
})
162+
163+
it('dedupes and renders correct number of entries for components section', () => {
164+
Object.defineProperty(window, 'location', {
165+
value: {
166+
pathname: '/foo/components',
167+
},
168+
writable: true,
169+
})
170+
171+
render(
172+
<NavSection
173+
entries={dupedEntries}
174+
sectionId="components"
175+
activeItem="entry1"
176+
/>,
177+
)
178+
179+
expect(screen.getAllByRole('listitem')).toHaveLength(3)
180+
expect(screen.getByRole('link', { name: 'Entry1' })).toBeInTheDocument()
181+
expect(screen.getByRole('link', { name: 'Entry2' })).toBeInTheDocument()
182+
})
183+
184+
it('dedupes and renders correct number of entries for layouts section', () => {
185+
Object.defineProperty(window, 'location', {
186+
value: {
187+
pathname: '/foo/layouts',
188+
},
189+
writable: true,
190+
})
191+
192+
render(
193+
<NavSection
194+
entries={dupedEntries}
195+
sectionId="layouts"
196+
activeItem="entry1"
197+
/>,
198+
)
199+
200+
expect(screen.getAllByRole('listitem')).toHaveLength(3)
201+
expect(screen.getByRole('link', { name: 'Entry1' })).toBeInTheDocument()
202+
expect(screen.getByRole('link', { name: 'Entry2' })).toBeInTheDocument()
203+
})

src/globals.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,46 @@ export const tabNames: any = {
66
'react-deprecated': 'React deprecated',
77
'html': 'HTML',
88
'html-demos': 'HTML demos'
9-
};
9+
};
10+
11+
export const buildTab = (entry: any, tab: string) => {
12+
// if no dictionary entry exists, and tab data exists
13+
if(componentTabs[entry.data.id] === undefined && tab) {
14+
componentTabs[entry.data.id] = [tab];
15+
// if dictionary entry & tab data exists, and entry does not include tab
16+
} else if (componentTabs[entry.data.id] && tab && !componentTabs[entry.data.id].includes(tab)) {
17+
componentTabs[entry.data.id] = [...componentTabs[entry.data.id], tab];
18+
}
19+
}
20+
21+
export const sortTabs = () => {
22+
const defaultOrder = 50;
23+
const sourceOrder: any = {
24+
react: 1,
25+
'react-next': 1.1,
26+
'react-demos': 2,
27+
'react-deprecated': 2.1,
28+
html: 3,
29+
'html-demos': 4,
30+
'design-guidelines': 99,
31+
'accessibility': 100,
32+
'upgrade-guide': 101,
33+
'release-notes': 102,
34+
};
35+
36+
const sortSources = (s1: string, s2: string) => {
37+
const s1Index = sourceOrder[s1] || defaultOrder;
38+
const s2Index = sourceOrder[s2] || defaultOrder;
39+
if (s1Index === defaultOrder && s2Index === defaultOrder) {
40+
return s1.localeCompare(s2);
41+
}
42+
43+
return s1Index > s2Index ? 1 : -1;
44+
}
45+
46+
// Sort tabs entries based on above sort order
47+
// Ensures all tabs are displayed in a consistent order & which tab gets displayed for a component route without a tab
48+
Object.values(componentTabs).map((tabs: any) => {
49+
tabs.sort(sortSources)
50+
})
51+
}

src/pages/[section]/[...page].astro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,5 @@ if(section === 'components') { // if section is components, rewrite to first tab
3434
</Title>
3535
)
3636
}
37-
AM I HERE?
3837
<Content />
3938
</MainLayout>

src/pages/[section]/[page]/[...tab].astro

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,30 @@ import { Title, PageSection, Content as PFContent } from '@patternfly/react-core
44
import MainLayout from '../../../layouts/Main.astro'
55
import { content } from "../../../content"
66
import { kebabCase } from 'change-case'
7-
import { componentTabs, tabNames } from '../../../globals';
7+
import { componentTabs, tabNames, buildTab, sortTabs } from '../../../globals';
88
99
export async function getStaticPaths() {
1010
const collections = await Promise.all(content.map(async (entry) => await getCollection(entry.name as 'textContent')))
1111
1212
const flatCol = collections.flat().map((entry) => {
1313
// Build tabs dictionary
1414
let tab = entry.data.tab;
15-
if(tab === 'react' || tab === 'html') { // if tab is default repo value, check for demos/deprecated
15+
if(tab) { // check for demos/deprecated
1616
if(entry.id.includes('demos')) {
1717
tab = `${tab}-demos`;
1818
} else if (entry.id.includes('deprecated')) {
1919
tab = `${tab}-deprecated`;
2020
}
2121
}
22-
23-
// if no dictionary entry exists, and tab data exists
24-
if(componentTabs[entry.data.id] === undefined && tab) {
25-
componentTabs[entry.data.id] = [tab];
26-
// if dictionary entry & tab data exists, and entry does not include tab
27-
} else if (componentTabs[entry.data.id] && tab && !componentTabs[entry.data.id].includes(tab)) {
28-
componentTabs[entry.data.id] = [...componentTabs[entry.data.id], tab];
29-
}
22+
buildTab(entry, tab);
3023
3124
return {
3225
params: { page: kebabCase(entry.data.id), section: entry.data.section, tab },
33-
props: { entry, title: entry.data.title, component: entry.data.id, package: entry.data.package },
26+
props: { entry, ...entry.data },
3427
}
3528
})
3629
37-
const defaultOrder = 50;
38-
const sourceOrder: any = {
39-
react: 1,
40-
'react-next': 1.1,
41-
'react-demos': 2,
42-
'react-deprecated': 2.1,
43-
html: 3,
44-
'html-demos': 4,
45-
'design-guidelines': 99,
46-
'accessibility': 100,
47-
'upgrade-guide': 101,
48-
'release-notes': 102,
49-
};
50-
51-
const sortSources = (s1: string, s2: string) => {
52-
const s1Index = sourceOrder[s1] || defaultOrder;
53-
const s2Index = sourceOrder[s2] || defaultOrder;
54-
if (s1Index === defaultOrder && s2Index === defaultOrder) {
55-
return s1.localeCompare(s2);
56-
}
57-
58-
return s1Index > s2Index ? 1 : -1;
59-
}
60-
61-
// Sort tabs entries based on above sort order
62-
// Ensures all tabs are displayed in a consistent order & which tab gets displayed for a component route without a tab
63-
Object.values(componentTabs).map((tabs: any) => {
64-
tabs.sort(sortSources)
65-
})
66-
30+
sortTabs()
6731
return flatCol;
6832
}
6933

0 commit comments

Comments
 (0)