Skip to content

Commit 9649f9a

Browse files
feat: add sitemap (#832)
* feat(sitemap): add Uli sitemap page and layout (#830) * refactor(sitemap): rename files, fix layout and tree logic * Added Sitemap page with fixed structure and link logic * fix(sitemap): applied feedback — removed nested blog pages, added ignore list, and improved display names * chore: add sitemap link to footer, remove sitemap background --------- Co-authored-by: maanasb01 <maanasb01@gmail.com>
1 parent 51b8bb9 commit 9649f9a

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

uli-website/src/components/molecules/Footer.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export default function Footer() {
2929
<NavLink to="https://github.com/tattle-made/OGBV/tree/main/uli-website">
3030
GitHub
3131
</NavLink>
32+
<NavLink to="/sitemap">
33+
SiteMap
34+
</NavLink>
3235
</Box>
3336
</Box>
3437
);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React from "react";
2+
import { Box, Heading } from "grommet";
3+
import { Link, useStaticQuery, graphql } from "gatsby";
4+
import generateDisplayName from "../../utils/generateDisplayName";
5+
6+
export default function Sitemap() {
7+
// Fetch all site pages
8+
const data = useStaticQuery(graphql`
9+
{
10+
allSitePage(
11+
filter: { path: { ne: "/dev-404-page/" } }
12+
sort: { path: ASC }
13+
) {
14+
nodes {
15+
path
16+
}
17+
}
18+
}
19+
`);
20+
21+
// Paths to ignore
22+
const ignoredPaths = [
23+
"/404/",
24+
"/404.html",
25+
"/dev-404-page/",
26+
"/offline-plugin-app-shell-fallback/",
27+
];
28+
29+
// Build tree structure
30+
const buildTree = (pages) => {
31+
const root = {};
32+
33+
pages.forEach(({ path }) => {
34+
if (ignoredPaths.includes(path)) return; // skip ignored pages
35+
36+
// Skip nested blog pages (keep only /blog)
37+
if (path.startsWith("/blog/") && path !== "/blog/") return;
38+
39+
const parts = path.split("/").filter(Boolean);
40+
let current = root;
41+
42+
parts.forEach((part, index) => {
43+
if (!current[part]) current[part] = { __children: {}, __isPage: false };
44+
if (index === parts.length - 1) {
45+
current[part].__isPage = true;
46+
}
47+
current = current[part].__children;
48+
});
49+
});
50+
51+
return root;
52+
};
53+
54+
const tree = buildTree(data.allSitePage.nodes);
55+
56+
// Recursive renderer
57+
const renderTree = (node, base = "") =>
58+
Object.entries(node).map(([key, value]) => {
59+
const fullPath = `${base}/${key}`;
60+
const hasChildren = Object.keys(value.__children || {}).length > 0;
61+
62+
return (
63+
<li key={fullPath} style={{ marginBottom: "6px", lineHeight: "1.8rem" }}>
64+
{value.__isPage ? (
65+
<Link
66+
to={fullPath}
67+
style={{
68+
textDecoration: "none",
69+
color: "#5A4230",
70+
fontWeight: "bold",
71+
}}
72+
>
73+
{generateDisplayName(key)}
74+
</Link>
75+
) : (
76+
<span style={{ color: "#5A4230", fontWeight: "600" }}>
77+
{generateDisplayName(key)}
78+
</span>
79+
)}
80+
81+
{hasChildren && (
82+
<ul style={{ marginLeft: "1.5rem", listStyleType: "disc" }}>
83+
{renderTree(value.__children, fullPath)}
84+
</ul>
85+
)}
86+
</li>
87+
);
88+
});
89+
90+
return (
91+
<Box
92+
pad={{ vertical: "large" }}
93+
align="center"
94+
>
95+
<Box
96+
width="xlarge"
97+
margin={{ horizontal: "auto" }}
98+
pad={{ horizontal: "large" }}
99+
style={{ maxWidth: "800px" }}
100+
>
101+
<Heading level={2} margin={{ bottom: "medium" }} textAlign="center">
102+
Site Map
103+
</Heading>
104+
105+
<ul
106+
style={{
107+
listStyleType: "disc",
108+
paddingLeft: "1.5rem",
109+
textAlign: "left",
110+
}}
111+
>
112+
{renderTree(tree)}
113+
</ul>
114+
</Box>
115+
</Box>
116+
);
117+
}

uli-website/src/pages/sitemap.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from "react"
2+
import Sitemap from "../components/sitemap/Sitemap"
3+
import AppShell from "../components/molecules/AppShell"
4+
5+
export default function SitemapPage() {
6+
return (
7+
<AppShell>
8+
<Sitemap />
9+
</AppShell>
10+
)
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function generateDisplayName(slug) {
2+
if (!slug) return ""
3+
return slug
4+
.replace(/-/g, " ")
5+
.replace(/\b\w/g, (char) => char.toUpperCase())
6+
}
7+

0 commit comments

Comments
 (0)