diff --git a/.gitignore b/.gitignore index 849425fe..a0f0371b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ yarn-error.log* # turbo .turbo + +# vscode +.vscode diff --git a/.prettierignore b/.prettierignore index b8a67e58..04307c26 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,6 @@ **/dist **/.docusaurus pnpm-lock.yaml + +/apps/website/src/pages/plugins/**/index.mdx +/apps/website/src/pages/gpts/**/index.mdx diff --git a/apps/website/.gitignore b/apps/website/.gitignore index 98c940d5..60e2ab7a 100644 --- a/apps/website/.gitignore +++ b/apps/website/.gitignore @@ -21,3 +21,5 @@ yarn-error.log* /src/pages/plugins !/src/pages/plugins.tsx +/src/pages/gpts +!/src/pages/gpts.tsx diff --git a/apps/website/content/gpts-list.js b/apps/website/content/gpts-list.js new file mode 100644 index 00000000..eecfca6c --- /dev/null +++ b/apps/website/content/gpts-list.js @@ -0,0 +1,93 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @type {import('ui/types').GPT[]} */ +const GPT_LIST = [ + { + title: 'Ansible Job', + description: 'Launch an Ansible Job within Ansible Automation Platform', + href: 'gpts/ansible-job', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/ansible-job/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/ansible-job', + }, + { + title: 'Add ArgoCD to an existing project', + description: 'Add ArgoCD to an existing project', + href: 'gpts/argocd', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/argocd-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/argocd-template', + }, + { + title: '.NET Frontend application', + description: 'Create a starter .NET frontend application with a CI pipeline', + href: 'gpts/dotnet-frontend', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/dotnet-frontend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/dotnet-frontend-template', + }, + { + title: 'Go Backend application', + description: 'Create a starter Go backend application with a CI pipeline', + href: 'gpts/go-backend', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/go-backend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/go-backend-template', + }, + { + title: 'Node.js Backend application', + description: 'Create a starter Node.js backend application with a CI pipeline', + href: 'gpts/nodejs-backend', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/nodejs-backend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/nodejs-backend-template', + }, + { + title: 'Python Backend application', + description: 'Create a starter Python backend application with a CI pipeline', + href: 'gpts/python-backend', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/python-backend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/python-backend-template', + }, + { + title: 'Quarkus Backend application', + description: 'Create a starter Quarkus Backend application with a CI pipeline', + href: `gpts/quarkus-backend`, + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/quarkus-backend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/quarkus-backend-template', + }, + { + title: 'Spring Boot Backend application', + description: 'Create a starter Spring Boot backend application with a CI pipeline', + href: 'gpts/spring-boot-backend', + githubUrl: + 'https://raw.githubusercontent.com/janus-idp/software-templates/main/scaffolder-templates/spring-boot-backend-template/README.md', + sourceUrl: + 'https://github.com/janus-idp/software-templates/tree/main/scaffolder-templates/spring-boot-backend-template', + }, +]; + +module.exports = { GPT_LIST }; diff --git a/apps/website/content/plugin-list.js b/apps/website/content/plugin-list.js index 915a3562..ecdfef27 100644 --- a/apps/website/content/plugin-list.js +++ b/apps/website/content/plugin-list.js @@ -23,7 +23,7 @@ const PLUGINS_LIST = [ href: '/plugins/3scale', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/3scale-backend/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-3scale-backend', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-3scale-backend', category: 'Backend', }, { @@ -34,7 +34,7 @@ const PLUGINS_LIST = [ href: '/plugins/keycloak', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/keycloak-backend/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-keycloak-backend', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-keycloak-backend', category: 'Backend', }, { @@ -44,7 +44,7 @@ const PLUGINS_LIST = [ href: '/plugins/acr', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/openshift-image-registry/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-openshift-image-registry', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-openshift-image-registry', category: 'Frontend', }, { @@ -54,7 +54,7 @@ const PLUGINS_LIST = [ href: '/plugins/jfrog-artifactory', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/jfrog-artifactory/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-jfrog-artifactory', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-jfrog-artifactory', category: 'Frontend', }, { @@ -64,7 +64,7 @@ const PLUGINS_LIST = [ href: '/plugins/quay', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/quay/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-quay', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-quay', category: 'Frontend', }, { @@ -74,7 +74,7 @@ const PLUGINS_LIST = [ href: '/plugins/ocm', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/ocm/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-ocm', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-ocm', category: 'Frontend', }, { @@ -85,7 +85,7 @@ const PLUGINS_LIST = [ href: '/plugins/topology', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/topology/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-topology', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-topology', category: 'Frontend', }, { @@ -95,9 +95,9 @@ const PLUGINS_LIST = [ href: '/plugins/tekton', githubUrl: 'https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/tekton/README.md', - npmUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-tekton', + sourceUrl: 'https://www.npmjs.com/package/@janus-idp/backstage-plugin-tekton', category: 'Frontend', }, ]; -module.exports = PLUGINS_LIST; +module.exports = { PLUGINS_LIST }; diff --git a/apps/website/docusaurus.config.js b/apps/website/docusaurus.config.js index 312e5679..135b17eb 100644 --- a/apps/website/docusaurus.config.js +++ b/apps/website/docusaurus.config.js @@ -17,8 +17,9 @@ const lightCodeTheme = require('prism-react-renderer').themes.github; const darkCodeTheme = require('prism-react-renderer').themes.vsDark; const dotenv = require('dotenv'); -/** @type {import('ui/types').Plugin[]} */ -const PLUGINS_LIST = require('./content/plugin-list'); +const { PLUGINS_LIST } = require('./content/plugin-list'); +const { GPT_LIST } = require('./content/gpts-list'); +const { fetchRemoteContent } = require('./src/lib/utils/fetch-remote-content'); darkCodeTheme.plain.backgroundColor = '#232323'; @@ -27,41 +28,6 @@ dotenv.config({ path: `.env.local`, override: true }); const copyright = `Copyright © ${new Date().getFullYear()} Janus -- All Rights Reserved
Apache License 2.0 open source project`; -const linkRegex = /!\[([\w .-]+)]\(\.\/([\w ./-]+)\)/gm; -const remoteContent = PLUGINS_LIST.map((plugin) => { - const filenameIndex = plugin.githubUrl.lastIndexOf('/') + 1; - const sourceBaseUrl = plugin.githubUrl.slice(0, Math.max(0, filenameIndex)); - const filename = plugin.githubUrl.slice(Math.max(0, filenameIndex)); - - return [ - 'docusaurus-plugin-remote-content', - { - name: `${plugin.title}-content`, - sourceBaseUrl, - outDir: `src/pages/${plugin.href}`, - documents: [filename], - modifyContent: (fname, content) => { - if (fname.includes('README')) { - return { - filename: 'index.mdx', - content: `--- -title: ${plugin.title} -description: ${plugin.description} ---- -import { PluginHeader } from 'ui/components'; - - `${key}:"${value}"`) - .join(',')}}} /> - -${content.replaceAll(linkRegex, `![$1](${sourceBaseUrl}$2)`)}`, - }; - } - }, - }, - ]; -}); - /** @type {import('@docusaurus/types').Config} */ const config = { title: 'Janus', @@ -139,6 +105,7 @@ const config = { { to: '/blog', label: 'Blog', position: 'left' }, { to: '/community', label: 'Community', position: 'left' }, { to: '/plugins', label: 'Plugins', position: 'left' }, + { to: '/gpts', label: 'GPTs', position: 'left' }, { href: 'https://showcase.janus-idp.io/', label: 'Showcase', @@ -232,7 +199,11 @@ const config = { }, }), - plugins: ['docusaurus-plugin-tailwind', ...remoteContent], + plugins: [ + 'docusaurus-plugin-tailwind', + ...fetchRemoteContent(PLUGINS_LIST, 'PluginHeader'), + ...fetchRemoteContent(GPT_LIST, 'GPTHeader'), + ], }; module.exports = config; diff --git a/apps/website/src/lib/utils/fetch-remote-content.js b/apps/website/src/lib/utils/fetch-remote-content.js new file mode 100644 index 00000000..bef3f2d6 --- /dev/null +++ b/apps/website/src/lib/utils/fetch-remote-content.js @@ -0,0 +1,61 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const linkRegex = /!\[([\w .-]+)]\(\.\/([\w ./-]+)\)/gm; + +/** + * @param {import('ui/types').RemoteContent[]} remoteContent + * @param {string} component + * + * @returns {import('ui/types').DocusaurusRemoteContent[]} + */ +function fetchRemoteContent(remoteContent, component) { + return remoteContent.map((plugin) => { + const filenameIndex = plugin.githubUrl.lastIndexOf('/') + 1; + const sourceBaseUrl = plugin.githubUrl.slice(0, Math.max(0, filenameIndex)); + const filename = plugin.githubUrl.slice(Math.max(0, filenameIndex)); + + return [ + 'docusaurus-plugin-remote-content', + { + name: `${plugin.title}-content`, + sourceBaseUrl, + outDir: `src/pages/${plugin.href}`, + documents: [filename], + modifyContent: (fname, content) => { + if (fname.includes('README')) { + return { + filename: 'index.mdx', + content: `--- +title: ${plugin.title} +description: ${plugin.description} +--- +import { ${component} } from 'ui/components'; + +<${component} remoteContent={{${Object.entries(plugin) + .map(([key, value]) => `${key}:"${value}"`) + .join(',')}}} /> + +${content.replaceAll(linkRegex, `![$1](${sourceBaseUrl}$2)`)}`, + }; + } + }, + }, + ]; + }); +} + +module.exports = { fetchRemoteContent }; diff --git a/apps/website/src/pages/gpts.tsx b/apps/website/src/pages/gpts.tsx new file mode 100644 index 00000000..f0c9489d --- /dev/null +++ b/apps/website/src/pages/gpts.tsx @@ -0,0 +1,59 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Link from '@docusaurus/Link'; +import { GPT_LIST } from '@site/content/gpts-list'; +import Layout from '@theme/Layout'; +import Fuse from 'fuse.js'; +import React from 'react'; +import { GPTsGrid } from 'ui/components'; +import { GPT } from 'ui/types'; + +const GPT_FUSE = new Fuse(GPT_LIST as GPT[], { + threshold: 0.25, + ignoreLocation: true, + keys: [{ name: 'title', weight: 2 }, 'description'], +}); + +function GPTsHeader(): JSX.Element { + return ( +
+
+

Janus Golden Path Templates

+

Have a GPT idea?

+
+ + Submit a proposal for a GPT! + +
+
+
+ ); +} + +export default function Plugins(): JSX.Element { + return ( + + +
+ +
+
+ ); +} diff --git a/apps/website/src/pages/plugins.tsx b/apps/website/src/pages/plugins.tsx index 148e70d3..f0b22fd4 100644 --- a/apps/website/src/pages/plugins.tsx +++ b/apps/website/src/pages/plugins.tsx @@ -15,13 +15,14 @@ */ import Link from '@docusaurus/Link'; +import { PLUGINS_LIST } from '@site/content/plugin-list'; import Layout from '@theme/Layout'; import Fuse from 'fuse.js'; import React from 'react'; import { PluginsGrid } from 'ui/components'; -import PLUGINS_LIST from '../../content/plugin-list'; +import { Plugin } from 'ui/types'; -const pluginsFuse = new Fuse(PLUGINS_LIST, { +const PLUGIN_FUSE = new Fuse(PLUGINS_LIST as Plugin[], { threshold: 0.25, ignoreLocation: true, keys: [{ name: 'title', weight: 2 }, 'description'], @@ -51,7 +52,7 @@ export default function Plugins(): JSX.Element {
- +
); diff --git a/apps/website/tsconfig.json b/apps/website/tsconfig.json index 90bcb5c1..80e0eb56 100644 --- a/apps/website/tsconfig.json +++ b/apps/website/tsconfig.json @@ -3,6 +3,7 @@ "extends": "@tsconfig/docusaurus/tsconfig.json", "compilerOptions": { "baseUrl": ".", - "checkJs": true + "checkJs": true, + "lib": ["DOM", "ESNext"] } } diff --git a/package.json b/package.json index 9cb49962..ced99119 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "preinstall": "npx only-allow pnpm", - "ci": "turbo run lint tsc build test:unit test:e2e", + "ci": "turbo run lint build test:unit test:e2e", "build": "turbo run build", "export": "turbo run export", "dev": "turbo run dev --parallel", diff --git a/packages/ui/components/gpt-grid/gpt-grid.tsx b/packages/ui/components/gpt-grid/gpt-grid.tsx new file mode 100644 index 00000000..e8b61574 --- /dev/null +++ b/packages/ui/components/gpt-grid/gpt-grid.tsx @@ -0,0 +1,59 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Fuse from 'fuse.js'; +import React from 'react'; +import { useSearch } from '../../hooks'; +import { GPT } from '../../types'; +import { Searchbar } from '../searchbar/searchbar'; +import { Tile } from '../tile/tile'; + +type GPTTileProps = GPT; + +function GPTTile({ title, description, href }: GPTTileProps): JSX.Element { + return ( + +
+

{title}

+

{description}

+
+
+ ); +} + +type GPTsFeaturesProps = { + GPT_FUSE: Fuse; + GPT_LIST: GPT[]; +}; + +export function GPTsGrid({ GPT_FUSE, GPT_LIST }: GPTsFeaturesProps): JSX.Element { + const { + content: gpts, + search, + setSearch, + } = useSearch({ CONTENT_FUSE: GPT_FUSE, CONTENT_LIST: GPT_LIST }); + + return ( +
+ +
+ {gpts.map((gpt) => ( + + ))} +
+
+ ); +} diff --git a/packages/ui/components/gpt-header/gpt-header.tsx b/packages/ui/components/gpt-header/gpt-header.tsx new file mode 100644 index 00000000..c922d432 --- /dev/null +++ b/packages/ui/components/gpt-header/gpt-header.tsx @@ -0,0 +1,40 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useContext } from 'react'; +import { EnvironmentContext } from '../../contexts'; +import { GPT } from '../../types'; + +export type GPTHeaderProps = { + remoteContent: GPT; +}; + +export function GPTHeader(props: GPTHeaderProps): JSX.Element { + const { remoteContent } = props; + const { Link } = useContext(EnvironmentContext); + + return ( +
+
+

{remoteContent.title}

+

{remoteContent.description}

+
+
+ Github Repo +
+
+ ); +} diff --git a/packages/ui/components/index.tsx b/packages/ui/components/index.tsx index 632a7653..672e377a 100644 --- a/packages/ui/components/index.tsx +++ b/packages/ui/components/index.tsx @@ -15,8 +15,12 @@ */ export * from './banner/banner'; +export * from './gpt-grid/gpt-grid'; +export * from './gpt-header/gpt-header'; export * from './homepage-grid/homepage-grid'; export * from './plugin-grid/plugin-grid'; export * from './plugin-header/plugin-header'; -export * from './plugin-searchbar/plugin-searchbar'; +export * from './searchbar/searchbar'; +export * from './searchbar/types'; +export * from './tile/tile'; export * from './tooltip/tooltip'; diff --git a/packages/ui/components/plugin-grid/plugin-grid.tsx b/packages/ui/components/plugin-grid/plugin-grid.tsx index 99b9b9b3..9b3260ec 100644 --- a/packages/ui/components/plugin-grid/plugin-grid.tsx +++ b/packages/ui/components/plugin-grid/plugin-grid.tsx @@ -15,122 +15,84 @@ */ import { Cog8ToothIcon } from '@heroicons/react/20/solid'; -import { motion, useMotionTemplate, useMotionValue } from 'framer-motion'; import type Fuse from 'fuse.js'; -import React, { useCallback, useContext, useMemo, useState } from 'react'; +import React from 'react'; import { FaNodeJs as NodejsIcon, FaReact as ReactIcon } from 'react-icons/fa'; -import { StringParam, useQueryParams } from 'use-query-params'; -import { EnvironmentContext } from '../../contexts'; +import { useSearch } from '../../hooks'; import { Plugin } from '../../types'; -import { PLUGIN_CATEGORIES, PluginSearchbar } from '../plugin-searchbar/plugin-searchbar'; +import { Searchbar } from '../searchbar/searchbar'; +import { PLUGIN_CATEGORIES } from '../searchbar/types'; +import { Tile } from '../tile/tile'; import { Tooltip } from '../tooltip/tooltip'; type PluginTileProps = Plugin; function PluginTile({ icon, title, description, href, category }: PluginTileProps): JSX.Element { - const { Link } = useContext(EnvironmentContext); - - const mouseX = useMotionValue(0); - const mouseY = useMotionValue(0); - - const handleMouseMove = useCallback( - ({ currentTarget, clientX, clientY }: React.MouseEvent) => { - const { left, top } = currentTarget.getBoundingClientRect(); - - mouseX.set(clientX - left); - mouseY.set(clientY - top); - }, - [mouseX, mouseY], - ); - return ( - - -
-
- {`${title} -

