From 8d1b174917a86e83cd3de7f7363c9f5af0d2936d Mon Sep 17 00:00:00 2001 From: ozakione <29860391+OzakIOne@users.noreply.github.com> Date: Sun, 24 Mar 2024 22:02:40 +0100 Subject: [PATCH] wip --- .../docusaurus-plugin-showcase/src/index.ts | 46 ++++--- .../docusaurus-plugin-showcase/src/options.ts | 8 +- .../src/plugin-showcase.d.ts | 20 ++- .../docusaurus-theme-classic/package.json | 1 + .../src/theme-classic.d.ts | 12 +- .../Showcase/ShowcaseFilterToggle/index.tsx | 18 ++- .../Showcase/ShowcaseTagSelect/index.tsx | 18 ++- .../src/theme/Showcase/index.tsx | 118 +++++++----------- website/src/components/Showcase.js | 12 -- website/src/showcase/website/dino.yaml | 6 + website/src/showcase/website/ozaki.yaml | 2 - website/src/showcase/website/ozaki/ozaki.yaml | 6 + website/src/showcase/website/seb.yaml | 8 +- 13 files changed, 160 insertions(+), 115 deletions(-) delete mode 100644 website/src/components/Showcase.js create mode 100644 website/src/showcase/website/dino.yaml delete mode 100644 website/src/showcase/website/ozaki.yaml create mode 100644 website/src/showcase/website/ozaki/ozaki.yaml diff --git a/packages/docusaurus-plugin-showcase/src/index.ts b/packages/docusaurus-plugin-showcase/src/index.ts index c6819a23f6..f66a49d297 100644 --- a/packages/docusaurus-plugin-showcase/src/index.ts +++ b/packages/docusaurus-plugin-showcase/src/index.ts @@ -36,28 +36,33 @@ export default function pluginContentShowcase( // }, async loadContent(): Promise { - const files = await fs.readdir( - path.join(siteDir, options.path, 'website'), - ); + const files = await fs.readdir(path.join(siteDir, options.path)); const yamlFiles = files.filter((file) => file.endsWith('.yaml')); const contentPromises = yamlFiles.map(async (file) => { - const yaml = await fs.readFile( - path.join(siteDir, options.path, 'website', file), + const rawYaml = await fs.readFile( + path.join(siteDir, options.path, file), 'utf-8', ); - const authors = Yaml.load(yaml); - const parsedAuthors = contentAuthorsSchema.validate(authors); + const yaml = Yaml.load(rawYaml); + const parsedYaml = contentAuthorsSchema.validate(yaml); - if (parsedAuthors.error) { - throw new Error(`Validation failed: ${parsedAuthors.error.message}`, { - cause: parsedAuthors.error, + if (parsedYaml.error) { + throw new Error(`Validation failed: ${parsedYaml.error.message}`, { + cause: parsedYaml.error, }); } + const {title, description, preview, website, source, tags} = + parsedYaml.value; + return { - title: parsedAuthors.value.title, - author: parsedAuthors.value.author, // Assuming author is part of Content type + title, + description, + preview, + website, + source, + tags, }; }); @@ -71,7 +76,6 @@ export default function pluginContentShowcase( if (!content) { return; } - console.log('content:', content); const {addRoute, createData} = actions; @@ -83,7 +87,7 @@ export default function pluginContentShowcase( ); addRoute({ - path: `/${item.title}`, + path: `/showcaseAll/${item.title}`, component: '@theme/Showcase', modules: { content: dataAuthor, @@ -92,6 +96,20 @@ export default function pluginContentShowcase( }); }), ); + + const showcaseAllData = await createData( + 'showcaseAll.json', + JSON.stringify(content.website), + ); + + addRoute({ + path: '/showcaseAll', + component: '@theme/Showcase', + modules: { + content: showcaseAllData, + }, + exact: true, + }); }, }; } diff --git a/packages/docusaurus-plugin-showcase/src/options.ts b/packages/docusaurus-plugin-showcase/src/options.ts index 032017c157..87588d50a7 100644 --- a/packages/docusaurus-plugin-showcase/src/options.ts +++ b/packages/docusaurus-plugin-showcase/src/options.ts @@ -11,7 +11,7 @@ import type {PluginOptions, Options} from '@docusaurus/plugin-showcase'; export const DEFAULT_OPTIONS: PluginOptions = { id: 'showcase', - path: 'src/showcase', // Path to data on filesystem, relative to site dir. + path: 'src/showcase/website', // Path to data on filesystem, relative to site dir. routeBasePath: '/', // URL Route. }; @@ -21,8 +21,12 @@ const PluginOptionSchema = Joi.object({ }); export const contentAuthorsSchema = Joi.object({ - author: Joi.string().required(), title: Joi.string().required(), + description: Joi.string().required(), + preview: Joi.string().required(), + website: Joi.string().required(), + source: Joi.string().required(), + tags: Joi.array().items(Joi.string()).required(), }); export function validateOptions({ diff --git a/packages/docusaurus-plugin-showcase/src/plugin-showcase.d.ts b/packages/docusaurus-plugin-showcase/src/plugin-showcase.d.ts index 7080908fba..f71d6c9f06 100644 --- a/packages/docusaurus-plugin-showcase/src/plugin-showcase.d.ts +++ b/packages/docusaurus-plugin-showcase/src/plugin-showcase.d.ts @@ -18,10 +18,26 @@ declare module '@docusaurus/plugin-showcase' { routeBasePath: string; }; + export type TagType = + | 'favorite' + | 'opensource' + | 'product' + | 'design' + | 'i18n' + | 'versioning' + | 'large' + | 'meta' + | 'personal' + | 'rtl'; + export type Content = { website: { - author: string; title: string; + description: string; + preview: string | null; // null = use our serverless screenshot service + website: string; + source: string | null; + tags: TagType[]; }[]; }; @@ -30,5 +46,5 @@ declare module '@docusaurus/plugin-showcase' { export default function pluginShowcase( context: LoadContext, options: PluginOptions, - ): Promise>; + ): Promise>; } diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 79f0082125..05d8caf873 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -26,6 +26,7 @@ "@docusaurus/plugin-content-blog": "3.0.0", "@docusaurus/plugin-content-docs": "3.0.0", "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/plugin-showcase": "3.0.0", "@docusaurus/theme-common": "3.0.0", "@docusaurus/theme-translations": "3.0.0", "@docusaurus/types": "3.0.0", diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 8c1af1e55b..446970b74f 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -248,14 +248,16 @@ declare module '@theme/BlogPostItems' { } declare module '@theme/Showcase' { - export interface Props { - content: { - [key: string]: string; - }; - } + import type {Content} from '@docusaurus/plugin-showcase'; export function prepareUserState(): UserState | undefined; + export type User = Content['website'][number]; + + export type Props = { + content: User[]; + }; + export default function Showcase(props: Props): JSX.Element; } diff --git a/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseFilterToggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseFilterToggle/index.tsx index 55c1cc3d52..d65e0a41d2 100644 --- a/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseFilterToggle/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseFilterToggle/index.tsx @@ -9,12 +9,28 @@ import React, {useState, useEffect, useCallback} from 'react'; import clsx from 'clsx'; import {useHistory, useLocation} from '@docusaurus/router'; +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import type {Operator} from '@theme/Showcase/ShowcaseFilterToggle'; import {OperatorQueryKey} from '@theme/Showcase/ShowcaseFilterToggle'; -import {prepareUserState} from '@theme/Showcase'; import styles from './styles.module.css'; +type UserState = { + scrollTopPosition: number; + focusedElementId: string | undefined; +}; + +function prepareUserState(): UserState | undefined { + if (ExecutionEnvironment.canUseDOM) { + return { + scrollTopPosition: window.scrollY, + focusedElementId: document.activeElement?.id, + }; + } + + return undefined; +} + function readOperator(search: string): Operator { return (new URLSearchParams(search).get(OperatorQueryKey) ?? 'OR') as Operator; diff --git a/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseTagSelect/index.tsx b/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseTagSelect/index.tsx index aa73e9c537..3219a051b7 100644 --- a/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseTagSelect/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Showcase/ShowcaseTagSelect/index.tsx @@ -15,9 +15,25 @@ import React, { } from 'react'; import {useHistory, useLocation} from '@docusaurus/router'; -import {prepareUserState} from '@theme/Showcase'; +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import styles from './styles.module.css'; +type UserState = { + scrollTopPosition: number; + focusedElementId: string | undefined; +}; + +function prepareUserState(): UserState | undefined { + if (ExecutionEnvironment.canUseDOM) { + return { + scrollTopPosition: window.scrollY, + focusedElementId: document.activeElement?.id, + }; + } + + return undefined; +} + function toggleListItem(list: T[], item: T): T[] { const itemIndex = list.indexOf(item); if (itemIndex === -1) { diff --git a/packages/docusaurus-theme-classic/src/theme/Showcase/index.tsx b/packages/docusaurus-theme-classic/src/theme/Showcase/index.tsx index d4fc93f365..61bd474edc 100644 --- a/packages/docusaurus-theme-classic/src/theme/Showcase/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Showcase/index.tsx @@ -12,27 +12,32 @@ import {useHistory, useLocation} from 'react-router-dom'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import Translate, {translate} from '@docusaurus/Translate'; import {usePluralForm} from '@docusaurus/theme-common'; -import type {Props} from '@theme/Showcase'; +import type {User, Props} from '@theme/Showcase'; import Layout from '@theme/Layout'; import Heading from '@theme/Heading'; import FavoriteIcon from '@theme/Showcase/FavoriteIcon'; import ShowcaseCard from '@theme/Showcase/ShowcaseCard'; import ShowcaseTooltip from '@theme/Showcase/ShowcaseTooltip'; -import ShowcaseTagSelect, { - readSearchTags, -} from '@theme/Showcase/ShowcaseTagSelect'; -import ShowcaseFilterToggle, { - readOperator, -} from '@theme/Showcase/ShowcaseFilterToggle'; +import ShowcaseTagSelect from '@theme/Showcase/ShowcaseTagSelect'; +import ShowcaseFilterToggle from '@theme/Showcase/ShowcaseFilterToggle'; import type {Operator} from '@theme/Showcase/ShowcaseFilterToggle'; +import type {TagType} from '@docusaurus/plugin-showcase'; import styles from './styles.module.css'; +type Users = User[]; + const TITLE = translate({message: 'Docusaurus Site Showcase'}); const DESCRIPTION = translate({ message: 'List of websites people are building with Docusaurus', }); const SUBMIT_URL = 'https://github.com/facebook/docusaurus/discussions/7826'; +const OperatorQueryKey = 'operator'; + +function readOperator(search: string): Operator { + return (new URLSearchParams(search).get(OperatorQueryKey) ?? + 'OR') as Operator; +} type UserState = { scrollTopPosition: number; focusedElementId: string | undefined; @@ -145,17 +150,6 @@ const Tags: {[type in TagType]: Tag} = { const TagList = Object.keys(Tags) as TagType[]; -const Users: User[] = [ - { - title: 'AgileTs', - description: 'Global State and Logic Framework for reactive Applications', - preview: 'https://github.com/ozakione.png', - website: 'https://agile-ts.org/', - source: 'https://github.com/agile-ts/documentation', - tags: ['opensource', 'design'], - }, -]; - function sortBy( array: T[], getter: (item: T) => string | number | boolean, @@ -168,17 +162,14 @@ function sortBy( return sortedArray; } -function sortUsers() { - let result = Users; +function sortUsers(users: Users): Users { // Sort by site name - result = sortBy(result, (user) => user.title.toLowerCase()); + let result = sortBy(users, (user) => user.title.toLowerCase()); // Sort by favorite tag, favorites first - result = sortBy(result, (user) => !user.tags.includes('favorite')); + result = sortBy(result, (user) => (user.tags.includes('favorite') ? -1 : 1)); return result; } -const sortedUsers = sortUsers(); - function ShowcaseHeader() { return (
@@ -213,35 +204,9 @@ function restoreUserState(userState: UserState | null) { document.getElementById(focusedElementId)?.focus(); window.scrollTo({top: scrollTopPosition}); } -type TagType = - | 'favorite' - | 'opensource' - | 'product' - | 'design' - | 'i18n' - | 'versioning' - | 'large' - | 'meta' - | 'personal' - | 'rtl'; - -type User = { - title: string; - description: string; - preview: string | null; // null = use our serverless screenshot service - website: string; - source: string | null; - tags: TagType[]; -}; - -// type Tag = { -// label: string; -// description: string; -// color: string; -// }; function filterUsers( - users: User[], + users: Users, selectedTags: TagType[], operator: Operator, searchName: string | null, @@ -266,7 +231,19 @@ function filterUsers( }); } -function useFilteredUsers() { +const SearchNameQueryKey = 'name'; + +function readSearchName(search: string) { + return new URLSearchParams(search).get(SearchNameQueryKey); +} + +const TagQueryStringKey = 'tags'; + +function readSearchTags(search: string): TagType[] { + return new URLSearchParams(search).getAll(TagQueryStringKey) as TagType[]; +} + +function useFilteredUsers(users: Users) { const location = useLocation(); const [operator, setOperator] = useState('OR'); // On SSR / first mount (hydration) no tag is selected @@ -282,8 +259,8 @@ function useFilteredUsers() { }, [location]); return useMemo( - () => filterUsers(sortedUsers, selectedTags, operator, searchName), - [selectedTags, operator, searchName], + () => filterUsers(sortUsers(users), selectedTags, operator, searchName), + [selectedTags, operator, searchName, users], ); } @@ -304,8 +281,8 @@ function useSiteCountPlural() { ); } -function ShowcaseFilters() { - const filteredUsers = useFilteredUsers(); +function ShowcaseFilters({users}: {users: Users}) { + const filteredUsers = useFilteredUsers(users); const siteCountPlural = useSiteCountPlural(); return (
@@ -358,12 +335,6 @@ function ShowcaseFilters() { ); } -const SearchNameQueryKey = 'name'; - -function readSearchName(search: string) { - return new URLSearchParams(search).get(SearchNameQueryKey); -} - function SearchBar() { const history = useHistory(); const location = useLocation(); @@ -401,15 +372,8 @@ function SearchBar() { ); } -const favoriteUsers = sortedUsers.filter((user) => - user.tags.includes('favorite'), -); -const otherUsers = sortedUsers.filter( - (user) => !user.tags.includes('favorite'), -); - -function ShowcaseCards() { - const filteredUsers = useFilteredUsers(); +function ShowcaseCards({users}: {users: Users}) { + const filteredUsers = useFilteredUsers(users); if (filteredUsers.length === 0) { return ( @@ -423,9 +387,12 @@ function ShowcaseCards() { ); } + const favoriteUsers = users.filter((user) => user.tags.includes('favorite')); + const otherUsers = users.filter((user) => !user.tags.includes('favorite')); + return (
- {filteredUsers.length === sortedUsers.length ? ( + {filteredUsers.length === sortUsers(users).length ? ( <>
@@ -481,18 +448,21 @@ function ShowcaseCards() { } export default function Showcase(props: Props): JSX.Element { + // TODO remove temporary to test showcase specific page + const users = Array.isArray(props.content) ? props.content : [props.content]; + return (
{JSON.stringify(props)}
- +
- +
); diff --git a/website/src/components/Showcase.js b/website/src/components/Showcase.js deleted file mode 100644 index 1db5612879..0000000000 --- a/website/src/components/Showcase.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/* eslint-disable @docusaurus/no-untranslated-text */ -import React from 'react'; - -export default function ShowcaseComponent(props) { - return
Your friends are : {props.content.author}
; -} diff --git a/website/src/showcase/website/dino.yaml b/website/src/showcase/website/dino.yaml new file mode 100644 index 0000000000..a0cf44b03b --- /dev/null +++ b/website/src/showcase/website/dino.yaml @@ -0,0 +1,6 @@ +title: 'Dinosaur' +description: 'Docusaurus dino' +preview: require('./showcase/agilets.png') +website: 'https://agile-ts.org/' +source: 'https://github.com/agile-ts/documentation' +tags: ['opensource', 'design'] diff --git a/website/src/showcase/website/ozaki.yaml b/website/src/showcase/website/ozaki.yaml deleted file mode 100644 index 77fa759f37..0000000000 --- a/website/src/showcase/website/ozaki.yaml +++ /dev/null @@ -1,2 +0,0 @@ -author: ozaki -title: ozaki diff --git a/website/src/showcase/website/ozaki/ozaki.yaml b/website/src/showcase/website/ozaki/ozaki.yaml new file mode 100644 index 0000000000..c7f70ca01b --- /dev/null +++ b/website/src/showcase/website/ozaki/ozaki.yaml @@ -0,0 +1,6 @@ +title: 'Ozaki' +description: 'Ozaki website' +preview: require('./showcase/agilets.png') +website: 'https://agile-ts.org/' +source: 'https://github.com/agile-ts/documentation' +tags: ['opensource', 'design'] diff --git a/website/src/showcase/website/seb.yaml b/website/src/showcase/website/seb.yaml index b85f96883c..6ac2b6be34 100644 --- a/website/src/showcase/website/seb.yaml +++ b/website/src/showcase/website/seb.yaml @@ -1,2 +1,6 @@ -author: seb -title: seb +title: 'Seb' +description: "Docusaurus maintainer's personal website" +preview: require('./showcase/agilets.png') +website: 'https://agile-ts.org/' +source: 'https://github.com/agile-ts/documentation' +tags: ['opensource', 'design']