Skip to content

Commit 0a2af33

Browse files
committed
feat: add new PageHeader unit
1 parent 850f824 commit 0a2af33

File tree

4 files changed

+116
-24
lines changed

4 files changed

+116
-24
lines changed

src/components/Layout/Header.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import Icon from '@ably/ui/core/Icon';
77
import TabMenu from '@ably/ui/core/TabMenu';
88
import Logo from '@ably/ui/core/images/logo/ably-logo.svg';
99
import { componentMaxHeight, HEADER_BOTTOM_MARGIN, HEADER_HEIGHT } from '@ably/ui/core/utils/heights';
10-
import cn from '@ably/ui/core/utils/cn';
1110
import { IconName } from '@ably/ui/core/Icon/types';
1211
import LeftSidebar from './LeftSidebar';
1312
import UserContext from 'src/contexts/user-context';
1413
import ExamplesList from '../Examples/ExamplesList';
1514
import Link from '../Link';
1615
import { InkeepSearchBar } from '../SearchBar/InkeepSearchBar';
16+
import { secondaryButtonClassName, iconButtonClassName, tooltipContentClassName } from './utils/styles';
1717

1818
// Tailwind 'md' breakpoint from tailwind.config.js
1919
const MD_BREAKPOINT = 1040;
@@ -50,14 +50,6 @@ const helpResourcesItems = [
5050
external: true,
5151
},
5252
];
53-
const tooltipContentClassName = cn(
54-
'px-2 py-1 bg-neutral-1000 dark:bg-neutral-300 text-neutral-200 dark:text-neutral-1100 ui-text-p3 font-medium rounded-lg relative z-50 mt-2',
55-
'data-[state=closed]:animate-[tooltipExit_0.25s_ease-in-out]',
56-
'data-[state=delayed-open]:animate-[tooltipEntry_0.25s_ease-in-out]',
57-
);
58-
const secondaryButtonClassName =
59-
'focus-base flex items-center justify-center gap-2 px-4 py-[7px] h-9 ui-text-label4 text-neutral-1300 dark:text-neutral-000 rounded border border-neutral-400 dark:border-neutral-900 hover:border-neutral-600 dark:hover:border-neutral-700';
60-
const iconButtonClassName = cn(secondaryButtonClassName, 'w-9 p-0');
6153

