Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion content/300-accelerate/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pagination_next: 'accelerate/getting-started'

import {
Bolt,
BorderBox,
BoxTitle,
Database,
Grid,
Expand Down
1 change: 0 additions & 1 deletion content/700-optimize/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pagination_next: 'optimize/getting-started'

import {
Bolt,
BorderBox,
BoxTitle,
Database,
Grid,
Expand Down
1 change: 0 additions & 1 deletion functions/_middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ export const onRequest: PagesFunction<Env> = async (context) => {
if (response.ok) {
// Check what content type we actually got
const actualContentType = response.headers.get('content-type');
console.log(`Fetched ${markdownPath}, got content-type: ${actualContentType}`);

return new Response(response.body, {
status: 200,
Expand Down
42 changes: 42 additions & 0 deletions src/hooks/useUTMParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useState, useEffect } from 'react';

export const useUTMParams = (): string => {
const [utmParams, setUTMParams] = useState('');

useEffect(() => {
// Check if we're on the client side
if (typeof window !== 'undefined') {
const updateUTMParams = () => {
const storedParams = sessionStorage.getItem('utm_params');
setUTMParams(storedParams || '');
};

// Initial load
updateUTMParams();

// Listen for storage changes (in case UTM params are set after initial load)
const handleStorageChange = (e: StorageEvent) => {
if (e.key === 'utm_params') {
updateUTMParams();
}
};

window.addEventListener('storage', handleStorageChange);

// Also check periodically in case the storage was updated in the same tab
const interval = setInterval(updateUTMParams, 100);

// Clean up after a short time to avoid infinite checking
setTimeout(() => {
clearInterval(interval);
}, 2000);

return () => {
window.removeEventListener('storage', handleStorageChange);
clearInterval(interval);
};
}
}, []);

return utmParams;
};
88 changes: 88 additions & 0 deletions src/theme/Logo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, {type ReactNode} from 'react';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import {useThemeConfig, type NavbarLogo} from '@docusaurus/theme-common';
import ThemedImage from '@theme/ThemedImage';
import type {Props} from '@theme/Logo';
import { useUTMParams } from '@site/src/hooks/useUTMParams';

function LogoThemedImage({
logo,
alt,
imageClassName,
}: {
logo: NavbarLogo;
alt: string;
imageClassName?: string;
}) {
const sources = {
light: useBaseUrl(logo.src),
dark: useBaseUrl(logo.srcDark || logo.src),
};
const themedImage = (
<ThemedImage
className={logo.className}
sources={sources}
height={logo.height}
width={logo.width}
alt={alt}
style={logo.style}
/>
);

// Is this extra div really necessary?
// introduced in https://github.com/facebook/docusaurus/pull/5666
return imageClassName ? (
<div className={imageClassName}>{themedImage}</div>
) : (
themedImage
);
}

export default function Logo(props: Props): ReactNode {
const {
siteConfig: {title},
} = useDocusaurusContext();
const {
navbar: {title: navbarTitle, logo},
} = useThemeConfig();

const {imageClassName, titleClassName, ...propsRest} = props;
const logoLink = useBaseUrl(logo?.href || '/');
const utmParams = useUTMParams();

// Helper function to append UTM params to URL
const appendUtmParams = (url: string): string => {
if (!utmParams) {
return url;
}
const separator = url.includes('?') ? '&' : '?';
const result = `${url}${separator}${utmParams}`;
return result;
};

// If visible title is shown, fallback alt text should be
// an empty string to mark the logo as decorative.
const fallbackAlt = navbarTitle ? '' : title;

// Use logo alt text if provided (including empty string),
// and provide a sensible fallback otherwise.
const alt = logo?.alt ?? fallbackAlt;
Comment on lines +55 to +71
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO appendUtmParams is enough to understand, I think you can drop the "Helper function to append UTM params to URL" comment.

More generally, do we tend to keep comments in the codebase ? (still fresh in the team so just asking for context)


return (
<Link
to={appendUtmParams(logoLink)}
{...propsRest}
{...(logo?.target && {target: logo.target})}>
{logo && (
<LogoThemedImage
logo={logo}
alt={alt}
imageClassName={imageClassName}
/>
)}
{navbarTitle != null && <b className={titleClassName}>{navbarTitle}</b>}
</Link>
);
}
11 changes: 10 additions & 1 deletion src/theme/Navbar/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React, { type ReactNode } from 'react';
import styles from './styles.module.css';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import { useUTMParams } from '@site/src/hooks/useUTMParams';

function useNavbarItems() {
// TODO temporary casting until ThemeConfig type is improved
Expand Down Expand Up @@ -58,12 +59,20 @@ function NavbarContentLayout({

export default function NavbarContent(): ReactNode {
const mobileSidebar = useNavbarMobileSidebar();
const utmParams = useUTMParams();

const items = useNavbarItems();
const [leftItems, rightItems] = splitNavbarItems(items);

const searchBarItem = items.find((item) => item.type === 'search');
const baseUrl = useBaseUrl("/");

// Helper function to append UTM params to URL
const appendUtmParams = (url: string): string => {
if (!utmParams) return url;
const separator = url.includes('?') ? '&' : '?';
return `${url}${separator}${utmParams}`;
};
Comment on lines +69 to +75
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above for comments


return (
<NavbarContentLayout
Expand All @@ -73,7 +82,7 @@ export default function NavbarContent(): ReactNode {
{!mobileSidebar.disabled && <NavbarMobileSidebarToggle />}
<NavbarLogo />
<span className={styles.separator}>/</span>
<Link to={baseUrl} className="logo-link">docs</Link>
<Link to={appendUtmParams(baseUrl)} className="logo-link">docs</Link>
</>
}
middle={
Expand Down
41 changes: 39 additions & 2 deletions src/theme/NavbarItem/NavbarNavLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {isRegexpStringMatch} from '@docusaurus/theme-common';
import IconExternalLink from '@theme/Icon/ExternalLink';
import type {Props} from '@theme/NavbarItem/NavbarNavLink';
import { Icon } from '@site/src/components/Icon';
import { useUTMParams } from '@site/src/hooks/useUTMParams';


type CustomProps = Props & {
Expand All @@ -31,6 +32,25 @@ export default function NavbarNavLink({
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
const isExternalLink = label && href && !isInternalUrl(href);

// Get UTM parameters from sessionStorage using custom hook
const utmParams = useUTMParams();

// Helper function to append UTM params to URL
const appendUtmParams = (url: string): string => {
Comment on lines +35 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above

if (!utmParams) {
return url;
}

const [baseUrl, existingQuery] = url.split('?');
if (existingQuery) {
const result = `${baseUrl}?${existingQuery}&${utmParams}`;
return result;
} else {
const result = `${baseUrl}?${utmParams}`;
return result;
}
};

// Link content is set through html XOR label
const linkContentProps = html
? {dangerouslySetInnerHTML: {__html: html}}
Expand All @@ -54,18 +74,35 @@ export default function NavbarNavLink({
};

if (href) {
// For external links, return as-is
if (isExternalLink) {
return (
<Link
href={prependBaseUrlToHref ? normalizedHref : href}
{...props}
{...linkContentProps}
/>
);
}

// For internal links, append UTM parameters if available
const finalHref = prependBaseUrlToHref ? normalizedHref : href;
const urlWithUtms = appendUtmParams(finalHref);

return (
<Link
href={prependBaseUrlToHref ? normalizedHref : href}
href={urlWithUtms}
{...props}
{...linkContentProps}
/>
);
}

const urlWithUtms = appendUtmParams(toUrl);

return (
<Link
to={toUrl}
to={urlWithUtms}
isNavLink
{...((activeBasePath || activeBaseRegex) && {
isActive: (_match, location) =>
Expand Down
4 changes: 2 additions & 2 deletions src/utils/useUTMPersistenceDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export const useUTMPersistenceDocs = () => {
if (previousSearch.current === '') {
previousSearch.current = location.search;
if (hasUTMParams(location.search)) {
sessionStorage.setItem('utm_params', getUTMParams(location.search));
const utms = getUTMParams(location.search);
sessionStorage.setItem('utm_params', utms);
}
return;
}
Expand All @@ -39,7 +40,6 @@ export const useUTMPersistenceDocs = () => {
if (hadUTMs && !hasUTMs && location.pathname === previousSearch.current.split('?')[0]) {
isManualRemoval.current = true;
sessionStorage.removeItem('utm_params');
console.log('Manual removal detected - UTMs cleared');
}
// Save new UTMs if they exist
else if (hasUTMs) {
Expand Down
Loading