Skip to content

Commit

Permalink
SOEOPSFY24-350 | add scroll to timeline anchor link functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
rebeccahongsf committed Dec 18, 2024
1 parent 421e5ca commit 75b2173
Show file tree
Hide file tree
Showing 20 changed files with 61 additions and 49 deletions.
20 changes: 16 additions & 4 deletions components/Timeline/TimelineOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type TimelineProps = {
const TimelineOverview = ({ timelineData }: TimelineProps) => {
const [isMounted, setIsMounted] = useState(false);
const [expandedUuid, setExpandedUuid] = useState<string | null>(null);
const [itemId, setItemid] = useState<string>("");

// Reference to the TimelineItems and TimelineDetails for accessibility focus management
const itemRefs = useRef<{ [key: string]: HTMLButtonElement | null }>({});
Expand All @@ -27,7 +28,17 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
// Ensure the component is mounted before running media queries
useEffect(() => {
setIsMounted(true);
}, []);

// Check if the URL has a hash
const anchor = window.location.hash.replace("#", ""); // Remove '#' character

if (anchor) {
// Validate hash against timeline data
timelineData.find((item) => {
if (item.anchor === anchor) return setExpandedUuid(item.uuid);
});
}
}, [timelineData]);

// Focus on the TimelineDetails when it is expanded
useEffect(() => {
Expand Down Expand Up @@ -56,8 +67,9 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
return acc;
}, []);

