Skip to content

Commit c7a45a8

Browse files
authored
feat(docs): add .md docs pages and LLM dropdown
Signed-off-by: rpavlini <[email protected]>
1 parent 696211f commit c7a45a8

File tree

10 files changed

+680
-90
lines changed

10 files changed

+680
-90
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
.dropdownMenuTrigger {
2+
display: flex;
3+
align-items: center;
4+
padding: 0.25rem 0.5rem;
5+
gap: 0.5rem;
6+
border: 1px solid var(--border-color);
7+
border-radius: 0.25rem;
8+
9+
background-color: var(--block-bg-color);
10+
color: var(--foreground-color);
11+
12+
font-size: 0.875rem;
13+
line-height: 1rem;
14+
font-weight: 500;
15+
user-select: none;
16+
17+
&:focus,
18+
&:hover,
19+
&[data-state='open'] {
20+
background-color: var(--cta-surface-neutral-primary);
21+
}
22+
cursor: pointer;
23+
}
24+
25+
.dropdownMenuContent {
26+
position: relative;
27+
z-index: 50;
28+
min-width: 8rem;
29+
max-height: var(--radix-dropdownMenucontent-available-height);
30+
padding: 0.25rem;
31+
overflow: hidden auto;
32+
transform-origin: var(--radix-dropdownMenucontent-transform-origin);
33+
animation-duration: 0.2s;
34+
animation-timing-function: ease-out;
35+
border: 1px solid var(--border-color);
36+
border-radius: 0.375rem;
37+
background-color: var(--block-bg-color);
38+
box-shadow:
39+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
40+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
41+
color: var(--text-color);
42+
43+
&[data-side='bottom'] {
44+
animation-name: slideUpAndFade;
45+
}
46+
47+
.dropdownMenuItem {
48+
display: flex;
49+
align-items: center;
50+
padding: 0.5rem 0.5rem;
51+
border-radius: 0.25rem;
52+
outline: none;
53+
font-size: 0.875rem;
54+
line-height: 1rem;
55+
cursor: pointer;
56+
user-select: none;
57+
gap: 0.5rem;
58+
color: var(--foreground-color);
59+
60+
& > svg {
61+
flex-shrink: 0;
62+
width: 14px;
63+
height: 14px;
64+
pointer-events: none;
65+
}
66+
67+
&:focus {
68+
background-color: var(--cta-surface-neutral-primary);
69+
}
70+
71+
& > svg:last-child {
72+
margin-left: auto;
73+
opacity: 0.5;
74+
}
75+
}
76+
}
77+
78+
@keyframes slideUpAndFade {
79+
from {
80+
opacity: 0;
81+
transform: translateY(2px);
82+
}
83+
to {
84+
opacity: 1;
85+
transform: translateY(0);
86+
}
87+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
'use client'
2+
3+
import {
4+
DropdownMenu,
5+
DropdownMenuContent,
6+
DropdownMenuItem,
7+
DropdownMenuPortal,
8+
DropdownMenuTrigger,
9+
} from '@radix-ui/react-dropdown-menu'
10+
import { clsx as cn } from 'clsx'
11+
import { GTProvider, T } from 'gt-react'
12+
import { ArrowUpRightIcon, ChevronDownIcon } from 'lucide-react'
13+
import loadTranslations from 'src/i18n/loadTranslations'
14+
15+
import gtConfig from '../../../gt.config.json'
16+
import styles from './OpenPageDropdown.module.scss'
17+
18+
function getPromptUrl(baseURL: string, url: string) {
19+
return `${baseURL}?q=${encodeURIComponent(
20+
`Read ${url} so I can ask questions about it.`
21+
)}`
22+
}
23+
24+
const menuItems = {
25+
claude: (url: string) => (
26+
<a
27+
href={getPromptUrl('https://claude.ai/new', url)}
28+
target="_blank"
29+
rel="noopener noreferrer"
30+
>
31+
<svg
32+
xmlns="http://www.w3.org/2000/svg"
33+
viewBox="0 0 24 24"
34+
className={styles.icon}
35+
>
36+
<path
37+
d="m4.714 15.956 4.718-2.648.079-.23-.08-.128h-.23l-.79-.048-2.695-.073-2.337-.097-2.265-.122-.57-.121-.535-.704.055-.353.48-.321.685.06 1.518.104 2.277.157 1.651.098 2.447.255h.389l.054-.158-.133-.097-.103-.098-2.356-1.596-2.55-1.688-1.336-.972-.722-.491L2 6.223l-.158-1.008.655-.722.88.06.225.061.893.686 1.906 1.476 2.49 1.833.364.304.146-.104.018-.072-.164-.274-1.354-2.446-1.445-2.49-.644-1.032-.17-.619a2.972 2.972 0 0 1-.103-.729L6.287.133 6.7 0l.995.134.42.364.619 1.415L9.735 4.14l1.555 3.03.455.898.243.832.09.255h.159V9.01l.127-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.583.28.48.685-.067.444-.286 1.851-.558 2.903-.365 1.942h.213l.243-.242.983-1.306 1.652-2.064.728-.82.85-.904.547-.431h1.032l.759 1.129-.34 1.166-1.063 1.347-.88 1.142-1.263 1.7-.79 1.36.074.11.188-.02 2.853-.606 1.542-.28 1.84-.315.832.388.09.395-.327.807-1.967.486-2.307.462-3.436.813-.043.03.049.061 1.548.146.662.036h1.62l3.018.225.79.522.473.638-.08.485-1.213.62-1.64-.389-3.825-.91-1.31-.329h-.183v.11l1.093 1.068 2.003 1.81 2.508 2.33.127.578-.321.455-.34-.049-2.204-1.657-.85-.747-1.925-1.62h-.127v.17l.443.649 2.343 3.521.122 1.08-.17.353-.607.213-.668-.122-1.372-1.924-1.415-2.168-1.141-1.943-.14.08-.674 7.254-.316.37-.728.28-.607-.461-.322-.747.322-1.476.388-1.924.316-1.53.285-1.9.17-.632-.012-.042-.14.018-1.432 1.967-2.18 2.945-1.724 1.845-.413.164-.716-.37.066-.662.401-.589 2.386-3.036 1.439-1.882.929-1.086-.006-.158h-.055L4.138 18.56l-1.13.146-.485-.456.06-.746.231-.243 1.907-1.312Z"
38+
fill="currentColor"
39+
/>
40+
</svg>
41+
<T>Open in Claude</T>
42+
<ArrowUpRightIcon size={13} />
43+
</a>
44+
),
45+
chatgpt: (url: string) => (
46+
<a
47+
href={getPromptUrl('https://chatgpt.com', url)}
48+
target="_blank"
49+
rel="noopener noreferrer"
50+
>
51+
<svg
52+
xmlns="http://www.w3.org/2000/svg"
53+
viewBox="0 0 24 24"
54+
className={styles.icon}
55+
>
56+
<path
57+
d="M22.282 9.821a5.985 5.985 0 0 0-.516-4.91 6.046 6.046 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a5.985 5.985 0 0 0-3.998 2.9 6.046 6.046 0 0 0 .743 7.097 5.98 5.98 0 0 0 .51 4.911 6.051 6.051 0 0 0 6.515 2.9A5.985 5.985 0 0 0 13.26 24a6.056 6.056 0 0 0 5.772-4.206 5.99 5.99 0 0 0 3.997-2.9 6.056 6.056 0 0 0-.747-7.073zM13.26 22.43a4.476 4.476 0 0 1-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 0 0 .392-.681v-6.737l2.02 1.168a.071.071 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494zM3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085 4.783 2.759a.771.771 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646zM2.34 7.896a4.485 4.485 0 0 1 2.366-1.973V11.6a.766.766 0 0 0 .388.676l5.815 3.355-2.02 1.168a.076.076 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855-5.833-3.387L15.119 7.2a.076.076 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667zm2.01-3.023-.141-.085-4.774-2.782a.776.776 0 0 0-.785 0L9.409 9.23V6.897a.066.066 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08-4.778 2.758a.795.795 0 0 0-.393.681zm1.097-2.365 2.602-1.5 2.607 1.5v2.999l-2.597 1.5-2.607-1.5Z"
58+
fill="currentColor"
59+
/>
60+
</svg>
61+
<T>Open in ChatGPT</T>
62+
<ArrowUpRightIcon size={13} />
63+
</a>
64+
),
65+
}
66+
67+
interface Props {
68+
url: string
69+
className?: string
70+
}
71+
72+
function OpenPageDropdownContent({ url, className }: Props) {
73+
return (
74+
<DropdownMenu>
75+
<DropdownMenuTrigger
76+
className={cn(styles.dropdownMenuTrigger, className)}
77+
aria-label="Open Page LLM Actions Menu"
78+
>
79+
<T>Open</T>
80+
<ChevronDownIcon size={14} />
81+
</DropdownMenuTrigger>
82+
<DropdownMenuPortal>
83+
<DropdownMenuContent
84+
align="end"
85+
className={styles.dropdownMenuContent}
86+
sideOffset={4}
87+
>
88+
{Object.entries(menuItems).map(([key, value]) => (
89+
<DropdownMenuItem
90+
key={key}
91+
asChild
92+
className={styles.dropdownMenuItem}
93+
>
94+
{value(url)}
95+
</DropdownMenuItem>
96+
))}
97+
</DropdownMenuContent>
98+
</DropdownMenuPortal>
99+
</DropdownMenu>
100+
)
101+
}
102+
103+
export const OpenPageDropdown = ({
104+
locale,
105+
...props
106+
}: { locale: string } & Props) => {
107+
return (
108+
<GTProvider
109+
config={gtConfig}
110+
loadTranslations={loadTranslations}
111+
locale={locale}
112+
projectId={import.meta.env.PUBLIC_VITE_GT_PROJECT_ID}
113+
devApiKey={import.meta.env.PUBLIC_VITE_GT_API_KEY}
114+
>
115+
<OpenPageDropdownContent {...props} />
116+
</GTProvider>
117+
)
118+
}
Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,118 @@
11
---
2+
import { CopyButton } from './buttons/CopyButton'
3+
import { LinkButton } from './buttons/LinkButton'
4+
import { OpenPageDropdown } from './OpenPageDropdown/OpenPageDropdown'
25
import { PAGE_TITLE_ID } from './TableOfContent/constants'
6+
7+
const { origin, pathname } = Astro.url
8+
const normalizedPath = pathname.replace(/\/$/, '')
9+
const markdownUrl = `${origin}${normalizedPath || '/docs/en'}.md`
10+
11+
const markdownRaw = Astro.props.entry.body
312
---
413

514
{
615
!Astro.props.entry.data.hideTitleOnPage && (
716
<h1 id={PAGE_TITLE_ID}>{Astro.props.entry.data.title}</h1>
817
)
918
}
10-
{
11-
(Astro.props.entry.data.licence || Astro.props.entry.data.distribution) && (
12-
<dl class="tiers-distribution-list">
13-
<div>
14-
<>
15-
<dt>Licence:</dt>
16-
<dd>{Astro.props.entry.data.licence}</dd>
17-
</>
18-
</div>
19-
<div>
20-
<>
21-
<dt>Distribution:</dt>
22-
<dd>{Astro.props.entry.data.distribution}</dd>
23-
</>
24-
</div>
25-
</dl>
26-
)
27-
}
19+
<div class="title-actions">
20+
<CopyButton client:load value={markdownRaw} variant="ghost"
21+
>{Astro.props.labels['header.copyForLlms']}</CopyButton
22+
>
23+
<LinkButton
24+
client:load
25+
href={markdownUrl}
26+
target="_blank"
27+
variant="ghost"
28+
className="desktop-only"
29+
>
30+
<svg stroke-linejoin="round" viewBox="0 0 22 16" height="16" width="16">
31+
<path
32+
fill-rule="evenodd"
33+
clip-rule="evenodd"
34+
d="M19.5 2.25H2.5C1.80964 2.25 1.25 2.80964 1.25 3.5V12.5C1.25 13.1904 1.80964 13.75 2.5 13.75H19.5C20.1904 13.75 20.75 13.1904 20.75 12.5V3.5C20.75 2.80964 20.1904 2.25 19.5 2.25ZM2.5 1C1.11929 1 0 2.11929 0 3.5V12.5C0 13.8807 1.11929 15 2.5 15H19.5C20.8807 15 22 13.8807 22 12.5V3.5C22 2.11929 20.8807 1 19.5 1H2.5ZM3 4.5H4H4.25H4.6899L4.98715 4.82428L7 7.02011L9.01285 4.82428L9.3101 4.5H9.75H10H11V5.5V11.5H9V7.79807L7.73715 9.17572L7 9.97989L6.26285 9.17572L5 7.79807V11.5H3V5.5V4.5ZM15 8V4.5H17V8H19.5L17 10.5L16 11.5L15 10.5L12.5 8H15Z"
35+
fill="currentColor"
36+
>
37+
</path>
38+
</svg>
39+
{Astro.props.labels['header.viewAsMarkdown']}
40+
</LinkButton>
41+
<OpenPageDropdown
42+
client:load
43+
locale={Astro.props.locale}
44+
url={markdownUrl}
45+
className="right"
46+
/>
2847

29-
<style>
30-
.tiers-distribution-list {
31-
margin: 0;
32-
border-left: 1px solid var(--hover-color);
33-
padding-left: 8px;
34-
display: flex;
35-
flex-direction: column;
36-
gap: 4px;
37-
> div {
38-
display: inline-flex;
39-
font-family: 'Inter', sans-serif;
40-
font-weight: 500;
41-
font-size: 0.75rem;
42-
line-height: 1.4;
43-
letter-spacing: -0.02em;
44-
> dt {
45-
color: var(--secondary-text-color);
48+
{
49+
(Astro.props.entry.data.licence || Astro.props.entry.data.distribution) && (
50+
<dl class="tiers-distribution-list">
51+
<div>
52+
<>
53+
<dt>Licence:</dt>
54+
<dd>{Astro.props.entry.data.licence}</dd>
55+
</>
56+
</div>
57+
<div>
58+
<>
59+
<dt>Distribution:</dt>
60+
<dd>{Astro.props.entry.data.distribution}</dd>
61+
</>
62+
</div>
63+
</dl>
64+
)
65+
}
66+
67+
<style>
68+
.tiers-distribution-list {
69+
margin: 0;
70+
border-left: 1px solid var(--hover-color);
71+
padding-left: 8px;
72+
display: flex;
73+
flex-direction: column;
74+
gap: 4px;
75+
> div {
76+
display: inline-flex;
77+
font-family: 'Inter', sans-serif;
78+
font-weight: 500;
79+
font-size: 0.75rem;
80+
line-height: 1.4;
81+
letter-spacing: -0.02em;
82+
> dt {
83+
color: var(--secondary-text-color);
84+
}
85+
> dd {
86+
color: var(--primary-text-color);
87+
margin-left: 1ch;
88+
}
4689
}
47-
> dd {
48-
color: var(--primary-text-color);
49-
margin-left: 1ch;
90+
}
91+
h1 {
92+
margin-bottom: unset !important;
93+
}
94+
95+
.title-actions {
96+
padding-bottom: 12px;
97+
border-bottom: 1px solid var(--border-color);
98+
font-size: 0.8125rem;
99+
display: flex;
100+
gap: 8px;
101+
align-items: center;
102+
}
103+
104+
.title-actions:first-child {
105+
margin-top: 40px;
106+
}
107+
108+
.right {
109+
margin-left: auto;
110+
}
111+
112+
@media (max-width: 650px) {
113+
.desktop-only {
114+
display: none;
50115
}
51116
}
52-
}
53-
h1 {
54-
margin-bottom: unset !important;
55-
}
56-
</style>
117+
</style>
118+
</div>

0 commit comments

Comments
 (0)