Skip to content

Commit de5aa34

Browse files
committed
1.2.0
1 parent 26f930d commit de5aa34

File tree

14 files changed

+248
-35
lines changed

14 files changed

+248
-35
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { CodeBlock } from "@/components/CodeBlock";
2+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
3+
import { EndpointCodeExamples } from "app/api/public/[...route]/public-api.types";
4+
5+
export function CodeExamples({ examples }: { examples: EndpointCodeExamples }) {
6+
const keys = Object.keys(examples) as (keyof EndpointCodeExamples)[];
7+
8+
return (
9+
<div className="flex flex-col gap-4">
10+
<Tabs defaultValue={keys[0]}>
11+
<TabsList>
12+
{keys.map((key) => (
13+
<TabsTrigger key={key} value={key}>
14+
{key}
15+
</TabsTrigger>
16+
))}
17+
</TabsList>
18+
{keys.map((key) => (
19+
<TabsContent key={key} value={key}>
20+
<div className="flex flex-col gap-4">
21+
{examples[key].map((example) => (
22+
<CodeBlock key={example.description} hideHeader>
23+
{`// ${example.description}
24+
${example.code.trim()}
25+
`}
26+
</CodeBlock>
27+
))}
28+
</div>
29+
</TabsContent>
30+
))}
31+
</Tabs>
32+
</div>
33+
);
34+
}

apps/web/app/(docs)/docs/api/[endpointId]/page.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { ObjectRenderer } from "app/(docs)/ui/object-renderer";
2-
import { useParams } from "next/navigation";
32
import {
43
BASE_API_URL,
54
endpoints,
65
} from "app/api/public/[...route]/public-api.constants";
76
import { Metadata } from "next";
7+
import { CodeExamples } from "./code-examples";
8+
import { CodeBlock } from "@/components/CodeBlock";
89