6254
const Header: React.FC = () => {
6355
const location = useLocation();

src/components/Layout/MDXWrapper.tsx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,31 @@ import { navigate, PageProps } from 'gatsby';
1313
import CodeSnippet from '@ably/ui/core/CodeSnippet';
1414
import type { CodeSnippetProps, SDKType } from '@ably/ui/core/CodeSnippet';
1515
import cn from '@ably/ui/core/utils/cn';
16+
1617
import { getRandomChannelName } from '../blocks/software/Code/get-random-channel-name';
18+
import Aside from '../blocks/dividers/Aside';
1719

18-
import PageTitle from '../PageTitle';
19-
import { Frontmatter, PageContextType } from './Layout';
20-
import { MarkdownProvider } from '../Markdown';
21-
import Article from '../Article';
2220
import If from './mdx/If';
2321
import { useCopyableHeaders } from './mdx/headers';
24-
import { useLayoutContext } from 'src/contexts/layout-context';
25-
import Aside from '../blocks/dividers/Aside';
26-
import { HtmlComponentPropsData } from '../html-component-props';
27-
import { languageData } from 'src/data/languages';
28-
import { ActivePage } from './utils/nav';
2922
import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from './mdx/tables';
3023
import { Tiles } from './mdx/tiles';
24+
import { PageHeader } from './mdx/PageHeader';
25+
26+
import { Frontmatter, PageContextType } from './Layout';
27+
import { ActivePage } from './utils/nav';
28+
29+
import { HtmlComponentPropsData } from '../html-component-props';
30+
import { MarkdownProvider } from '../Markdown';
31+
32+
import Article from '../Article';
3133
import { Head } from '../Head';
34+
35+
import UserContext from 'src/contexts/user-context';
36+
import { useLayoutContext } from 'src/contexts/layout-context';
37+
import { languageData } from 'src/data/languages';
3238
import { useSiteMetadata } from 'src/hooks/use-site-metadata';
33-
import { ProductName } from 'src/templates/template-data';
3439
import { getMetaTitle } from '../common/meta-title';
35-
import UserContext from 'src/contexts/user-context';
40+
import { ProductName } from 'src/templates/template-data';
3641

3742
type MDXWrapperProps = PageProps<unknown, PageContextType>;
3843

@@ -47,6 +52,8 @@ type Replacement = {
4752
replacer: () => string;
4853
};
4954

55+
type ElementProps = { className?: string; children?: ReactNode };
56+
5057
const SDKContext = createContext<SDKContextType | undefined>(undefined);
5158

5259
const useSDK = () => {
@@ -114,10 +121,12 @@ const WrappedCodeSnippet: React.FC<{ activePage: ActivePage } & CodeSnippetProps
114121
return null;
115122
}
116123

117-
const preElement = child as ReactElement<{ children?: ReactNode }>;
118-
const codeElement = isValidElement(preElement.props?.children) ? (preElement.props.children as ReactElement) : null;
124+
const preElement = child as ReactElement<ElementProps>;
125+
const codeElement = isValidElement(preElement.props?.children)
126+
? (preElement.props.children as ReactElement<ElementProps>)
127+
: null;
119128

120-
if (!codeElement || !codeElement.props?.className) {
129+
if (!codeElement || !codeElement.props.className) {
121130
return null;
122131
}
123132

@@ -222,7 +231,7 @@ const MDXWrapper: React.FC<MDXWrapperProps> = ({ children, pageContext, location
222231
Tiles,
223232
}}
224233
>
225-
<PageTitle>{title}</PageTitle>
234+
<PageHeader title={title} description={description} />
226235
{children}
227236
</MarkdownProvider>
228237
</Article>
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React, { useMemo } from 'react';
2+
import Icon from '@ably/ui/core/Icon';
3+
import { LanguageSelector } from '../LanguageSelector';
4+
import { track } from '@ably/ui/core/insights';
5+
import * as Tooltip from '@radix-ui/react-tooltip';
6+
import { productData } from 'src/data';
7+
import { languageInfo } from 'src/data/languages';
8+
import { useLayoutContext } from 'src/contexts/layout-context';
9+
import { IconName } from '@ably/ui/core/Icon/types';
10+
import { tooltipContentClassName } from '../utils/styles';
11+
12+
type PageHeaderProps = {
13+
title: string;
14+
description: string;
15+
};
16+
17+
export const PageHeader: React.FC<PageHeaderProps> = ({ title, description }) => {
18+
const { activePage } = useLayoutContext();
19+
const { language, product, page } = activePage;
20+
21+
const llmLinks = useMemo(() => {
22+
const prompt = `Tell me more about ${product ? productData[product]?.nav.name : 'Ably'}'s '${page.name}' feature from https://ably.com${page.link}${language ? ` for ${languageInfo[language]?.label}` : ''}`;
23+
const gptPath = `https://chatgpt.com/?q=${encodeURIComponent(prompt)}`;
24+
const claudePath = `https://claude.ai/new?q=${encodeURIComponent(prompt)}`;
25+
26+
return [
27+
{ model: 'gpt', label: 'ChatGPT', icon: 'icon-tech-openai', link: gptPath },
28+
{ model: 'claude', label: 'Claude (must be logged in)', icon: 'icon-tech-claude-mono', link: claudePath },
29+
];
30+
}, [product, page.name, page.link, language]);
31+
32+
return (
33+
<div className="my-8">
34+
<h1 className="ui-text-h1 mb-4">{title}</h1>
35+
<p className="text-neutral-800 dark:text-neutral-500 mb-8 font-serif italic tracking-tight text-lg leading-normal">
36+
{description}
37+
</p>
38+
39+
<div className="flex items-center gap-5">
40+
{activePage.languages.length > 0 && (
41+
<div className="flex-shrink-0 border-r border-neutral-300 dark:border-neutral-1000 pr-5">
42+
<LanguageSelector />
43+
</div>
44+
)}
45+
46+
<div className="flex items-center gap-0.5">
47+
<span className="text-p4 font-semibold text-neutral-900 dark:text-neutral-400 mr-1.5">Open in </span>
48+
<Tooltip.Provider delayDuration={0} disableHoverableContent>
49+
{llmLinks.map(({ model, label, icon, link }) => (
50+
<Tooltip.Root key={model}>
51+
<Tooltip.Trigger asChild>
52+
<a
53+
key={model}
54+
href={link}
55+
target="_blank"
56+
rel="noopener noreferrer"
57+
className="flex text-neutral-900 dark:text-neutral-400 cursor-pointer p-1.5"
58+
onClick={() => {
59+
track('llm_link_clicked', {
60+
model,
61+
location: location.pathname,
62+
link,
63+
});
64+
}}
65+
>
66+
<Icon name={icon as IconName} size="20px" />
67+
</a>
68+
</Tooltip.Trigger>
69+
<Tooltip.Portal>
70+
<Tooltip.Content className={tooltipContentClassName}>{label}</Tooltip.Content>
71+
</Tooltip.Portal>
72+
</Tooltip.Root>
73+
))}
74+
</Tooltip.Provider>
75+
</div>
76+
</div>
77+
</div>
78+
);
79+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import cn from '@ably/ui/core/utils/cn';
2+
3+
export const tooltipContentClassName = cn(
4+
'px-2 py-1 bg-neutral-1000 dark:bg-neutral-300 text-neutral-200 dark:text-neutral-1100 ui-text-p3 font-medium rounded-lg relative z-50 mt-2',
5+
'data-[state=closed]:animate-[tooltipExit_0.25s_ease-in-out]',
6+
'data-[state=delayed-open]:animate-[tooltipEntry_0.25s_ease-in-out]',
7+
);
8+
9+
export const secondaryButtonClassName =
10+
'focus-base flex items-center justify-center gap-2 px-4 py-[7px] h-9 ui-text-label4 text-neutral-1300 dark:text-neutral-000 rounded border border-neutral-400 dark:border-neutral-900 hover:border-neutral-600 dark:hover:border-neutral-700';
11+
12+
export const iconButtonClassName = cn(secondaryButtonClassName, 'w-9 p-0');

0 commit comments

Comments
 (0)