From c6f6ac6effab923d223591a1f8d676be272e01b3 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Sat, 5 Oct 2024 19:02:01 +0300 Subject: [PATCH 1/5] fix(www): add missing langs to analytics bento Also, add a copy button to the code editor for one-click code copying, removing the need for manual selection. --- .../components/analytics/analytics-bento.tsx | 337 ++++++++++++++++-- 1 file changed, 308 insertions(+), 29 deletions(-) diff --git a/apps/www/components/analytics/analytics-bento.tsx b/apps/www/components/analytics/analytics-bento.tsx index f0bd5b417d..91d5e9e581 100644 --- a/apps/www/components/analytics/analytics-bento.tsx +++ b/apps/www/components/analytics/analytics-bento.tsx @@ -8,12 +8,24 @@ import { PrimaryButton } from "../button"; import { AnalyticsStars } from "../svg/analytics-stars"; import { WebAppLight } from "../svg/web-app-light"; -export const theme = { +const theme = { plain: { color: "#F8F8F2", backgroundColor: "#282A36", }, styles: [ + { + types: ["keyword"], + style: { + color: "#9D72FF", + }, + }, + { + types: ["function"], + style: { + color: "#FB3186", + }, + }, { types: ["string"], style: { @@ -32,28 +44,15 @@ export const theme = { color: "#FB3186", }, }, + { + types: ["comment"], + style: { + color: "#4D4D4D", + }, + }, ], } satisfies PrismTheme; -const codeBlock = `curl --request GET \\ - --url https://api.unkey.dev/v1/keys.getKey \\ - --header 'Authorization: ' - { - "apiId": "api_1234", - "createdAt": 123, - "deletedAt": 123, - "expires": 123, - "id": "key_1234", - "meta": { - "roles": [ - "admin", - "user" - ], - "stripeCustomerId": "cus_1234" - } - } -`; - export function AnalyticsBento() { const [showApi, toggleShowApi] = useState(false); @@ -76,7 +75,213 @@ export function AnalyticsBento() { ); } +type IconProps = { + active: boolean; +}; + +const RustIcon: React.FC = ({ active }) => ( + + + + + + +); + +const CurlIcon: React.FC = ({ active }) => ( + + + + + + + + + + + + +); + +const PythonIcon: React.FC = ({ active }) => ( + + + + + + + + + +); + +const TSIcon: React.FC = ({ active }) => ( + + + + + + + +); + +const GoIcon: React.FC = ({ active }) => ( + + + +); + +type Language = { + name: string; + Icon: React.FC; + codeBlock: string; +}; + +type LanguageName = "Typescript" | "Python" | "Rust" | "Golang" | "cURL"; + +const curlCodeBlock = `curl --request GET \\ + --url https://api.unkey.dev/v1/keys.getKey?keyId=key_123 \\ + --header 'Authorization: Bearer ' +`; + +const tsCodeBlock = `import { Unkey } from "@unkey/api"; + +const unkey = new Unkey({ rootKey: "" }); + +const { result, error } = await unkey.keys.get({ keyId: "key_123" }); + +if ( error ) { + // handle network error +} + +// handle request +`; + +const pythonCodeBlock = `import asyncio +import os +import unkey + +async def main() -> None: + client = unkey.Client("") + await client.start() + + result = await client.keys.get_key("key_123") + + if result.is_ok: + data = result.unwrap() + print(data.id) + else: + print(result.unwrap_err()) + + await client.close() +`; + +const goCodeBlock = `package main + +import ( + "context" + "log" + + unkeygo "github.com/unkeyed/unkey-go" + "github.com/unkeyed/unkey-go/models/operations" +) + +func main() { + s := unkeygo.New( + unkeygo.WithSecurity(""), + ) + + ctx := context.Background() + res, err := s.Keys.GetKey(ctx, operations.GetKeyRequest{ + KeyID: "key_123", + }) + if err != nil { + log.Fatal(err) + } + if res.Key != nil { + // handle response + } +} + +`; + +const rustCodeBlock = `use unkey::models::GetKeyRequest; +use unkey::Client; + +async fn get_key() { + let c = Client::new(""); + let req = GetKeyRequest::new("key_123"); + + match c.get_key(req).await { + Ok(res) => println!("{res:?}"), + Err(err) => eprintln!("{err:?}"), + } +} +`; + +const languagesList = { + cURL: { Icon: CurlIcon, name: 'cURL', codeBlock: curlCodeBlock, editorLanguage: "tsx" }, + Typescript: { Icon: TSIcon, name: 'Typescript', codeBlock: tsCodeBlock, editorLanguage: "ts" }, + Python: { Icon: PythonIcon, name: 'Python', codeBlock: pythonCodeBlock, editorLanguage: "python" }, + Golang: { Icon: GoIcon, name: 'Golang', codeBlock: goCodeBlock, editorLanguage: "go" }, + Rust: { Icon: RustIcon, name: 'Rust', codeBlock: rustCodeBlock, editorLanguage: "rust" }, +}; + function AnalyticsApiView() { + const [language, setLanguage] = useState("cURL"); + const [copied, setCopied] = useState(false); + return ( -
-
-
- -
cURL
-
-
-
- +
+ +
+ +
); } +function LanguageSwitcher({ + languages, + currentLanguage, + setLanguage, +}: { + languages: Language[]; + currentLanguage: LanguageName; + setLanguage: React.Dispatch>; +}) { + return ( +
+
+ {languages.map(({ Icon, name }) => ( + + ))} +
+
+ ) +} + function AnalyticsWebAppView() { function Tab({ backgroundColor, From c2501db55f4819d37394c460cd4147dfb18c6b92 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Sat, 5 Oct 2024 19:20:43 +0300 Subject: [PATCH 2/5] refactor(www): extract langs SVG icons into separate file Also, rename and move components to components/ui folder. --- apps/www/app/code-examples.tsx | 145 +--------- .../components/analytics/analytics-bento.tsx | 252 +----------------- apps/www/components/svg/lang-icons.tsx | 177 ++++++++++++ apps/www/components/ui/code-editor.tsx | 37 +++ 4 files changed, 225 insertions(+), 386 deletions(-) create mode 100644 apps/www/components/svg/lang-icons.tsx create mode 100644 apps/www/components/ui/code-editor.tsx diff --git a/apps/www/app/code-examples.tsx b/apps/www/app/code-examples.tsx index 83f95e866b..7e5a4e35a4 100644 --- a/apps/www/app/code-examples.tsx +++ b/apps/www/app/code-examples.tsx @@ -1,7 +1,8 @@ "use client"; -import { Editor } from "@/components/analytics/analytics-bento"; import { PrimaryButton, SecondaryButton } from "@/components/button"; import { SectionTitle } from "@/components/section"; +import { CurlIcon, ElixirIcon, GoIcon, JavaIcon, LangIconProps, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; +import { CodeEditor } from "@/components/ui/code-editor"; import { MeteorLines } from "@/components/ui/meteorLines"; import { cn } from "@/lib/utils"; import * as TabsPrimitive from "@radix-ui/react-tabs"; @@ -57,142 +58,6 @@ const editorTheme = { ], } satisfies PrismTheme; -type IconProps = { - active: boolean; -}; - -const JavaIcon: React.FC = ({ active }) => ( - - - - - - -); - -const ElixirIcon: React.FC = ({ active }) => ( - - - -); - -const RustIcon: React.FC = ({ active }) => ( - - - - - - -); - -const CurlIcon: React.FC = ({ active }) => ( - - - - - - - - - - - - -); - -const PythonIcon: React.FC = ({ active }) => ( - - - - - - - - - -); - -const TSIcon: React.FC = ({ active }) => ( - - - - - - - -); - -const GoIcon: React.FC = ({ active }) => ( - - - -); - const typescriptCodeBlock = `import { verifyKey } from '@unkey/api'; const { result, error } = await verifyKey({ @@ -472,7 +337,7 @@ public class APIController { type Framework = { name: string; - Icon: React.FC; + Icon: React.FC; codeBlock: string; editorLanguage: string; }; @@ -613,7 +478,7 @@ type Props = { type Language = "Typescript" | "Python" | "Rust" | "Golang" | "Curl" | "Elixir" | "Java"; type LanguagesList = { name: Language; - Icon: React.FC; + Icon: React.FC; }; const languages = [ { name: "Typescript", Icon: TSIcon }, @@ -727,7 +592,7 @@ export const CodeExamples: React.FC = ({ className }) => { setFramework={setFramework} />
- = ({ active }) => ( - - - - - - -); - -const CurlIcon: React.FC = ({ active }) => ( - - - - - - - - - - - - -); - -const PythonIcon: React.FC = ({ active }) => ( - - - - - - - - - -); - -const TSIcon: React.FC = ({ active }) => ( - - - - - - - -); - -const GoIcon: React.FC = ({ active }) => ( - - - -); - type Language = { name: string; - Icon: React.FC; + Icon: React.FC; codeBlock: string; }; @@ -253,7 +148,6 @@ func main() { // handle response } } - `; const rustCodeBlock = `use unkey::models::GetKeyRequest; @@ -294,7 +188,7 @@ function AnalyticsApiView() {
- + +
diff --git a/apps/www/components/analytics/analytics-bento.tsx b/apps/www/components/analytics/analytics-bento.tsx index a9a914b74a..6688f137af 100644 --- a/apps/www/components/analytics/analytics-bento.tsx +++ b/apps/www/components/analytics/analytics-bento.tsx @@ -9,6 +9,7 @@ import { AnalyticsStars } from "../svg/analytics-stars"; import { WebAppLight } from "../svg/web-app-light"; import { CurlIcon, GoIcon, LangIconProps, PythonIcon, RustIcon, TSIcon } from "../svg/lang-icons"; import { CodeEditor } from "../ui/code-editor"; +import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button"; const theme = { plain: { @@ -174,7 +175,6 @@ const languagesList = { function AnalyticsApiView() { const [language, setLanguage] = useState("cURL"); - const [copied, setCopied] = useState(false); return (
- - + +
diff --git a/apps/www/components/ui/copy-code-button.tsx b/apps/www/components/ui/copy-code-button.tsx new file mode 100644 index 0000000000..586e9aa4ed --- /dev/null +++ b/apps/www/components/ui/copy-code-button.tsx @@ -0,0 +1,84 @@ +import { useState } from "react"; + +type Props = { + textToCopy: string; + className?: string; +}; + +export function CopyCodeSnippetButton(props: Props) { + const [copied, setCopied] = useState(false); + + return ( + + ); +} + +function CheckmarkCircle() { + return ( + + + + + ); +} + +function CopyIcon() { + return ( + + + + + + + + + + ); +} From 682ec92e4c05f873ef38689d78357ebed6a032be Mon Sep 17 00:00:00 2001 From: unrenamed Date: Sat, 5 Oct 2024 20:50:01 +0300 Subject: [PATCH 4/5] refactor(www): apply coderabbitai review comments --- apps/www/app/code-examples.tsx | 19 ++++++++++--------- .../components/analytics/analytics-bento.tsx | 9 +++++---- apps/www/components/ui/code-editor.tsx | 4 ++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/www/app/code-examples.tsx b/apps/www/app/code-examples.tsx index 16188d3df0..243097fc55 100644 --- a/apps/www/app/code-examples.tsx +++ b/apps/www/app/code-examples.tsx @@ -1,7 +1,8 @@ "use client";; import { PrimaryButton, SecondaryButton } from "@/components/button"; import { SectionTitle } from "@/components/section"; -import { CurlIcon, ElixirIcon, GoIcon, JavaIcon, LangIconProps, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; +import type { LangIconProps } from "@/components/svg/lang-icons"; +import { CurlIcon, ElixirIcon, GoIcon, JavaIcon, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; import { CodeEditor } from "@/components/ui/code-editor"; import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button"; import { MeteorLines } from "@/components/ui/meteorLines"; @@ -380,31 +381,31 @@ const languagesList = { name: "Typescript", Icon: TSIcon, codeBlock: typescriptCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, { name: "Next.js", Icon: TSIcon, codeBlock: nextJsCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, { name: "Nuxt", codeBlock: nuxtCodeBlock, Icon: TSIcon, - editorLanguage: "ts", + editorLanguage: "tsx", }, { name: "Hono", Icon: TSIcon, codeBlock: honoCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, { name: "Ratelimiting", Icon: TSIcon, codeBlock: tsRatelimitCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, ], Python: [ @@ -440,13 +441,13 @@ const languagesList = { name: "Verify key", Icon: JavaIcon, codeBlock: javaVerifyKeyCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, { name: "Create key", Icon: JavaIcon, codeBlock: javaCreateKeyCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, ], Elixir: [ @@ -454,7 +455,7 @@ const languagesList = { name: "Verify key", Icon: ElixirIcon, codeBlock: elixirCodeBlock, - editorLanguage: "ts", + editorLanguage: "tsx", }, ], Rust: [ diff --git a/apps/www/components/analytics/analytics-bento.tsx b/apps/www/components/analytics/analytics-bento.tsx index 6688f137af..73dd74f7db 100644 --- a/apps/www/components/analytics/analytics-bento.tsx +++ b/apps/www/components/analytics/analytics-bento.tsx @@ -7,7 +7,8 @@ import { useState } from "react"; import { PrimaryButton } from "../button"; import { AnalyticsStars } from "../svg/analytics-stars"; import { WebAppLight } from "../svg/web-app-light"; -import { CurlIcon, GoIcon, LangIconProps, PythonIcon, RustIcon, TSIcon } from "../svg/lang-icons"; +import type { LangIconProps } from "@/components/svg/lang-icons"; +import { CurlIcon, GoIcon, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; import { CodeEditor } from "../ui/code-editor"; import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button"; @@ -84,7 +85,7 @@ type Language = { codeBlock: string; }; -type LanguageName = "Typescript" | "Python" | "Rust" | "Golang" | "cURL"; +type LanguageName = "TypeScript" | "Python" | "Rust" | "Go" | "cURL"; const curlCodeBlock = `curl --request GET \\ --url https://api.unkey.dev/v1/keys.getKey?keyId=key_123 \\ @@ -167,9 +168,9 @@ async fn get_key() { const languagesList = { cURL: { Icon: CurlIcon, name: 'cURL', codeBlock: curlCodeBlock, editorLanguage: "tsx" }, - Typescript: { Icon: TSIcon, name: 'Typescript', codeBlock: tsCodeBlock, editorLanguage: "ts" }, + TypeScript: { Icon: TSIcon, name: 'TypeScript', codeBlock: tsCodeBlock, editorLanguage: "tsx" }, Python: { Icon: PythonIcon, name: 'Python', codeBlock: pythonCodeBlock, editorLanguage: "python" }, - Golang: { Icon: GoIcon, name: 'Golang', codeBlock: goCodeBlock, editorLanguage: "go" }, + Go: { Icon: GoIcon, name: 'Go', codeBlock: goCodeBlock, editorLanguage: "go" }, Rust: { Icon: RustIcon, name: 'Rust', codeBlock: rustCodeBlock, editorLanguage: "rust" }, }; diff --git a/apps/www/components/ui/code-editor.tsx b/apps/www/components/ui/code-editor.tsx index e55f78f1bf..a880ac0ef5 100644 --- a/apps/www/components/ui/code-editor.tsx +++ b/apps/www/components/ui/code-editor.tsx @@ -8,8 +8,8 @@ export function CodeEditor({ return ( {({ tokens, getLineProps, getTokenProps }) => { - const amountLines = tokens.length; - const gutterPadLength = Math.max(String(amountLines).length, 2); + const lineCount = tokens.length; + const gutterPadLength = Math.max(String(lineCount).length, 2); return (
Date: Sat, 5 Oct 2024 19:03:52 +0000
Subject: [PATCH 5/5] [autofix.ci] apply automated fixes

---
 apps/www/app/code-examples.tsx                | 17 +++--
 .../components/analytics/analytics-bento.tsx  | 63 ++++++++++-------
 apps/www/components/svg/lang-icons.tsx        | 56 ++--------------
 apps/www/components/ui/code-editor.tsx        | 67 +++++++++----------
 apps/www/components/ui/copy-code-button.tsx   | 20 +-----
 5 files changed, 95 insertions(+), 128 deletions(-)

diff --git a/apps/www/app/code-examples.tsx b/apps/www/app/code-examples.tsx
index 243097fc55..ac5127708c 100644
--- a/apps/www/app/code-examples.tsx
+++ b/apps/www/app/code-examples.tsx
@@ -1,8 +1,16 @@
-"use client";;
+"use client";
 import { PrimaryButton, SecondaryButton } from "@/components/button";
 import { SectionTitle } from "@/components/section";
 import type { LangIconProps } from "@/components/svg/lang-icons";
-import { CurlIcon, ElixirIcon, GoIcon, JavaIcon, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons";
+import {
+  CurlIcon,
+  ElixirIcon,
+  GoIcon,
+  JavaIcon,
+  PythonIcon,
+  RustIcon,
+  TSIcon,
+} from "@/components/svg/lang-icons";
 import { CodeEditor } from "@/components/ui/code-editor";
 import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button";
 import { MeteorLines } from "@/components/ui/meteorLines";
@@ -630,8 +638,9 @@ export const CodeExamples: React.FC = ({ className }) => {
               codeBlock={getCodeBlock({ language, framework })}
             />
             
+              textToCopy={getCodeBlock({ language, framework })}
+              className="absolute hidden cursor-pointer top-5 right-5 lg:flex"
+            />
           
diff --git a/apps/www/components/analytics/analytics-bento.tsx b/apps/www/components/analytics/analytics-bento.tsx index 73dd74f7db..65d9444c2d 100644 --- a/apps/www/components/analytics/analytics-bento.tsx +++ b/apps/www/components/analytics/analytics-bento.tsx @@ -1,16 +1,16 @@ "use client"; +import type { LangIconProps } from "@/components/svg/lang-icons"; +import { CurlIcon, GoIcon, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; +import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button"; import { cn } from "@/lib/utils"; import { motion } from "framer-motion"; import { Wand2 } from "lucide-react"; -import { type PrismTheme } from "prism-react-renderer"; +import type { PrismTheme } from "prism-react-renderer"; import { useState } from "react"; import { PrimaryButton } from "../button"; import { AnalyticsStars } from "../svg/analytics-stars"; import { WebAppLight } from "../svg/web-app-light"; -import type { LangIconProps } from "@/components/svg/lang-icons"; -import { CurlIcon, GoIcon, PythonIcon, RustIcon, TSIcon } from "@/components/svg/lang-icons"; import { CodeEditor } from "../ui/code-editor"; -import { CopyCodeSnippetButton } from "@/components/ui/copy-code-button"; const theme = { plain: { @@ -167,16 +167,21 @@ async fn get_key() { `; const languagesList = { - cURL: { Icon: CurlIcon, name: 'cURL', codeBlock: curlCodeBlock, editorLanguage: "tsx" }, - TypeScript: { Icon: TSIcon, name: 'TypeScript', codeBlock: tsCodeBlock, editorLanguage: "tsx" }, - Python: { Icon: PythonIcon, name: 'Python', codeBlock: pythonCodeBlock, editorLanguage: "python" }, - Go: { Icon: GoIcon, name: 'Go', codeBlock: goCodeBlock, editorLanguage: "go" }, - Rust: { Icon: RustIcon, name: 'Rust', codeBlock: rustCodeBlock, editorLanguage: "rust" }, + cURL: { Icon: CurlIcon, name: "cURL", codeBlock: curlCodeBlock, editorLanguage: "tsx" }, + TypeScript: { Icon: TSIcon, name: "TypeScript", codeBlock: tsCodeBlock, editorLanguage: "tsx" }, + Python: { + Icon: PythonIcon, + name: "Python", + codeBlock: pythonCodeBlock, + editorLanguage: "python", + }, + Go: { Icon: GoIcon, name: "Go", codeBlock: goCodeBlock, editorLanguage: "go" }, + Rust: { Icon: RustIcon, name: "Rust", codeBlock: rustCodeBlock, editorLanguage: "rust" }, }; function AnalyticsApiView() { const [language, setLanguage] = useState("cURL"); - + return (
- +
- - + +
@@ -219,17 +230,21 @@ function LanguageSwitcher({ key={name} type="button" onClick={() => setLanguage(name as LanguageName)} - className={cn("flex items-center cursor-pointer bg-white/5 py-1 px-2 rounded-lg w-[184px]", { - "bg-white/10 text-white": currentLanguage === name, - "text-white/40": currentLanguage !== name, - })}> + className={cn( + "flex items-center cursor-pointer bg-white/5 py-1 px-2 rounded-lg w-[184px]", + { + "bg-white/10 text-white": currentLanguage === name, + "text-white/40": currentLanguage !== name, + }, + )} + >
{name}
))} + - - ) + ); } function AnalyticsWebAppView() { diff --git a/apps/www/components/svg/lang-icons.tsx b/apps/www/components/svg/lang-icons.tsx index c62345b2f5..88c362df6f 100644 --- a/apps/www/components/svg/lang-icons.tsx +++ b/apps/www/components/svg/lang-icons.tsx @@ -3,13 +3,7 @@ export type LangIconProps = { }; export const JavaIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const ElixirIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const RustIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const CurlIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const PythonIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const TSIcon: React.FC = ({ active }) => ( - + = ({ active }) => ( ); export const GoIcon: React.FC = ({ active }) => ( - + - {({ tokens, getLineProps, getTokenProps }) => { - const lineCount = tokens.length; - const gutterPadLength = Math.max(String(lineCount).length, 2); - return ( -
-              {tokens.map((line, i) => {
-                const lineNumber = i + 1;
-                const paddedLineGutter = String(lineNumber).padStart(gutterPadLength, " ");
-                return (
-                  // biome-ignore lint/suspicious/noArrayIndexKey: I got nothing better right now
-                  
- {paddedLineGutter} - {line.map((token, key) => ( - - ))} -
- ); - })} -
- ); - }} - - ); - } - \ No newline at end of file + codeBlock, + language, + theme, +}: { codeBlock: string; language: string; theme?: PrismTheme }) { + return ( + + {({ tokens, getLineProps, getTokenProps }) => { + const lineCount = tokens.length; + const gutterPadLength = Math.max(String(lineCount).length, 2); + return ( +
+            {tokens.map((line, i) => {
+              const lineNumber = i + 1;
+              const paddedLineGutter = String(lineNumber).padStart(gutterPadLength, " ");
+              return (
+                // biome-ignore lint/suspicious/noArrayIndexKey: I got nothing better right now
+                
+ {paddedLineGutter} + {line.map((token, key) => ( + + ))} +
+ ); + })} +
+ ); + }} +
+ ); +} diff --git a/apps/www/components/ui/copy-code-button.tsx b/apps/www/components/ui/copy-code-button.tsx index 586e9aa4ed..f2eb008dbd 100644 --- a/apps/www/components/ui/copy-code-button.tsx +++ b/apps/www/components/ui/copy-code-button.tsx @@ -28,23 +28,9 @@ export function CopyCodeSnippetButton(props: Props) { function CheckmarkCircle() { return ( - - - + + + ); }