From 9bfef591fa8c8df1b419fa1d0782f535cf8c251a Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 3 Dec 2024 21:00:47 -0800 Subject: [PATCH] Add "Additional Information" section to GitHub util (#3429) ## Description This PR adds some frontend enhancements to the GitHub util. Specifically, an "additional information" section is added to the username->global node id tool. before/after: image ## Checklist - [x] I have read and understood the [WATcloud Guidelines](https://cloud.watonomous.ca/docs/community-docs/watcloud/guidelines) - [x] I have performed a self-review of my code --- components/blog-post.tsx | 36 +-------- components/github.tsx | 110 ++++++++++++++++++++++++-- components/ui/avatar.tsx | 48 ++++++++++++ components/ui/social-links.tsx | 64 +++++++++++++++ package-lock.json | 138 +++++++++++++++++++++++++++++++++ package.json | 2 + 6 files changed, 360 insertions(+), 38 deletions(-) create mode 100644 components/ui/avatar.tsx create mode 100644 components/ui/social-links.tsx diff --git a/components/blog-post.tsx b/components/blog-post.tsx index 16cb5ef..e61beb5 100644 --- a/components/blog-post.tsx +++ b/components/blog-post.tsx @@ -13,6 +13,7 @@ import { Link, useConfig } from "nextra-theme-docs"; import React, { Fragment } from 'react'; import { SubscribeDialog } from './blog'; import Picture from './picture'; +import { SocialLinks } from './ui/social-links'; // Reference for styling: https://github.com/vercel/turbo/blob/22585c9dcc23eb010ab01f177394358af03210d7/docs/pages/blog/turbo-1-10-0.mdx @@ -49,38 +50,9 @@ export function Avatar({ username }: { username: string }) {
Name
{profile.watcloud_public_profile.full_name}
- {profile.watcloud_public_profile.links && profile.watcloud_public_profile.links.map((link: string) => { - const iconSize = 16; - let icon = ; - let sr = "link"; - if (link.startsWith("mailto:")) { - icon = ; - sr = "email"; - } else if (link.startsWith("https://github.com")) { - icon = ; - sr = "github"; - } else if (link.startsWith("https://linkedin.com")) { - icon = ; - sr = "linkedin"; - } else if (link.startsWith("https://twitter.com") || link.startsWith("https://x.com")) { - icon = ; - sr = "twitter"; - } - return ( - -
{sr}
-
- - {icon} - -
-
- ) - })} + {profile.watcloud_public_profile.links && ( + + )}
); diff --git a/components/github.tsx b/components/github.tsx index 5bac95d..dfc7266 100644 --- a/components/github.tsx +++ b/components/github.tsx @@ -15,16 +15,108 @@ import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Input } from "./ui/input"; import { useMDXComponents } from "nextra-theme-docs"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; +import { Link } from "nextra-theme-docs" +import { SocialLinks } from "./ui/social-links"; const usernameToIDFormSchema = z.object({ username: z.string(), }); +type RawData = { + request: { + url: string; + options: Record; + }; + response: { + headers: Record; + data: any; + }; +}; + +export function GitHubUserCard({ + login, + name, + bio, + avatar_url, + html_url, + public_repos, + followers, + following, + blog, + twitter_username, + email, +}: { + login: string, + name: string, + bio: string, + avatar_url: string, + html_url: string, + public_repos: number, + followers: number, + following: number, + blog?: string, + twitter_username?: string, + email?: string, +}) { + return ( + + + + + {(login || "U")[0]} + + {name} + + + @{login} + + + + + + {bio} + + +
+ +

{public_repos}

+

+ Public Repos +

+ +
+
+ +

{followers}

+

+ Followers +

+ +
+
+ +

{following}

+

+ Following +

+ +
+
+
+ ) +} + export function UsernameToID() { const [isSubmitting, setIsSubmitting] = useState(false); const [warningMessage, setWarningMessage] = useState(""); const [errorMessage, setErrorMessage] = useState(""); - const [rawData, setRawData] = useState(null); + const [rawData, setRawData] = useState(null); const [globalNodeID, setGlobalNodeID] = useState(""); // Use MDX components from the theme: @@ -129,12 +221,18 @@ export function UsernameToID() { )} {rawData && ( -
- Raw data -
-
{JSON.stringify(rawData, null, 2)}
+ <> +
+

Additional Information

+ +
+ Raw data +
+
{JSON.stringify(rawData, null, 2)}
+
+
-
+ )} ); diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx new file mode 100644 index 0000000..991f56e --- /dev/null +++ b/components/ui/avatar.tsx @@ -0,0 +1,48 @@ +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/components/ui/social-links.tsx b/components/ui/social-links.tsx new file mode 100644 index 0000000..9890462 --- /dev/null +++ b/components/ui/social-links.tsx @@ -0,0 +1,64 @@ +import { cn } from "@/lib/utils"; +import { SiX } from "@icons-pack/react-simple-icons"; +import { GithubIcon, GlobeIcon, LinkedinIcon, MailIcon } from "lucide-react"; + +import { Link } from "nextra-theme-docs"; +import { Fragment } from "react"; + +export const DEFAULT_ICON_SIZE = 16; + + +export function SocialLink({ + link, + iconSize = DEFAULT_ICON_SIZE +}: { + link: string, + iconSize?: number, +}) { + let icon = ; + let sr = "link"; + if (link.startsWith("mailto:")) { + icon = ; + sr = "email"; + } else if (link.startsWith("https://github.com")) { + icon = ; + sr = "github"; + } else if (link.startsWith("https://linkedin.com")) { + icon = ; + sr = "linkedin"; + } else if (link.startsWith("https://twitter.com") || link.startsWith("https://x.com")) { + icon = ; + sr = "twitter"; + } + return ( + +
{sr}
+
+ + {icon} + +
+
+ ) +} + +export function SocialLinks({ + links, + className, + iconSize = DEFAULT_ICON_SIZE +}: { + links: string[], + className?: string, + iconSize?: number, +}) { + return ( +
+ {links.filter((link) => link).map((link) => )} +
+ ) +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3e910e3..8776126 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "@giscus/react": "^3.0.0", "@hookform/resolvers": "^3.3.3", + "@icons-pack/react-simple-icons": "^10.2.0", "@radix-ui/react-alert-dialog": "^1.0.5", + "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", @@ -988,6 +990,15 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "node_modules/@icons-pack/react-simple-icons": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@icons-pack/react-simple-icons/-/react-simple-icons-10.2.0.tgz", + "integrity": "sha512-QDUxup8D3GdIIzwGpxQs6bjeFV5mJes25qqf4aqP/PaBYQNCar7AiyD8C14636TosCG0A/QqAUwm/Hviep4d4g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.13 || ^17 || ^18 || ^19" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -2598,6 +2609,133 @@ } } }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.1.tgz", + "integrity": "sha512-eoOtThOmxeoizxpX6RiEsQZ2wj5r4+zoeqAwO0cBaFQGjJwIH3dIX0OCxNrCyrrdxG+vBweMETh3VziQG7c1kw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-checkbox": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz", diff --git a/package.json b/package.json index af39f27..1d48093 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "dependencies": { "@giscus/react": "^3.0.0", "@hookform/resolvers": "^3.3.3", + "@icons-pack/react-simple-icons": "^10.2.0", "@radix-ui/react-alert-dialog": "^1.0.5", + "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6",