Skip to content

Commit a867640

Browse files
authored
Fix the /code page (#2133)
* Fix the /code page * Fail get-github-info.ts on errors (apart from deployments) * Fix malformed GitHub link, tweak the markup for the e2e test sake * Add a test for the code page
1 parent ad865a9 commit a867640

File tree

10 files changed

+1720
-208
lines changed

10 files changed

+1720
-208
lines changed

scripts/sort-libraries/get-github-stats.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ type GitHubStatsFetchResponse =
8080
}
8181
}
8282

83-
type GitHubInfo = {
83+
export type GitHubInfo = {
8484
hasCommitsInLast3Months: boolean
8585
stars: number
8686
formattedStars: string

src/app/conf/_design-system/button.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export declare namespace ButtonProps {
99
export interface BaseProps {
1010
size?: Size
1111
variant?: Variant
12+
isIconButton?: boolean
1213
}
1314

1415
export interface AnchorProps
@@ -58,13 +59,21 @@ export type ButtonProps =
5859
export function Button(props: ButtonProps) {
5960
const className = clsx(
6061
"relative flex items-center justify-center gap-2.5 font-normal text-base/none text-neu-0 bg-neu-900 hover:bg-neu-800 active:bg-neu-700 font-sans h-14 px-8 data-[size=md]:h-12 data-[variant=secondary]:bg-neu-100 dark:data-[variant=secondary]:bg-neu-100/80 dark:data-[variant=secondary]:hover:bg-neu-200/50 data-[variant=secondary]:text-neu-900 data-[variant=secondary]:hover:bg-neu-200/75 data-[variant=secondary]:active:bg-neu-200/90 data-[variant=tertiary]:bg-neu-100 data-[variant=tertiary]:text-neu-900 data-[variant=tertiary]:hover:bg-neu-200 data-[variant=tertiary]:active:bg-neu-300 gql-focus-visible [aria-disabled]:bg-neu-800 aria-disabled:pointer-events-none dark:data-[variant=tertiary]:bg-neu-900/10 dark:data-[variant=tertiary]:text-neu-900 dark:data-[variant=tertiary]:hover:bg-neu-900/[.125] dark:data-[variant=tertiary]:active:bg-neu-800/20 dark:data-[variant=tertiary]:ring-1 dark:data-[variant=tertiary]:ring-inset dark:data-[variant=tertiary]:ring-neu-900/20",
62+
props.isIconButton && "!p-2 h-min",
6163
props.className,
6264
)
6365

6466
const styleAttrs = { "data-size": props.size, "data-variant": props.variant }
6567

6668
if ("href" in props && typeof props.href === "string") {
67-
const { className: _1, size: _2, disabled, children, ...rest } = props
69+
const {
70+
className: _1,
71+
size: _2,
72+
isIconButton: _3,
73+
disabled,
74+
children,
75+
...rest
76+
} = props
6877

6978
if (disabled) (rest as { href?: string }).href = undefined
7079

@@ -81,7 +90,14 @@ export function Button(props: ButtonProps) {
8190
}
8291

8392
if (props.as) {
84-
const { className: _1, size: _2, children, as, ...rest } = props
93+
const {
94+
className: _1,
95+
size: _2,
96+
isIconButton: _3,
97+
children,
98+
as,
99+
...rest
100+
} = props
85101
const Root = as as "span" // we don't need HTMLDivElement type
86102
return (
87103
<Root className={className} {...styleAttrs} {...rest}>
@@ -90,7 +106,7 @@ export function Button(props: ButtonProps) {
90106
)
91107
}
92108

93-
const { className: _1, size: _2, children, ...rest } = props
109+
const { className: _1, size: _2, isIconButton: _3, children, ...rest } = props
94110

95111
return (
96112
<button className={className} {...styleAttrs} {...rest}>

src/app/conf/_design-system/tag.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export function Tag({ color, children, style, className, ...rest }: TagProps) {
1414
{...rest}
1515
>
1616
<span
17-
className="absolute inset-0 opacity-20"
17+
// eslint-disable-next-line tailwindcss/no-custom-classname
18+
className="Tag--bg absolute inset-0 opacity-20"
1819
style={{
1920
backgroundColor: color,
2021
}}

src/code/language-support/python/client/ql.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name: ql
33
description: Non intrusive python GraphQL client wrapped around pydantic.
44
url: https://dsal3389.github.io/ql/
5-
github: https://github.com/dsal3389/ql
5+
github: dsal3389/ql
66
---
77

88
GraphQL client library, wrapped around pydantic classes for type validation,

src/components/card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function Card({
1515
return (
1616
<Component
1717
className={clsx(
18-
"border border-zinc-200 bg-white p-8 dark:border-[#414141] dark:bg-neutral-800 lg:p-12",
18+
"border border-neu-200 bg-neu-0 p-8 dark:border-neu-50 lg:p-12",
1919
"rounded-none",
2020
isLink && [
2121
"hover:!border-primary hover:shadow-2xl hover:shadow-primary/10 hover:dark:bg-neutral-700/50",

src/components/tools-and-libraries.tsx

Lines changed: 92 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
RubyGemsIcon,
88
ChevronLeftIcon,
99
} from "@/icons"
10-
import { Card, Tag } from "@/components"
10+
import { Card } from "@/components"
1111
import NextLink from "next/link"
1212
import NextHead from "next/head"
1313
import { useMounted } from "nextra/hooks"
@@ -30,6 +30,17 @@ import {
3030
import { clsx } from "clsx"
3131
import { getComponents } from "nextra-theme-docs"
3232
import { RadioGroup, RadioGroupItem } from "@/components/radio"
33+
import { Button } from "@/app/conf/_design-system/button"
34+
import { Tag } from "@/app/conf/_design-system/tag"
35+
36+
type PackageInfo = {
37+
name: string
38+
description: string
39+
url: string
40+
github: string
41+
npm: string
42+
gem?: string
43+
}
3344

3445
type CodePageProps = {
3546
allTags: {
@@ -39,14 +50,7 @@ type CodePageProps = {
3950
}[]
4051
data: {
4152
tags: string[]
42-
frontMatter: {
43-
name: string
44-
description: string
45-
url: string
46-
github: string
47-
npm: string
48-
gem?: string
49-
}
53+
frontMatter: PackageInfo
5054
stars?: number
5155
formattedStars?: string
5256
lastRelease?: string
@@ -187,11 +191,9 @@ export function CodePage({ allTags, data }: CodePageProps) {
187191
key="meta-og-description"
188192
/>
189193
</NextHead>
190-
<div className="container py-10 md:py-20">
191-
<h1 className="text-4xl font-extrabold md:text-7xl">
192-
Code Using GraphQL
193-
</h1>
194-
<div className="my-10 flex max-w-[700px] items-center border-b border-current pb-2.5 text-2xl font-extrabold">
194+
<div className="container py-8 md:pt-16">
195+
<h1 className="typography-h1">Code Using GraphQL</h1>
196+
<div className="typography-h3 my-10 flex max-w-[700px] items-center border-b border-current pb-2.5">
195197
<div
196198
className={clsx(
197199
"flex shrink-0",
@@ -201,6 +203,7 @@ export function CodePage({ allTags, data }: CodePageProps) {
201203
{inputTags}
202204
</div>
203205
<input
206+
// TODO: This should also do a fuzzy full text search, not just search on tags.
204207
value={search}
205208
onChange={e => setSearch(e.target.value)}
206209
onKeyDown={handleKeyDown}
@@ -213,26 +216,27 @@ export function CodePage({ allTags, data }: CodePageProps) {
213216
/>
214217
<MagnifyingGlassIcon className="shrink-0" />
215218
</div>
216-
<div className="roboto-mono flex flex-wrap gap-3 md:gap-5">
219+
<div className="flex flex-wrap gap-2">
217220
{queryTags.map(({ tag, count, name }) => {
218221
const isTagMatchSearch =
219222
!search || name.toLowerCase().includes(search.toLowerCase())
220223
if (!isTagMatchSearch) return
224+
221225
return (
222226
<NextLink
223227
href={`/community/tools-and-libraries/?tags=${tag}`}
224228
key={tag}
225229
data-tag={tag}
226-
className={clsx(
227-
"tag",
228-
mounted &&
229-
(queryParamsTags as string[]).includes(tag) &&
230-
"bg-primary",
231-
)}
232230
onClick={handleQuery}
233231
title={`${mounted && (queryParamsTags as string[]).includes(tag) ? "Remove" : "Add"} tag "${name}"`}
232+
className="flex"
234233
>
235-
{name} ({count})
234+
<Tag
235+
className="!capitalize lg:!text-sm [&:has(:hover)_.Tag--bg]:opacity-50"
236+
color="hsl(var(--color-neu-500)/.8)"
237+
>
238+
{name} ({count})
239+
</Tag>
236240
</NextLink>
237241
)
238242
})}
@@ -258,7 +262,8 @@ export function CodePage({ allTags, data }: CodePageProps) {
258262
</div>
259263
</RadioGroup>
260264

261-
<div className="container grid gap-10 py-20 md:grid-cols-2">
265+
{/* todo: add md:*:h-full when the readme opens in a modal */}
266+
<div className="container grid gap-2 py-8 md:grid-cols-2 md:gap-4">
262267
{(sort === "alphabetical"
263268
? [...newData].sort((a, b) =>
264269
a.frontMatter.name.localeCompare(b.frontMatter.name),
@@ -273,75 +278,46 @@ export function CodePage({ allTags, data }: CodePageProps) {
273278
license,
274279
compiledSource,
275280
}) => {
276-
const { name, description, url, github, npm, gem } = frontMatter
281+
const { name, description } = frontMatter
277282
const hasMetadata = formattedStars || lastRelease || license
278283
return (
279284
<Card
280285
key={`${name}${tags.toString()}`}
281286
className={clsx(
282-
"h-max !p-0",
287+
"flex h-max flex-col !p-0",
283288
"min-w-0", // hack to avoid overflow when opening details
284289
)}
285290
>
286-
<div className="flex grow flex-col gap-7 p-8 lg:p-12">
287-
<div className="flex items-center gap-6 [&_a:hover]:text-primary [&_a]:transition-colors">
288-
<span className="grow break-all text-3xl font-extrabold">
289-
{name}
290-
</span>
291-
{url && (
292-
<a href={url} target="_blank" rel="noreferrer">
293-
<GlobeIcon />
294-
</a>
295-
)}
296-
{github && (
297-
<a
298-
href={`https://github.com/${github}`}
299-
target="_blank"
300-
rel="noreferrer"
301-
>
302-
<GitHubIcon />
303-
</a>
304-
)}
305-
{npm && (
306-
<a
307-
href={`https://npmjs.com/package/${npm}`}
308-
target="_blank"
309-
rel="noreferrer"
310-
>
311-
<NPMIcon />
312-
</a>
313-
)}
314-
{gem && (
315-
<a
316-
href={`https://rubygems.org/gems/${gem}`}
317-
target="_blank"
318-
rel="noreferrer"
319-
>
320-
<RubyGemsIcon />
321-
</a>
322-
)}
323-
</div>
324-
<div className="roboto-mono flex gap-2">
291+
<article className="flex grow flex-col gap-7 p-4 lg:p-8">
292+
<header className="flex items-center gap-2">
293+
<span className="typography-h3 grow break-all">{name}</span>
294+
<PackageLinks data={frontMatter} />
295+
</header>
296+
<div className="flex gap-2">
325297
{tags.map(tag => (
326-
<Tag
298+
<NextLink
327299
key={tag}
328-
// @ts-expect-error -- fixme
329-
as={NextLink}
330300
href={`/community/tools-and-libraries/?tags=${tag}`}
331-
className="cursor-pointer transition-colors hover:!bg-primary hover:text-white"
301+
className="flex [&:has(:hover)_.Tag--bg]:opacity-50"
332302
>
333-
{allTagsMap.get(tag)!.name}
334-
</Tag>
303+
<Tag
304+
className="cursor-pointer !capitalize"
305+
color="hsl(var(--color-neu-400))" // todo: tags could be color coded like on the conference page
306+
>
307+
{allTagsMap.get(tag)!.name}
308+
</Tag>
309+
</NextLink>
335310
))}
336311
</div>
337312
<Markdown className="line-clamp-4 grow lg:text-lg [&_a]:text-primary">
338313
{description}
339314
</Markdown>
315+
<div className="flex-1" />
340316
{hasMetadata && (
341317
<div
342318
className={clsx(
343319
"flex items-center gap-5 max-md:text-xs",
344-
"[&>:not(:last-child)]:border-r [&>:not(:last-child)]:border-gray-500 [&>:not(:last-child)]:pr-5",
320+
"[&>:not(:last-child)]:border-r [&>:not(:last-child)]:border-neu-500 [&>:not(:last-child)]:pr-5",
345321
)}
346322
>
347323
{lastRelease && <span>Last release {lastRelease}</span>}
@@ -354,14 +330,14 @@ export function CodePage({ allTags, data }: CodePageProps) {
354330
{license && <span>{license}</span>}
355331
</div>
356332
)}
357-
</div>
333+
</article>
358334

359335
{compiledSource && (
360-
<details className="bg-[#f0f0f0] dark:bg-[#2f2f2f]">
336+
<details className="bg-neu-100">
361337
<summary
362338
className={clsx(
363-
"flex justify-between px-8 py-5 font-bold text-primary lg:px-12 dark:[[open]>&]:shadow-[-5px_10px_30px_20px_#1b1b1b4d]",
364-
"[[open]>&]:shadow-[0_6px_21px_0_#1b1b1b33]",
339+
"flex justify-between px-8 py-5 text-primary lg:px-12 dark:[[open]>&]:shadow-[-5px_10px_30px_20px_#1b1b1b4d]",
340+
"[[open]>&]:bg-neu-200",
365341
"cursor-pointer",
366342
)}
367343
>
@@ -405,3 +381,44 @@ const RemoteContent = memo(function RemoteContent({
405381
})
406382
return <MDXContent components={components} />
407383
})
384+
385+
function PackageLinks({ data }: { data: PackageInfo }) {
386+
const { url, github, npm, gem } = data
387+
388+
return (
389+
<>
390+
{url && (
391+
<Button href={url} variant="tertiary" isIconButton>
392+
<GlobeIcon className="size-5" />
393+
</Button>
394+
)}
395+
{github && (
396+
<Button
397+
href={`https://github.com/${github}`}
398+
variant="tertiary"
399+
isIconButton
400+
>
401+
<GitHubIcon className="size-5" />
402+
</Button>
403+
)}
404+
{npm && (
405+
<Button
406+
href={`https://npmjs.com/package/${npm}`}
407+
variant="tertiary"
408+
isIconButton
409+
>
410+
<NPMIcon className="size-5" viewBox="0 0 30 30" />
411+
</Button>
412+
)}
413+
{gem && (
414+
<Button
415+
href={`https://rubygems.org/gems/${gem}`}
416+
variant="tertiary"
417+
isIconButton
418+
>
419+
<RubyGemsIcon className="size-5" />
420+
</Button>
421+
)}
422+
</>
423+
)
424+
}

0 commit comments

Comments
 (0)