{title}

-

{description}

-
-
- {/* Node.js brand guidelines require us to use a white icon on a dark background and vice versa */} - {category === 'Backend' && ( - } - popupContent={category} - /> - )} - {category === 'Frontend' && ( - } - popupContent={category} - /> - )} - {category === 'Custom Actions' && ( - } - popupContent={category} - /> - )} -
+ +
+ {`${title} +

{title}

+

{description}

- +
+ {/* Node.js brand guidelines require us to use a white icon on a dark background and vice versa */} + {category === 'Backend' && ( + + } + popupContent={category} + /> + )} + {category === 'Frontend' && ( + + } + popupContent={category} + /> + )} + {category === 'Custom Actions' && ( + + } + popupContent={category} + /> + )} +
+
); } type PluginsFeaturesProps = { - pluginsFuse: Fuse; - pluginsList: Plugin[]; + PLUGIN_FUSE: Fuse; + PLUGIN_LIST: Plugin[]; }; -export function PluginsGrid({ pluginsFuse, pluginsList }: PluginsFeaturesProps): JSX.Element { - // search state cannot be lifted to query params because docusaurus uses react router v5 - // which does not support a shallow updates. i.e. every time the state changes, the page - // will lose focus on the input field. - const [queryParams, setQueryParams] = useQueryParams({ - category: StringParam, +export function PluginsGrid({ PLUGIN_FUSE, PLUGIN_LIST }: PluginsFeaturesProps): JSX.Element { + const { + content: plugins, + category, + search, + setSearch, + setQueryParams, + } = useSearch({ + CATEGORIES: PLUGIN_CATEGORIES, + CONTENT_FUSE: PLUGIN_FUSE, + CONTENT_LIST: PLUGIN_LIST, }); - const [search, setSearch] = useState(''); - - const pluginCategory = - PLUGIN_CATEGORIES.find(({ slug }) => slug === queryParams.category) || PLUGIN_CATEGORIES[0]; - - const plugins = useMemo(() => { - let p = pluginsList; - - if (search !== '') { - p = pluginsFuse.search(search).map(({ item }) => item); - } - - if (pluginCategory.name !== 'All plugins') { - p = p.filter(({ category }) => category === pluginCategory.name); - } - - return p; - }, [pluginCategory.name, pluginsFuse, pluginsList, search]); return (
-
{plugins.map((plugin) => ( diff --git a/packages/ui/components/plugin-header/plugin-header.tsx b/packages/ui/components/plugin-header/plugin-header.tsx index d1f07a40..77cf2013 100644 --- a/packages/ui/components/plugin-header/plugin-header.tsx +++ b/packages/ui/components/plugin-header/plugin-header.tsx @@ -19,23 +19,23 @@ import { EnvironmentContext } from '../../contexts'; import { Plugin } from '../../types'; export type PluginHeaderProps = { - plugin: Plugin; + remoteContent: Plugin; }; export function PluginHeader(props: PluginHeaderProps): JSX.Element { - const { plugin } = props; + const { remoteContent } = props; const { Link } = useContext(EnvironmentContext); return (
- {plugin?.title} + {remoteContent.title}
-

{plugin.title}

-

{plugin.description}

+

{remoteContent.title}

+

{remoteContent.description}

- NPM + NPM
); diff --git a/packages/ui/components/plugin-searchbar/plugin-searchbar.tsx b/packages/ui/components/plugin-searchbar/plugin-searchbar.tsx deleted file mode 100644 index ed06c915..00000000 --- a/packages/ui/components/plugin-searchbar/plugin-searchbar.tsx +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright 2023 Janus Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ChevronDownIcon, MagnifyingGlassIcon } from '@heroicons/react/20/solid'; -import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import * as Form from '@radix-ui/react-form'; -import { AnimatePresence, motion, useAnimationControls } from 'framer-motion'; -import React, { useEffect, useRef, useState } from 'react'; -import { PluginCategoryKind } from '../../types'; - -type QueryParams = { - category: string | null; -}; - -type PluginCategory = { - name: PluginCategoryKind | 'All plugins'; - slug: string | null; -}; - -export const PLUGIN_CATEGORIES: PluginCategory[] = [ - { name: 'All plugins', slug: null }, - { name: 'Frontend', slug: 'frontend' }, - { name: 'Backend', slug: 'backend' }, - { name: 'Custom Actions', slug: 'custom-actions' }, -]; - -export type PluginSearchbarProps = { - search: string; - setSearch: React.Dispatch>; - setQueryParams: (partial: Partial) => void; - pluginCategory: PluginCategory; -}; - -export function PluginSearchbar(props: PluginSearchbarProps): JSX.Element { - const { search, setSearch, setQueryParams, pluginCategory } = props; - - const searchRef = useRef(null); - const [open, setOpen] = useState(false); - const controls = useAnimationControls(); - - useEffect(() => { - searchRef.current?.focus(); - setQueryParams({ category: pluginCategory.slug }); - /// run on mount - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - if (open) { - controls.start('open').catch(() => {}); - } - }, [controls, open]); - - return ( - - - Search plugins - - - - - - - - {open && ( - - - -
- {PLUGIN_CATEGORIES.map(({ name, slug }) => ( - - - - ))} -
-
-
-
- )} -
-
- -
- setSearch(e.target.value)} - id="plugin-search" - className="text-pf-cyan-300 dark:bg-pf-cyan-300/[0.15] bg-pf-cyan-50 placeholder-pf-cyan-300 dark:border-pf-cyan-300/30 border-pf-cyan-300/20 ring-pf-cyan-300 outline-pf-cyan-300 outline-solid z-20 block w-full rounded-r-lg border border-x-0 border-solid p-2.5 text-sm outline-0 focus:ring-1" - placeholder="Search plugins..." - required - /> -
- - Search -
-
-
-
- ); -} diff --git a/packages/ui/components/searchbar/searchbar.tsx b/packages/ui/components/searchbar/searchbar.tsx new file mode 100644 index 00000000..d28c40bd --- /dev/null +++ b/packages/ui/components/searchbar/searchbar.tsx @@ -0,0 +1,182 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChevronDownIcon, MagnifyingGlassIcon } from '@heroicons/react/20/solid'; +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; +import * as Form from '@radix-ui/react-form'; +import { AnimatePresence, motion, useAnimationControls } from 'framer-motion'; +import React, { useEffect, useRef, useState } from 'react'; +import { CategoryOptions } from './types'; + +type SearchbarCategoryProps = { + category: T; + setQueryParams: ( + partial: Partial<{ + category: string | null; + }>, + ) => void; + CATEGORIES: { name: string; slug: string | null }[]; +}; + +export type SearchbarProps = { + search: string; + setSearch: React.Dispatch>; + id: string; +} & (T extends CategoryOptions + ? SearchbarCategoryProps + : Partial>); + +function hasCategories( + props: SearchbarProps, +): props is SearchbarProps { + if (props.category === undefined) { + return false; + } + + if (props.setQueryParams === undefined) { + return false; + } + + if (props.CATEGORIES === undefined) { + return false; + } + + return true; +} + +export function Searchbar( + props: SearchbarProps, +): JSX.Element { + const { search, setSearch, id } = props; + + const searchRef = useRef(null); + + useEffect(() => { + searchRef.current?.focus(); + if (hasCategories(props)) { + const { setQueryParams, category } = props; + + setQueryParams({ category: category.slug }); + } + /// run on mount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( + + + Search {id}s + + {hasCategories(props) ? ( + + ) : ( +
+ All {id}s +
+ )} + +
+ setSearch(e.target.value)} + id={`${id}-search`} + className="text-pf-cyan-300 dark:bg-pf-cyan-300/[0.15] bg-pf-cyan-50 placeholder-pf-cyan-300 dark:border-pf-cyan-300/30 border-pf-cyan-300/20 ring-pf-cyan-300 outline-pf-cyan-300 outline-solid z-20 block w-full rounded-r-lg border border-x-0 border-solid p-2.5 text-sm outline-0 focus:ring-1" + placeholder={`Search ${id}s...`} + required + /> +
+ + Search +
+
+
+
+ ); +} + +function SearchbarDropdown(props: SearchbarProps): JSX.Element { + const { category, setQueryParams, CATEGORIES, id } = props; + + const [open, setOpen] = useState(false); + const controls = useAnimationControls(); + + useEffect(() => { + if (open) { + controls.start('open').catch(() => {}); + } + }, [controls, open]); + + return ( + + + + + + + {open && ( + + + +
+ {CATEGORIES.map(({ name, slug }) => ( + + + + ))} +
+
+
+
+ )} +
+
+ ); +} diff --git a/packages/ui/components/searchbar/types.ts b/packages/ui/components/searchbar/types.ts new file mode 100644 index 00000000..c9978d49 --- /dev/null +++ b/packages/ui/components/searchbar/types.ts @@ -0,0 +1,31 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PluginCategoryKind } from '../../types'; + +export type PluginCategory = { + name: PluginCategoryKind | 'All plugins'; + slug: string | null; +}; + +export const PLUGIN_CATEGORIES: PluginCategory[] = [ + { name: 'All plugins', slug: null }, + { name: 'Frontend', slug: 'frontend' }, + { name: 'Backend', slug: 'backend' }, + { name: 'Custom Actions', slug: 'custom-actions' }, +]; + +export type CategoryOptions = PluginCategory; diff --git a/packages/ui/components/tile/tile.tsx b/packages/ui/components/tile/tile.tsx new file mode 100644 index 00000000..beff059c --- /dev/null +++ b/packages/ui/components/tile/tile.tsx @@ -0,0 +1,64 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { motion, useMotionTemplate, useMotionValue } from 'framer-motion'; +import React, { useCallback, useContext, type PropsWithChildren } from 'react'; +import { EnvironmentContext } from '../../contexts'; + +export type TileProps = { + href: string; +}; + +export function Tile({ href, children }: PropsWithChildren): JSX.Element { + const { Link } = useContext(EnvironmentContext); + + const mouseX = useMotionValue(0); + const mouseY = useMotionValue(0); + + const handleMouseMove = useCallback( + ({ currentTarget, clientX, clientY }: React.MouseEvent) => { + const { left, top } = currentTarget.getBoundingClientRect(); + + mouseX.set(clientX - left); + mouseY.set(clientY - top); + }, + [mouseX, mouseY], + ); + + return ( + + +
+ {children} +
+ + ); +} diff --git a/packages/ui/hooks/index.tsx b/packages/ui/hooks/index.tsx index ac0082b7..d5376a0d 100644 --- a/packages/ui/hooks/index.tsx +++ b/packages/ui/hooks/index.tsx @@ -15,3 +15,4 @@ */ export * from './use-analytics/use-analytics'; +export * from './use-search/use-search'; diff --git a/packages/ui/hooks/use-search/use-search.tsx b/packages/ui/hooks/use-search/use-search.tsx new file mode 100644 index 00000000..8f8af2bd --- /dev/null +++ b/packages/ui/hooks/use-search/use-search.tsx @@ -0,0 +1,79 @@ +/** + * Copyright 2023 Janus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type Fuse from 'fuse.js'; +import { useMemo, useState } from 'react'; +import { StringParam, useQueryParams } from 'use-query-params'; +import { type CategoryOptions } from '../../components'; +import { GPT, Plugin } from '../../types'; + +export type UseSearch< + ContentType extends GPT | Plugin, + CategoryType extends CategoryOptions | undefined, +> = { + content: ContentType[]; + category: CategoryType; + search: string; + setSearch: React.Dispatch>; + setQueryParams: ( + partial: Partial<{ + category: string | null; + }>, + ) => void; +}; + +type UseSearchArgs< + ContentType extends GPT | Plugin, + CategoryType extends CategoryOptions | undefined, +> = { + CATEGORIES?: CategoryType[]; + CONTENT_FUSE: Fuse; + CONTENT_LIST: ContentType[]; +}; + +export function useSearch< + ContentType extends GPT | Plugin, + CategoryType extends CategoryOptions | undefined, +>(args: UseSearchArgs): UseSearch { + const { CATEGORIES, CONTENT_FUSE, CONTENT_LIST } = args; + + // search state cannot be lifted to query params because docusaurus uses react router v5 + // which does not support a shallow updates. i.e. every time the state changes, the page + // will lose focus on the input field. + const [queryParams, setQueryParams] = useQueryParams({ + category: StringParam, + }); + const [search, setSearch] = useState(''); + + const category = + CATEGORIES?.find((element) => element?.slug === queryParams.category) || CATEGORIES?.at(0); + + const content = useMemo(() => { + let c = CONTENT_LIST; + + if (search !== '') { + c = CONTENT_FUSE.search(search).map(({ item }) => item); + } + + if (category !== undefined && !category.name.startsWith('All')) { + c = c.filter((element) => element.category === category.name); + } + + return c; + }, [CONTENT_LIST, search, category, CONTENT_FUSE]); + + return { content, category: category as CategoryType, search, setSearch, setQueryParams }; +} diff --git a/packages/ui/package.json b/packages/ui/package.json index 94623b03..72e50069 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -24,6 +24,7 @@ "@radix-ui/react-form": "0.0.3", "@radix-ui/react-tooltip": "1.0.6", "@segment/analytics-next": "1.53.0", + "@tailwindcss/container-queries": "^0.1.1", "clsx": "1.2.1", "deepmerge": "4.3.1", "framer-motion": "10.12.17", diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index 35e09f2d..48a1720d 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -14,6 +14,8 @@ * limitations under the License. */ +/* eslint-disable global-require */ + module.exports = { content: ['./components/**/*.{js,ts,jsx,tsx}'], theme: { @@ -122,5 +124,5 @@ module.exports = { }, }, }, - plugins: [], + plugins: [require('@tailwindcss/container-queries')], }; diff --git a/packages/ui/types/index.ts b/packages/ui/types/index.ts index 3a95dcc2..cfd2c2c5 100644 --- a/packages/ui/types/index.ts +++ b/packages/ui/types/index.ts @@ -15,17 +15,36 @@ */ export type Feature = { - icon: string; title: string; description: string; }; -export type PluginCategoryKind = 'Frontend' | 'Backend' | 'Custom Actions'; -export type Plugin = Feature & { +export type RemoteContent = Feature & { href: string; githubUrl: string; - npmUrl: string; - category: PluginCategoryKind; + sourceUrl: string; + category?: T; +}; + +export type PluginCategoryKind = 'Frontend' | 'Backend' | 'Custom Actions'; + +export type Plugin = RemoteContent & { + icon: string; +}; + +export type GPT = RemoteContent; + +export type Homepage = Feature & { + icon: string; }; -export type Homepage = Feature; +export type DocusaurusRemoteContent = [ + string, + { + name: string; + sourceBaseUrl: string; + outDir: string; + documents: string[] | Promise; + modifyContent: (filename: string, content: string) => { filename?: string; content?: string }; + }, +]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50caa759..3eaacd06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -219,6 +219,9 @@ importers: '@segment/analytics-next': specifier: 1.53.0 version: 1.53.0 + '@tailwindcss/container-queries': + specifier: ^0.1.1 + version: 0.1.1(tailwindcss@3.3.2) clsx: specifier: 1.2.1 version: 1.2.1 @@ -395,7 +398,6 @@ packages: /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - dev: true /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} @@ -4583,6 +4585,14 @@ packages: dependencies: defer-to-connect: 1.1.3 + /@tailwindcss/container-queries@0.1.1(tailwindcss@3.3.2): + resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} + peerDependencies: + tailwindcss: '>=3.2.0' + dependencies: + tailwindcss: 3.3.2 + dev: false + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -5178,19 +5188,12 @@ packages: mime-types: 2.1.35 negotiator: 0.6.3 - /acorn-import-assertions@1.9.0(acorn@8.8.2): + /acorn-import-assertions@1.9.0(acorn@8.9.0): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.8.2 - - /acorn-jsx@5.3.2(acorn@8.8.2): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.8.2 + acorn: 8.9.0 /acorn-jsx@5.3.2(acorn@8.9.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -5198,22 +5201,15 @@ packages: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.9.0 - dev: false /acorn-walk@8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} - /acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} - engines: {node: '>=0.4.0'} - hasBin: true - /acorn@8.9.0: resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} engines: {node: '>=0.4.0'} hasBin: true - dev: false /address@1.2.2: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} @@ -5331,7 +5327,6 @@ packages: /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} @@ -5919,7 +5914,6 @@ packages: /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: true /commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} @@ -6439,7 +6433,6 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true /diff@5.1.0: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} @@ -7102,8 +7095,8 @@ packages: resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.2 - acorn-jsx: 5.3.2(acorn@8.8.2) + acorn: 8.9.0 + acorn-jsx: 5.3.2(acorn@8.9.0) eslint-visitor-keys: 3.4.1 /esprima@4.0.1: @@ -7629,7 +7622,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -9288,7 +9280,6 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} @@ -9415,7 +9406,6 @@ packages: /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: true /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} @@ -9737,12 +9727,10 @@ packages: /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: true /pirates@4.0.5: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} - dev: true /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -9843,7 +9831,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.2 - dev: true /postcss-js@4.0.1(postcss@8.4.24): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} @@ -9853,7 +9840,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.24 - dev: true /postcss-load-config@4.0.1(postcss@8.4.24): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} @@ -9870,7 +9856,6 @@ packages: lilconfig: 2.1.0 postcss: 8.4.24 yaml: 2.3.1 - dev: true /postcss-loader@7.3.0(postcss@8.4.24)(webpack@5.82.1): resolution: {integrity: sha512-qLAFjvR2BFNz1H930P7mj1iuWJFjGey/nVhimfOAAQ1ZyPpcClAxP8+A55Sl8mBvM+K2a9Pjgdj10KpANWrNfw==} @@ -10003,7 +9988,6 @@ packages: dependencies: postcss: 8.4.24 postcss-selector-parser: 6.0.13 - dev: true /postcss-normalize-charset@5.1.0(postcss@8.4.24): resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} @@ -10677,7 +10661,6 @@ packages: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: true /read-package-json-fast@3.0.2: resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} @@ -11521,7 +11504,6 @@ packages: mz: 2.7.0 pirates: 4.0.5 ts-interface-checker: 0.1.13 - dev: true /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -11604,7 +11586,6 @@ packages: sucrase: 3.32.0 transitivePeerDependencies: - ts-node - dev: true /tapable@1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} @@ -11643,7 +11624,7 @@ packages: hasBin: true dependencies: '@jridgewell/source-map': 0.3.3 - acorn: 8.8.2 + acorn: 8.9.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -11655,13 +11636,11 @@ packages: engines: {node: '>=0.8'} dependencies: thenify: 3.3.1 - dev: true /thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} dependencies: any-promise: 1.3.0 - dev: true /thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} @@ -11730,7 +11709,6 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} @@ -12388,7 +12366,7 @@ packages: hasBin: true dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.8.2 + acorn: 8.9.0 acorn-walk: 8.2.0 chalk: 4.1.2 commander: 7.2.0 @@ -12490,8 +12468,8 @@ packages: '@webassemblyjs/ast': 1.11.6 '@webassemblyjs/wasm-edit': 1.11.6 '@webassemblyjs/wasm-parser': 1.11.6 - acorn: 8.8.2 - acorn-import-assertions: 1.9.0(acorn@8.8.2) + acorn: 8.9.0 + acorn-import-assertions: 1.9.0(acorn@8.9.0) browserslist: 4.21.5 chrome-trace-event: 1.0.3 enhanced-resolve: 5.14.0