Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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;

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}`;
};

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 => {
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