diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 65e0c17d2e..78a5eb0362 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -5,6 +5,7 @@ env: ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }} ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }} ALGOLIA_SEARCH_INDEX: ${{ secrets. ALGOLIA_SEARCH_INDEX }} + FONTAWESOME_CDN_HOST: https://fontawesome-cdn.vercel.app on: push: branches: diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 5618479c8c..a04c0eece7 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -5,6 +5,7 @@ env: ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }} ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }} ALGOLIA_SEARCH_INDEX: ${{ secrets. ALGOLIA_SEARCH_INDEX }} + FONTAWESOME_CDN_HOST: https://fontawesome-cdn.vercel.app on: push: branches-ignore: diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 96653d5e68..5a711b65b1 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -6,6 +6,7 @@ env: ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }} ALGOLIA_SEARCH_INDEX: ${{ secrets. ALGOLIA_SEARCH_INDEX }} POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + FONTAWESOME_CDN_HOST: https://fontawesome-cdn.vercel.app on: push: tags: diff --git a/.pnp.cjs b/.pnp.cjs index b631382008..e5ef126934 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -67,6 +67,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "name": "@fern-ui/ui",\ "reference": "workspace:packages/ui/app"\ },\ + {\ + "name": "@fern-ui/fontawesome-cdn",\ + "reference": "workspace:packages/ui/fontawesome-cdn"\ + },\ {\ "name": "@fern-ui/local-preview-bundle",\ "reference": "workspace:packages/ui/local-preview-bundle"\ @@ -88,6 +92,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-ui/common-components", ["workspace:packages/commons/react/common-components"]],\ ["@fern-ui/compile-root", ["workspace:packages/_root"]],\ ["@fern-ui/core-utils", ["workspace:packages/commons/core-utils"]],\ + ["@fern-ui/fontawesome-cdn", ["workspace:packages/ui/fontawesome-cdn"]],\ ["@fern-ui/fonts", ["workspace:packages/commons/react/fonts"]],\ ["@fern-ui/loadable", ["workspace:packages/commons/loadable"]],\ ["@fern-ui/local-preview-bundle", ["workspace:packages/ui/local-preview-bundle"]],\ @@ -4382,6 +4387,36 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "SOFT"\ }]\ ]],\ + ["@fern-ui/fontawesome-cdn", [\ + ["workspace:packages/ui/fontawesome-cdn", {\ + "packageLocation": "./packages/ui/fontawesome-cdn/",\ + "packageDependencies": [\ + ["@fern-ui/fontawesome-cdn", "workspace:packages/ui/fontawesome-cdn"],\ + ["@fortawesome/fontawesome-svg-core", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffontawesome-svg-core%2F-%2F6.5.1%2Ffontawesome-svg-core-6.5.1.tgz"],\ + ["@fortawesome/free-brands-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffree-brands-svg-icons%2F-%2F6.5.1%2Ffree-brands-svg-icons-6.5.1.tgz"],\ + ["@fortawesome/free-solid-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffree-solid-svg-icons%2F-%2F6.5.1%2Ffree-solid-svg-icons-6.5.1.tgz"],\ + ["@fortawesome/pro-duotone-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-duotone-svg-icons%2F-%2F6.5.1%2Fpro-duotone-svg-icons-6.5.1.tgz"],\ + ["@fortawesome/pro-light-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-light-svg-icons%2F-%2F6.5.1%2Fpro-light-svg-icons-6.5.1.tgz"],\ + ["@fortawesome/pro-regular-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-regular-svg-icons%2F-%2F6.5.1%2Fpro-regular-svg-icons-6.5.1.tgz"],\ + ["@fortawesome/pro-solid-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-solid-svg-icons%2F-%2F6.5.1%2Fpro-solid-svg-icons-6.5.1.tgz"],\ + ["@next/bundle-analyzer", "npm:14.0.3"],\ + ["@types/jest", "npm:29.5.11"],\ + ["@types/node", "npm:18.18.13"],\ + ["@types/react", "npm:18.0.20"],\ + ["depcheck", "npm:1.4.3"],\ + ["eslint", "npm:8.56.0"],\ + ["jest", "virtual:81cc2531fc6bda045c87d6c3b21351574209a7d87ba11b639412d754d2fbdd0831d00d35ee7d39be3226e871d899842f300a82fbfbdd17e263ce302a51c65de6#npm:29.7.0"],\ + ["next", "virtual:cf6fbd07d81e6c070e1d18b6ec0fb7336cfec041fcde20c98947f8564f9b6fb68d67e538b00e8fa6087067487182a29316882652bf651e41897aa30e5a9283e1#npm:14.0.4"],\ + ["organize-imports-cli", "npm:0.10.0"],\ + ["prettier", "npm:3.2.4"],\ + ["react", "npm:18.2.0"],\ + ["react-dom", "virtual:365c5e55d4374302d83e985bf13cdc0e1b9981623dceff55d2afbcfc02ee37332be44cf95e9c81193f89ad56d1cfe060a8b59dd16c83a03bcf51abe82d13ecf2#npm:18.2.0"],\ + ["stylelint", "npm:16.1.0"],\ + ["typescript", "patch:typescript@npm%3A4.9.4#~builtin::version=4.9.4&hash=289587"]\ + ],\ + "linkType": "SOFT"\ + }]\ + ]],\ ["@fern-ui/fonts", [\ ["workspace:packages/commons/react/fonts", {\ "packageLocation": "./packages/commons/react/fonts/",\ @@ -4654,14 +4689,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-ui/loadable", "workspace:packages/commons/loadable"],\ ["@fern-ui/react-commons", "workspace:packages/commons/react/react-commons"],\ ["@fontsource/ibm-plex-mono", "npm:4.5.13"],\ - ["@fortawesome/fontawesome-svg-core", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffontawesome-svg-core%2F-%2F6.5.1%2Ffontawesome-svg-core-6.5.1.tgz"],\ - ["@fortawesome/free-brands-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffree-brands-svg-icons%2F-%2F6.5.1%2Ffree-brands-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/free-solid-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffree-solid-svg-icons%2F-%2F6.5.1%2Ffree-solid-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/pro-duotone-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-duotone-svg-icons%2F-%2F6.5.1%2Fpro-duotone-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/pro-light-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-light-svg-icons%2F-%2F6.5.1%2Fpro-light-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/pro-regular-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-regular-svg-icons%2F-%2F6.5.1%2Fpro-regular-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/pro-solid-svg-icons", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Fpro-solid-svg-icons%2F-%2F6.5.1%2Fpro-solid-svg-icons-6.5.1.tgz"],\ - ["@fortawesome/react-fontawesome", "virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:0.2.0"],\ ["@headlessui/react", "virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:1.7.18"],\ ["@react-hook/size", "virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:2.1.2"],\ ["@testing-library/react", "virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:14.0.0"],\ @@ -4798,33 +4825,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@fortawesome/react-fontawesome", [\ - ["npm:0.2.0", {\ - "packageLocation": "./.yarn/cache/@fortawesome-react-fontawesome-npm-0.2.0-a36215138f-f652a0c217.zip/node_modules/@fortawesome/react-fontawesome/",\ - "packageDependencies": [\ - ["@fortawesome/react-fontawesome", "npm:0.2.0"]\ - ],\ - "linkType": "SOFT"\ - }],\ - ["virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:0.2.0", {\ - "packageLocation": "./.yarn/__virtual__/@fortawesome-react-fontawesome-virtual-4761f86e1d/0/cache/@fortawesome-react-fontawesome-npm-0.2.0-a36215138f-f652a0c217.zip/node_modules/@fortawesome/react-fontawesome/",\ - "packageDependencies": [\ - ["@fortawesome/react-fontawesome", "virtual:78e90867e46510db2994cf6ed805ab4ba701c55b6d7a2c33f6cc04865dc082c172bef019989477dda8bc6824512d13cb3bcb74ef12bd113a2f6bdcd291ad70f1#npm:0.2.0"],\ - ["@fortawesome/fontawesome-svg-core", "npm:6.5.1::__archiveUrl=https%3A%2F%2Fnpm.fontawesome.com%2F%40fortawesome%2Ffontawesome-svg-core%2F-%2F6.5.1%2Ffontawesome-svg-core-6.5.1.tgz"],\ - ["@types/fortawesome__fontawesome-svg-core", null],\ - ["@types/react", "npm:18.0.20"],\ - ["prop-types", "npm:15.8.1"],\ - ["react", "npm:18.2.0"]\ - ],\ - "packagePeers": [\ - "@fortawesome/fontawesome-svg-core",\ - "@types/fortawesome__fontawesome-svg-core",\ - "@types/react",\ - "react"\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@gar/promisify", [\ ["npm:1.1.3", {\ "packageLocation": "./.yarn/cache/@gar-promisify-npm-1.1.3-ac1a325862-4059f790e2.zip/node_modules/@gar/promisify/",\ @@ -15766,6 +15766,48 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "sass"\ ],\ "linkType": "HARD"\ + }],\ + ["virtual:cf6fbd07d81e6c070e1d18b6ec0fb7336cfec041fcde20c98947f8564f9b6fb68d67e538b00e8fa6087067487182a29316882652bf651e41897aa30e5a9283e1#npm:14.0.4", {\ + "packageLocation": "./.yarn/__virtual__/next-virtual-050a8862cf/0/cache/next-npm-14.0.4-93c7e4ca0b-879842979d.zip/node_modules/next/",\ + "packageDependencies": [\ + ["next", "virtual:cf6fbd07d81e6c070e1d18b6ec0fb7336cfec041fcde20c98947f8564f9b6fb68d67e538b00e8fa6087067487182a29316882652bf651e41897aa30e5a9283e1#npm:14.0.4"],\ + ["@next/env", "npm:14.0.4"],\ + ["@next/swc-darwin-arm64", "npm:14.0.4"],\ + ["@next/swc-darwin-x64", "npm:14.0.4"],\ + ["@next/swc-linux-arm64-gnu", "npm:14.0.4"],\ + ["@next/swc-linux-arm64-musl", "npm:14.0.4"],\ + ["@next/swc-linux-x64-gnu", "npm:14.0.4"],\ + ["@next/swc-linux-x64-musl", "npm:14.0.4"],\ + ["@next/swc-win32-arm64-msvc", "npm:14.0.4"],\ + ["@next/swc-win32-ia32-msvc", "npm:14.0.4"],\ + ["@next/swc-win32-x64-msvc", "npm:14.0.4"],\ + ["@opentelemetry/api", null],\ + ["@swc/helpers", "npm:0.5.2"],\ + ["@types/opentelemetry__api", null],\ + ["@types/react", "npm:18.0.20"],\ + ["@types/react-dom", null],\ + ["@types/sass", null],\ + ["busboy", "npm:1.6.0"],\ + ["caniuse-lite", "npm:1.0.30001576"],\ + ["graceful-fs", "npm:4.2.11"],\ + ["postcss", "npm:8.4.31"],\ + ["react", "npm:18.2.0"],\ + ["react-dom", "virtual:365c5e55d4374302d83e985bf13cdc0e1b9981623dceff55d2afbcfc02ee37332be44cf95e9c81193f89ad56d1cfe060a8b59dd16c83a03bcf51abe82d13ecf2#npm:18.2.0"],\ + ["sass", null],\ + ["styled-jsx", "virtual:1fb4793cda658baa2784e33af35bd4eb8b51de4759933685f057e3640bfdc682d7fa82fa1edb5a01c899681a1d18776cc50dfb9cadcf037888f9270bc612a8bf#npm:5.1.1"],\ + ["watchpack", "npm:2.4.0"]\ + ],\ + "packagePeers": [\ + "@opentelemetry/api",\ + "@types/opentelemetry__api",\ + "@types/react-dom",\ + "@types/react",\ + "@types/sass",\ + "react-dom",\ + "react",\ + "sass"\ + ],\ + "linkType": "HARD"\ }]\ ]],\ ["next-mdx-remote", [\ diff --git a/.yarn/cache/@fortawesome-react-fontawesome-npm-0.2.0-a36215138f-f652a0c217.zip b/.yarn/cache/@fortawesome-react-fontawesome-npm-0.2.0-a36215138f-f652a0c217.zip deleted file mode 100644 index 068f66c7f3..0000000000 Binary files a/.yarn/cache/@fortawesome-react-fontawesome-npm-0.2.0-a36215138f-f652a0c217.zip and /dev/null differ diff --git a/packages/ui/app/package.json b/packages/ui/app/package.json index e7c6e111a9..83bb0540aa 100644 --- a/packages/ui/app/package.json +++ b/packages/ui/app/package.json @@ -40,14 +40,6 @@ "@fern-ui/loadable": "workspace:*", "@fern-ui/react-commons": "workspace:*", "@fontsource/ibm-plex-mono": "^4.5.13", - "@fortawesome/fontawesome-svg-core": "^6.5.1", - "@fortawesome/free-brands-svg-icons": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.5.1", - "@fortawesome/pro-duotone-svg-icons": "^6.5.1", - "@fortawesome/pro-light-svg-icons": "^6.5.1", - "@fortawesome/pro-regular-svg-icons": "^6.5.1", - "@fortawesome/pro-solid-svg-icons": "^6.5.1", - "@fortawesome/react-fontawesome": "0.2.0", "@headlessui/react": "^1.7.18", "@react-hook/size": "^2.1.2", "@vercel/speed-insights": "^1.0.7", diff --git a/packages/ui/app/src/api-page/endpoints/CodeExampleClientDropdown.tsx b/packages/ui/app/src/api-page/endpoints/CodeExampleClientDropdown.tsx index 6801b3cabe..ab930fbbd1 100644 --- a/packages/ui/app/src/api-page/endpoints/CodeExampleClientDropdown.tsx +++ b/packages/ui/app/src/api-page/endpoints/CodeExampleClientDropdown.tsx @@ -1,4 +1,5 @@ -import { FontAwesomeIcon } from "../../commons/FontAwesomeIcon"; +import classNames from "classnames"; +import { RemoteFontAwesomeIcon } from "../../commons/FontAwesomeIcon"; import { FernMenu, FernMenuItem } from "../../components/FernMenu"; import type { CodeExampleClient, CodeExampleClientId } from "../examples//code-example"; @@ -31,21 +32,40 @@ export const CodeExampleClientDropdown: React.FC } + icon={ + + } align="right" > - {clients.map(({ id: clientId, name: clientName }) => ( - onClickClient(clientId)} - > - -
- {clientName} -
-
- ))} + {clients.map(({ id: clientId, name: clientName }) => { + const selected = clientId === selectedClient.id; + return ( + onClickClient(clientId)} + > + {(active) => ( + <> + +
+ {clientName} +
+ + )} +
+ ); + })}
); diff --git a/packages/ui/app/src/api-playground/ApiPlaygroundContent.tsx b/packages/ui/app/src/api-playground/ApiPlaygroundContent.tsx index d0b17b7bca..8629e3ad7c 100644 --- a/packages/ui/app/src/api-playground/ApiPlaygroundContent.tsx +++ b/packages/ui/app/src/api-playground/ApiPlaygroundContent.tsx @@ -2,13 +2,13 @@ import { NonIdealState, Spinner } from "@blueprintjs/core"; import { APIV1Read, joinUrlSlugs } from "@fern-api/fdr-sdk"; import { ResolvedEndpointDefinition } from "@fern-ui/app-utils"; import { failed, Loadable, loaded, loading, notStartedLoading, visitLoadable } from "@fern-ui/loadable"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import classNames from "classnames"; import { useAtom } from "jotai"; import { atomWithStorage } from "jotai/utils"; import { isEmpty, round } from "lodash-es"; import { Dispatch, FC, SetStateAction, useCallback, useState } from "react"; import { capturePosthogEvent } from "../analytics/posthog"; +import { RemoteFontAwesomeIcon } from "../commons/FontAwesomeIcon"; import { PlaygroundEndpointForm } from "./PlaygroundEndpointForm"; import { PlaygroundRequestPreview } from "./PlaygroundRequestPreview"; import { PlaygroundResponsePreview } from "./PlaygroundResponsePreview"; @@ -219,14 +219,14 @@ export const ApiPlayroundContent: FC = ({ {response.type !== "notStartedLoading" && endpoint != null && (
@@ -278,14 +278,14 @@ export const ApiPlayroundContent: FC = ({ icon={ response.type === "notStartedLoading" ? ( diff --git a/packages/ui/app/src/commons/FontAwesomeIcon.tsx b/packages/ui/app/src/commons/FontAwesomeIcon.tsx index 7aaaf43d22..08d2171836 100644 --- a/packages/ui/app/src/commons/FontAwesomeIcon.tsx +++ b/packages/ui/app/src/commons/FontAwesomeIcon.tsx @@ -1,13 +1,52 @@ -import { IconProp } from "@fortawesome/fontawesome-svg-core"; -import { FontAwesomeIcon as _FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -export declare namespace FontAwesomeIcon { +export declare namespace RemoteFontAwesomeIcon { export interface Props { - className?: string; + className?: string; // you must specify the bg-color rather than text-color because this is a mask. icon?: string; } } - -export const FontAwesomeIcon: React.FC = ({ className, icon }) => { - return <_FontAwesomeIcon className={className} icon={icon as IconProp} />; +export const RemoteFontAwesomeIcon: React.FC = ({ className, icon }) => { + return ( + + ); }; + +function getIconUrl(icon: string | undefined): string { + const parsed = parseFontAwesomeIcon(icon); + if (!parsed) { + return ""; + } + const [style, iconName] = parsed; + return `${getCdnHost()}/${style}/${iconName}.svg`; +} + +function getCdnHost() { + const CDN_HOST = process.env.NEXT_PUBLIC_FONTAWESOME_CDN_HOST; + if (CDN_HOST == null) { + throw new Error("NEXT_PUBLIC_FONTAWESOME_CDN_HOST is not set"); + } + return CDN_HOST; +} + +function parseFontAwesomeIcon(icon: string | undefined): [string, string] | undefined { + if (!icon) { + return; + } + const [left, right] = icon.split(" "); + if (left && right) { + return [left.replace("fa-", ""), right.replace("fa-", "")]; + } + if (left) { + return ["solid", left.replace("fa-", "")]; + } + return; +} diff --git a/packages/ui/app/src/components/FernMenu.tsx b/packages/ui/app/src/components/FernMenu.tsx index 83af73ba0e..8eafe9cc6e 100644 --- a/packages/ui/app/src/components/FernMenu.tsx +++ b/packages/ui/app/src/components/FernMenu.tsx @@ -1,8 +1,8 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Menu as HeadlessMenu, Transition } from "@headlessui/react"; import classNames from "classnames"; import Link, { LinkProps } from "next/link"; import { FC, Fragment, PropsWithChildren, ReactNode } from "react"; +import { RemoteFontAwesomeIcon } from "../commons/FontAwesomeIcon"; import { CheckIcon } from "../commons/icons/CheckIcon"; import { ChevronDownIcon } from "../commons/icons/ChevronDownIcon"; @@ -59,7 +59,7 @@ export const FernMenu: FC = ({ className="hover:bg-tag-primary border-border-primary dark:border-border-primary-dark text-accent-primary dark:text-accent-primary-dark -ml-px inline-flex w-fit items-center justify-center rounded-lg rounded-l-none border px-2 py-1 tracking-tight transition hover:border-2 hover:px-[calc(theme(spacing[2])-1px)]" onClick={clearSelection} > - + )}
diff --git a/packages/ui/app/src/mdx/components/Card.tsx b/packages/ui/app/src/mdx/components/Card.tsx index b4f334f44e..9c241c27e0 100644 --- a/packages/ui/app/src/mdx/components/Card.tsx +++ b/packages/ui/app/src/mdx/components/Card.tsx @@ -1,6 +1,6 @@ import classNames from "classnames"; import Link from "next/link"; -import { FontAwesomeIcon } from "../../commons/FontAwesomeIcon"; +import { RemoteFontAwesomeIcon } from "../../commons/FontAwesomeIcon"; export declare namespace Card { export interface Props { @@ -30,7 +30,7 @@ export const Card: React.FC = ({ title, icon, iconPosition = "top", const content = ( <> - +
{title}
{children != null &&
{children}
} diff --git a/packages/ui/app/src/next-app/NextApp.tsx b/packages/ui/app/src/next-app/NextApp.tsx index 0af05c7236..62c07a6b2b 100644 --- a/packages/ui/app/src/next-app/NextApp.tsx +++ b/packages/ui/app/src/next-app/NextApp.tsx @@ -1,16 +1,12 @@ -import "@fortawesome/fontawesome-svg-core/styles.css"; import { SpeedInsights } from "@vercel/speed-insights/next"; import type { AppProps } from "next/app"; import PageLoader from "next/dist/client/page-loader"; import { Router } from "next/router"; import { ReactElement, useEffect } from "react"; import { ThemeProvider } from "../docs/ThemeProvider"; -import { setupFontAwesomeIcons } from "../util/setupFontAwesomeIcons"; import { DocsPage } from "./DocsPage"; import "./globals.css"; -setupFontAwesomeIcons(); - export function NextApp({ Component, pageProps, router }: AppProps>): ReactElement { const theme = pageProps.config?.colorsV3?.type; useInterceptNextDataHref({ diff --git a/packages/ui/app/src/sidebar/SidebarTabButton.tsx b/packages/ui/app/src/sidebar/SidebarTabButton.tsx index 5e6d8f8867..6e9a881851 100644 --- a/packages/ui/app/src/sidebar/SidebarTabButton.tsx +++ b/packages/ui/app/src/sidebar/SidebarTabButton.tsx @@ -2,7 +2,7 @@ import { DocsV1Read } from "@fern-api/fdr-sdk"; import classNames from "classnames"; import Link from "next/link"; import { memo } from "react"; -import { FontAwesomeIcon } from "../commons/FontAwesomeIcon"; +import { RemoteFontAwesomeIcon } from "../commons/FontAwesomeIcon"; export declare namespace SidebarTabButton { export interface Props { @@ -38,12 +38,12 @@ const UnmemoizedSidebarTabButton: React.FC = ({ tab, sel }, )} > - >; + +declare module "*.module.scss" { + const classes: CSSModuleClasses; + export default classes; +} + +// CSS +declare module "*.css" {} +declare module "*.scss" {} + +// images +declare module "*.png" { + const src: string; + export default { src }; +} +declare module "*.jpg" { + const src: string; + export default { src }; +} +declare module "*.jpeg" { + const src: string; + export default { src }; +} +declare module "*.gif" { + const src: string; + export default { src }; +} +declare module "*.svg" { + const src: string; + export default { src }; +} +declare module "*.ico" { + const src: string; + export default { src }; +} diff --git a/packages/ui/fontawesome-cdn/src/index.ts b/packages/ui/fontawesome-cdn/src/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/ui/fontawesome-cdn/src/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/ui/fontawesome-cdn/src/pages/[style]/[icon].ts b/packages/ui/fontawesome-cdn/src/pages/[style]/[icon].ts new file mode 100644 index 0000000000..865d0b61ea --- /dev/null +++ b/packages/ui/fontawesome-cdn/src/pages/[style]/[icon].ts @@ -0,0 +1,75 @@ +import { AbstractElement, icon, IconPrefix, library } from "@fortawesome/fontawesome-svg-core"; +import { fab, IconName } from "@fortawesome/free-brands-svg-icons"; +import { fas } from "@fortawesome/free-solid-svg-icons"; +import { fad } from "@fortawesome/pro-duotone-svg-icons"; +import { fal } from "@fortawesome/pro-light-svg-icons"; +import { far } from "@fortawesome/pro-regular-svg-icons"; +import { fas as fasPro } from "@fortawesome/pro-solid-svg-icons"; +import { GetServerSideProps } from "next"; + +library.add(fas, fab, fad, fal, far, fasPro); + +export default function FontawesomeIcon(): null { + return null; +} + +// This gets called on every request +export const getServerSideProps: GetServerSideProps = async ({ params = {}, res }) => { + const { style, icon: iconName } = params; + + if (typeof style !== "string" || typeof iconName !== "string" || !iconName.endsWith(".svg")) { + return { notFound: true }; + } + const prefix = getIconPrefix(style); + + const foundIcon = icon({ prefix, iconName: iconName.replace(".svg", "") as IconName }); + + if (foundIcon == null || foundIcon.abstract[0] == null) { + return { notFound: true }; + } + + const iconAbstract = foundIcon.abstract[0]; + + res.setHeader("Content-Type", "image/svg+xml"); + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Methods", "GET"); + + res.setHeader("Cache-Control", "public, max-age=31536000, immutable"); + res.write(abstractToString(iconAbstract)); + res.end(); + return { props: {} }; +}; + +const DUOTONE_CSS = ""; + +function abstractToString(abstract: AbstractElement): string { + const attributes = Object.entries(abstract.attributes) + .map(([key, value]) => `${key}="${value}"`) + .join(" "); + if (abstract.children == null) { + return `<${abstract.tag} ${attributes} />`; + } else { + const children = abstract.children.map(abstractToString).join(""); + if (abstract.tag === "svg") { + return `<${abstract.tag} ${attributes}>${DUOTONE_CSS}${children}`; + } + return `<${abstract.tag} ${attributes}>${children}`; + } +} + +function getIconPrefix(style: string): IconPrefix { + switch (style) { + case "brands": + return "fab"; + case "duotone": + return "fad"; + case "light": + return "fal"; + case "regular": + return "far"; + case "solid": + return "fas"; + default: + return "fas"; + } +} diff --git a/packages/ui/fontawesome-cdn/tsconfig.json b/packages/ui/fontawesome-cdn/tsconfig.json new file mode 100644 index 0000000000..16a75a892e --- /dev/null +++ b/packages/ui/fontawesome-cdn/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../shared/tsconfig.shared.json", + "compilerOptions": { + "composite": true, + "outDir": "lib", + "rootDir": "src", + "allowJs": true, + "incremental": true, + "noEmit": true, + "jsx": "preserve", + "plugins": [{ "name": "next" }] + }, + "include": ["./src/**/*"], + "exclude": ["node_modules"] +} diff --git a/packages/ui/public-docs-bundle/.env-cmdrc.cjs b/packages/ui/public-docs-bundle/.env-cmdrc.cjs index b891cddd18..dffda38714 100644 --- a/packages/ui/public-docs-bundle/.env-cmdrc.cjs +++ b/packages/ui/public-docs-bundle/.env-cmdrc.cjs @@ -4,14 +4,16 @@ module.exports = { NEXT_PUBLIC_POSTHOG_API_KEY: "", NEXT_PUBLIC_ALGOLIA_APP_ID: "CQINPZSKS3", NEXT_PUBLIC_ALGOLIA_API_KEY: "9515d5b15764da73b5cfad85772779fa", - NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX: "search_index_dev" + NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX: "search_index_dev", + NEXT_PUBLIC_FONTAWESOME_CDN_HOST: process.env.FONTAWESOME_CDN_HOST }, "fern-prod": { NEXT_PUBLIC_FDR_ORIGIN: "https://registry.buildwithfern.com", NEXT_PUBLIC_POSTHOG_API_KEY: process.env.POSTHOG_API_KEY, NEXT_PUBLIC_ALGOLIA_APP_ID: process.env.ALGOLIA_APP_ID, NEXT_PUBLIC_ALGOLIA_API_KEY: process.env.ALGOLIA_API_KEY, - NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX: "search_index_prod" + NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX: "search_index_prod", + NEXT_PUBLIC_FONTAWESOME_CDN_HOST: process.env.FONTAWESOME_CDN_HOST }, "fern-preview": { NEXT_PUBLIC_FDR_ORIGIN: "http://localhost:3000" diff --git a/packages/ui/public-docs-bundle/.mrlint.json b/packages/ui/public-docs-bundle/.mrlint.json index 8720297b7d..e9f912760e 100644 --- a/packages/ui/public-docs-bundle/.mrlint.json +++ b/packages/ui/public-docs-bundle/.mrlint.json @@ -8,7 +8,8 @@ "NEXT_PUBLIC_POSTHOG_API_KEY", "NEXT_PUBLIC_ALGOLIA_APP_ID", "NEXT_PUBLIC_ALGOLIA_API_KEY", - "NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX" + "NEXT_PUBLIC_ALGOLIA_SEARCH_INDEX", + "NEXT_PUBLIC_FONTAWESOME_CDN_HOST" ] }, "rules": { diff --git a/yarn.lock b/yarn.lock index 3b6761ba66..8fd76ca41d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2565,6 +2565,34 @@ __metadata: languageName: unknown linkType: soft +"@fern-ui/fontawesome-cdn@workspace:packages/ui/fontawesome-cdn": + version: 0.0.0-use.local + resolution: "@fern-ui/fontawesome-cdn@workspace:packages/ui/fontawesome-cdn" + dependencies: + "@fortawesome/fontawesome-svg-core": ^6.5.1 + "@fortawesome/free-brands-svg-icons": ^6.5.1 + "@fortawesome/free-solid-svg-icons": ^6.5.1 + "@fortawesome/pro-duotone-svg-icons": ^6.5.1 + "@fortawesome/pro-light-svg-icons": ^6.5.1 + "@fortawesome/pro-regular-svg-icons": ^6.5.1 + "@fortawesome/pro-solid-svg-icons": ^6.5.1 + "@next/bundle-analyzer": ^14.0.3 + "@types/jest": ^29.5.11 + "@types/node": ^18.7.18 + "@types/react": ^18.0.20 + depcheck: ^1.4.3 + eslint: ^8.56.0 + jest: ^29.7.0 + next: ^14.0.4 + organize-imports-cli: ^0.10.0 + prettier: ^3.2.4 + react: ^18.2.0 + react-dom: ^18.2.0 + stylelint: ^16.1.0 + typescript: 4.9.4 + languageName: unknown + linkType: soft + "@fern-ui/fonts@workspace:*, @fern-ui/fonts@workspace:packages/commons/react/fonts": version: 0.0.0-use.local resolution: "@fern-ui/fonts@workspace:packages/commons/react/fonts" @@ -2818,14 +2846,6 @@ __metadata: "@fern-ui/loadable": "workspace:*" "@fern-ui/react-commons": "workspace:*" "@fontsource/ibm-plex-mono": ^4.5.13 - "@fortawesome/fontawesome-svg-core": ^6.5.1 - "@fortawesome/free-brands-svg-icons": ^6.5.1 - "@fortawesome/free-solid-svg-icons": ^6.5.1 - "@fortawesome/pro-duotone-svg-icons": ^6.5.1 - "@fortawesome/pro-light-svg-icons": ^6.5.1 - "@fortawesome/pro-regular-svg-icons": ^6.5.1 - "@fortawesome/pro-solid-svg-icons": ^6.5.1 - "@fortawesome/react-fontawesome": 0.2.0 "@headlessui/react": ^1.7.18 "@react-hook/size": ^2.1.2 "@testing-library/react": ^14.0.0 @@ -2950,18 +2970,6 @@ __metadata: languageName: node linkType: hard -"@fortawesome/react-fontawesome@npm:0.2.0": - version: 0.2.0 - resolution: "@fortawesome/react-fontawesome@npm:0.2.0" - dependencies: - prop-types: ^15.8.1 - peerDependencies: - "@fortawesome/fontawesome-svg-core": ~1 || ~6 - react: ">=16.3" - checksum: f652a0c2172e7b209e2d9e7e511f9b8c17abad85f55e0bd09bb1175ea1927693215da47eb6cd95b1f3a23bd124368553c677907fa76cb17c5093afc1fcffe338 - languageName: node - linkType: hard - "@gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3"