const handleToggle = (uuid: string) => {
const handleToggle = (uuid: string, anchor: string) => {
setExpandedUuid((currentUuid) => (currentUuid === uuid ? null : uuid));
setItemid((currentAnchor) => (currentAnchor === anchor ? "" : anchor));
};

if (!isMounted) {
Expand Down Expand Up @@ -94,7 +106,7 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
isExpanded={expandedUuid === item.uuid}
size={size}
trapezoid={trapezoid}
onClick={() => handleToggle(item.uuid)}
onClick={() => handleToggle(item.uuid, item.anchor)}
ref={(el) => {
itemRefs.current[item.uuid] = el;
}}
Expand All @@ -108,7 +120,7 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
{expandedUuid &&
row.some((item) => item.uuid === expandedUuid) && (
<motion.div
id={`drawer-${expandedUuid}`}
id={itemId}
className="w-full"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
Expand Down
2 changes: 1 addition & 1 deletion out/404.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example.html

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions out/example.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/quote.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/quote.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/story.html

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions out/example/story.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/story/hero.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/story/hero.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/textarea.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/example/textarea.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ e:I[3120,[],"OutletBoundary"]
7:HL["/soe-centennial-nextjs/_next/static/media/db3cc5ff6037fbad-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
8:HL["/soe-centennial-nextjs/_next/static/css/80d763bd62d2b210.css","style"]
9:HL["/soe-centennial-nextjs/_next/static/css/ccc860492bb873ee.css","style"]
0:{"P":null,"b":"JFRyXAfXcRCCvAvQ29pxe","p":"/soe-centennial-nextjs","c":["","example","textarea"],"i":false,"f":[[["",{"children":["example",{"children":["textarea",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$a","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/soe-centennial-nextjs/_next/static/css/80d763bd62d2b210.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/soe-centennial-nextjs/_next/static/css/ccc860492bb873ee.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__variable_6f86a8 __variable_cf1540 __variable_2df5e6 __variable_0f68e0","children":["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}],{"children":["example",["$","$a","c",{"children":[null,["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children","example","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}],{"children":["textarea",["$","$a","c",{"children":[null,["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children","example","children","textarea","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}],{"children":["__PAGE__",["$","$a","c",{"children":["$Ld",null,["$","$Le",null,{"children":"$Lf"}]]}],{},null]},null]},null]},null],["$","$a","h",{"children":[null,["$","$a","m6yTpt7FI63o_LltvwrYL",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],["$","meta",null,{"name":"next-size-adjust"}]]}]]}]]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
0:{"P":null,"b":"Ja36Uxqgx9rkJhMUvJstO","p":"/soe-centennial-nextjs","c":["","example","textarea"],"i":false,"f":[[["",{"children":["example",{"children":["textarea",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$a","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/soe-centennial-nextjs/_next/static/css/80d763bd62d2b210.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/soe-centennial-nextjs/_next/static/css/ccc860492bb873ee.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__variable_6f86a8 __variable_cf1540 __variable_2df5e6 __variable_0f68e0","children":["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}],{"children":["example",["$","$a","c",{"children":[null,["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children","example","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}],{"children":["textarea",["$","$a","c",{"children":[null,["$","$Lb",null,{"parallelRouterKey":"children","segmentPath":["children","example","children","textarea","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}],{"children":["__PAGE__",["$","$a","c",{"children":["$Ld",null,["$","$Le",null,{"children":"$Lf"}]]}],{},null]},null]},null]},null],["$","$a","h",{"children":[null,["$","$a","DZ4PUOXEnOPG7aoaGiw4f",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],["$","meta",null,{"name":"next-size-adjust"}]]}]]}]]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
16:I[5218,["143","static/chunks/143-6336b0270e9ea367.js","173","static/chunks/173-3883eb32a68d9f70.js","721","static/chunks/app/example/textarea/page-e1545e95c27cb075.js"],"Skiplink"]
23:I[8173,["143","static/chunks/143-6336b0270e9ea367.js","173","static/chunks/173-3883eb32a68d9f70.js","721","static/chunks/app/example/textarea/page-e1545e95c27cb075.js"],"Image"]
24:I[231,["143","static/chunks/143-6336b0270e9ea367.js","173","static/chunks/173-3883eb32a68d9f70.js","721","static/chunks/app/example/textarea/page-e1545e95c27cb075.js"],""]
Expand Down
2 changes: 1 addition & 1 deletion out/index.html

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions out/index.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/timeline.html

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions out/timeline.txt

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions utilities/loadTimelineData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type TimelineItem = {
year: string;
heading: string;
body: string;
href?: string;
anchor: string;
image: string;
uuid: string;
};
Expand Down Expand Up @@ -39,10 +39,10 @@ export async function loadTimelineData(): Promise<TimelineItem[]> {
if (Array.isArray(parsedData)) {
const validatedItems = parsedData
.filter(isTimelineItem)
.map(assignUuidAndHref);
.map(assignUuidAndAnchor);
allTimelineData.push(...validatedItems);
} else if (isTimelineItem(parsedData)) {
allTimelineData.push(assignUuidAndHref(parsedData));
allTimelineData.push(assignUuidAndAnchor(parsedData));
} else {
console.warn(`Invalid data format in file: ${filePath}`);
}
Expand All @@ -58,18 +58,18 @@ export async function loadTimelineData(): Promise<TimelineItem[]> {
return allTimelineData;
}

function assignUuidAndHref(
item: Omit<TimelineItem, "uuid" | "href">,
function assignUuidAndAnchor(
item: Omit<TimelineItem, "uuid" | "anchor">,
): TimelineItem {
if (!item.heading) {
throw new Error(`Missing heading for timeline item with year ${item.year}`);
}

const sanitizedHeading = sanitizeForUrl(item.heading);
const href = `/${item.year}-${sanitizedHeading}`;
const anchor = `${item.year}-${sanitizedHeading}`;
const uuid = uuidv4(); // Always generate a new UUID

return { ...item, uuid, href };
return { ...item, uuid, anchor };
}

function sanitizeForUrl(text: string): string {
Expand All @@ -82,7 +82,7 @@ function sanitizeForUrl(text: string): string {

function isTimelineItem(
data: unknown,
): data is Omit<TimelineItem, "uuid" | "href"> {
): data is Omit<TimelineItem, "uuid" | "anchor"> {
if (typeof data !== "object" || data === null) return false;

const item = data as Partial<TimelineItem>;
Expand Down

0 comments on commit 75b2173

Please sign in to comment.