910
type Props = {
1011
params: Promise<{ endpointId: string }>;
@@ -61,9 +62,11 @@ export default async function Endpoint(props: Props) {
6162
<ul className="mt-2 list-disc space-y-2 pl-4">
6263
{endpoint.headers?.map((header) => (
6364
<li key={header.key}>
64-
<div className="flex gap-2">
65+
<div className="flex items-center gap-2">
6566
<p className="font-medium">{header.key}</p>
66-
<p>{header.required ? "Required" : "Optional"}</p>
67+
<p className="text-xs text-zinc-400">
68+
{header.required ? "Required" : "Optional"}
69+
</p>
6770
</div>
6871
<p>{header.description}</p>
6972
</li>
@@ -77,9 +80,11 @@ export default async function Endpoint(props: Props) {
7780
<ul className="mt-2 list-disc space-y-2 pl-4">
7881
{endpoint.query?.map((query) => (
7982
<li key={query.key}>
80-
<div className="flex gap-2">
83+
<div className="flex items-center gap-2">
8184
<p className="font-medium">{query.key}</p>
82-
<p>{query.required ? "Required" : "Optional"}</p>
85+
<p className="text-xs text-zinc-400">
86+
{query.required ? "Required" : "Optional"}
87+
</p>
8388
</div>
8489
<p>{query.description}</p>
8590
</li>
@@ -97,13 +102,17 @@ export default async function Endpoint(props: Props) {
97102
<p className="font-medium">{status}</p>
98103
<p>{response.description}</p>
99104
</div>
100-
<pre className="mt-2 overflow-x-auto rounded-md bg-gray-100 p-4 text-xs">
101-
{response.example}
102-
</pre>
105+
<CodeBlock language="typescript">{response.example}</CodeBlock>
103106
</div>
104107
))}
105108
</div>
106109
</div>
110+
111+
<hr className="my-4" />
112+
<section>
113+
<h3 className="text-md font-medium">Usage</h3>
114+
<CodeExamples examples={endpoint.examples} />
115+
</section>
107116
</div>
108117
</>
109118
);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Checks if the code examples are valid with typescript
3+
*/
4+
5+
import { createZenblogClient } from "zenblog";
6+
7+
const zenblog = createZenblogClient({
8+
blogId: "doesnt-matter",
9+
});
10+
11+
const posts = await zenblog.posts.list({
12+
limit: 100,
13+
offset: 0,
14+
tags: ["tag1", "tag2"],
15+
category: "category-slug",
16+
author: "author-slug",
17+
});
18+
const postsBySlug = await zenblog.posts.get({
19+
slug: "slug",
20+
});
21+
22+
const categories = await zenblog.categories.list();
23+
const tags = await zenblog.tags.list();
24+
const authors = await zenblog.authors.list();
25+
const authorBySlug = await zenblog.authors.get({
26+
slug: "slug",
27+
});
28+
29+
console.log(posts);
30+
console.log(postsBySlug);
31+
console.log(categories);
32+
console.log(tags);
33+
console.log(authors);
34+
console.log(authorBySlug);

apps/web/app/api/public/[...route]/public-api.constants.ts

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,38 @@ export const posts: Endpoint = {
88
method: "GET",
99
title: "Post list",
1010
description: "Get posts for a blog",
11+
examples: {
12+
typescript: [
13+
{
14+
description: "Get posts for a blog",
15+
code: `const { data: posts } = await zenblog.posts.list()`,
16+
},
17+
{
18+
description: "Get posts for a blog filtered by a category",
19+
code: `const { data: posts } = await zenblog.posts.list({
20+
category: "news",
21+
})`,
22+
},
23+
{
24+
description: "Get posts limit results to 10",
25+
code: `const { data: posts } = await zenblog.posts.list({
26+
limit: 10,
27+
})`,
28+
},
29+
{
30+
description: "Get posts filtered by tag slugs",
31+
code: `const { data: posts } = await zenblog.posts.list({
32+
tags: ["tag1", "tag2"],
33+
})`,
34+
},
35+
{
36+
description: "Get posts filtered by author slug",
37+
code: `const { data: posts } = await zenblog.posts.list({
38+
author: "author-slug",
39+
})`,
40+
},
41+
],
42+
},
1143
query: [
1244
{
1345
key: "offset",
@@ -22,8 +54,7 @@ export const posts: Endpoint = {
2254
{
2355
key: "category",
2456
required: false,
25-
description:
26-
"The category slug to filter posts by. Example: &category=news",
57+
description: "The category slug to filter posts by. Ex: &category=news",
2758
},
2859
{
2960
key: "tags",
@@ -85,14 +116,36 @@ export const postBySlug: Endpoint = {
85116
title: "string",
86117
html_content: "string",
87118
slug: "string",
88-
category_name: "string",
89-
category_slug: "string",
90-
tags: "object",
91-
excerpt: "string",
92-
published_at: "string",
119+
category?: {
120+
name: "string",
121+
slug: "string",
122+
},
123+
tags?: [{
124+
name: "string",
125+
slug: "string",
126+
}],
127+
authors?: [{
128+
slug: "string",
129+
name: "string",
130+
image_url?: "string",
131+
website?: "string",
132+
twitter?: "string",
133+
}],
134+
excerpt: "string",
135+
published_at: "string",
93136
}`,
94137
},
95138
},
139+
examples: {
140+
typescript: [
141+
{
142+
description: "Get a post by its slug",
143+
code: `const { data: post } = await zenblog.posts.get({
144+
slug: "post-slug",
145+
})`,
146+
},
147+
],
148+
},
96149
};
97150
export const categories: Endpoint = {
98151
id: "categories",
@@ -117,6 +170,14 @@ export const categories: Endpoint = {
117170
}`,
118171
},
119172
},
173+
examples: {
174+
typescript: [
175+
{
176+
description: "Get the categories for a blog",
177+
code: `const { data: categories } = await zenblog.categories.list()`,
178+
},
179+
],
180+
},
120181
};
121182
export const tags: Endpoint = {
122183
id: "tags",
@@ -141,6 +202,14 @@ export const tags: Endpoint = {
141202
}`,
142203
},
143204
},
205+
examples: {
206+
typescript: [
207+
{
208+
description: "Get the tags for a blog",
209+
code: `const { data: tags } = await zenblog.tags.list()`,
210+
},
211+
],
212+
},
144213
};
145214

146215
export const authors: Endpoint = {
@@ -149,9 +218,14 @@ export const authors: Endpoint = {
149218
method: "GET",
150219
title: "Authors list",
151220
description: "Get the authors for a blog",
152-
typescriptExample: `
153-
const { data: authors } = await zenblogClient.authors.list()
154-
`,
221+
examples: {
222+
typescript: [
223+
{
224+
description: "Get the authors for a blog",
225+
code: `const { data: authors } = await zenblog.authors.list()`,
226+
},
227+
],
228+
},
155229
response: {
156230
200: {
157231
description: "The authors",
@@ -196,6 +270,16 @@ export const authorBySlug: Endpoint = {
196270
}`,
197271
},
198272
},
273+
examples: {
274+
typescript: [
275+
{
276+
description: "Get an author by their slug",
277+
code: `const { data: author } = await zenblog.authors.get({
278+
slug: "author-slug",
279+
})`,
280+
},
281+
],
282+
},
199283
};
200284

201285
export const endpoints = [

apps/web/app/api/public/[...route]/public-api.types.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
export type CodeExample = {
2+
description: string;
3+
code: string;
4+
};
5+
6+
export type EndpointCodeExamples = {
7+
typescript: CodeExample[];
8+
};
9+
110
export type Endpoint = {
211
id: string;
312
path: string;
@@ -7,7 +16,7 @@ export type Endpoint = {
716
headers?: Header[];
817
query?: Query[];
918
response: Response;
10-
typescriptExample?: string;
19+
examples: EndpointCodeExamples;
1120
};
1221

1322
export type Header = {

apps/web/src/components/CodeBlock.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
11
"use client";
22

3-
import React, { PropsWithChildren } from "react";
3+
import React from "react";
44
import SyntaxHighlighter from "react-syntax-highlighter";
5-
import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
6-
import { Check, CheckCheck, Clipboard } from "lucide-react";
5+
import { stackoverflowDark as codeTheme } from "react-syntax-highlighter/dist/esm/styles/hljs";
6+
import { Check, Clipboard } from "lucide-react";
77
import useClipboard from "react-use-clipboard";
88

99
type Props = {
1010
children: string;
1111
language?: string;
1212
title?: string;
13+
hideHeader?: boolean;
1314
};
1415

1516
export const CodeBlock = ({
1617
children,
1718
language = "typescript",
1819
title,
20+
hideHeader = false,
1921
}: Props) => {
2022
const [isCopied, copy] = useClipboard(children, {
2123
successDuration: 1000,
2224
});
2325

2426
return (
2527
<div className="rounded-lg bg-zinc-900 font-mono text-white">
26-
<div className="flex items-center justify-between pl-2">
27-
<h2 className="text-xs text-zinc-300">{title || language}</h2>
28-
<button onClick={copy} className="p-2 text-zinc-400">
29-
{isCopied ? <Check size="15" /> : <Clipboard size="15" />}
30-
</button>
31-
</div>
28+
{!hideHeader && (
29+
<div className="flex items-center justify-between pl-2">
30+
<h2 className="text-xs text-zinc-300">{title || language}</h2>
31+
<button onClick={copy} className="p-2 text-zinc-400">
32+
{isCopied ? <Check size="15" /> : <Clipboard size="15" />}
33+
</button>
34+
</div>
35+
)}
3236
<SyntaxHighlighter
3337
customStyle={{
3438
padding: "1rem",
@@ -37,7 +41,7 @@ export const CodeBlock = ({
3741
fontSize: "0.82rem",
3842
}}
3943
language={language}
40-
style={atomOneDark}
44+
style={codeTheme}
4145
>
4246
{children}
4347
</SyntaxHighlighter>

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/zenblog/dist/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ export declare function createZenblogClient({ blogId, _url, _debug, }: CreateCli
3939
};
4040
authors: {
4141
list: () => Promise<PaginatedApiResponse<Author[]>>;
42+
get: ({ slug }: {
43+
slug: string;
44+
}, opts?: {
45+
cache?: RequestInit["cache"];
46+
limit?: number;
47+
offset?: number;
48+
}) => Promise<ApiResponse<Author>>;
4249
};
4350
};
4451
export {};

packages/zenblog/dist/index.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)