mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 10:48:05 +02:00
screenshot api
This commit is contained in:
parent
510539fc96
commit
c8b7e6d5df
8 changed files with 108 additions and 32 deletions
|
@ -31,7 +31,15 @@ export default async function pluginContentShowcase(
|
||||||
): Promise<Plugin<ShowcaseItems>> {
|
): Promise<Plugin<ShowcaseItems>> {
|
||||||
const {siteDir, localizationDir} = context;
|
const {siteDir, localizationDir} = context;
|
||||||
// todo check for better naming of path: sitePath
|
// todo check for better naming of path: sitePath
|
||||||
const {include, exclude, tags, routeBasePath, path: sitePath, id} = options;
|
const {
|
||||||
|
include,
|
||||||
|
exclude,
|
||||||
|
tags,
|
||||||
|
routeBasePath,
|
||||||
|
path: sitePath,
|
||||||
|
id,
|
||||||
|
screenshotApi,
|
||||||
|
} = options;
|
||||||
|
|
||||||
const contentPaths: ShowcaseContentPaths = {
|
const contentPaths: ShowcaseContentPaths = {
|
||||||
contentPath: path.resolve(siteDir, sitePath),
|
contentPath: path.resolve(siteDir, sitePath),
|
||||||
|
@ -81,6 +89,7 @@ export default async function pluginContentShowcase(
|
||||||
await processContentLoaded({
|
await processContentLoaded({
|
||||||
content,
|
content,
|
||||||
tags: validatedTags,
|
tags: validatedTags,
|
||||||
|
screenshotApi,
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
addRoute,
|
addRoute,
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,11 +15,13 @@ export async function processContentLoaded({
|
||||||
content,
|
content,
|
||||||
tags,
|
tags,
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
|
screenshotApi,
|
||||||
addRoute,
|
addRoute,
|
||||||
}: {
|
}: {
|
||||||
content: ShowcaseItems;
|
content: ShowcaseItems;
|
||||||
routeBasePath: string;
|
routeBasePath: string;
|
||||||
tags: TagsOption;
|
tags: TagsOption;
|
||||||
|
screenshotApi: string;
|
||||||
addRoute: PluginContentLoadedActions['addRoute'];
|
addRoute: PluginContentLoadedActions['addRoute'];
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
addRoute({
|
addRoute({
|
||||||
|
@ -28,6 +30,7 @@ export async function processContentLoaded({
|
||||||
props: {
|
props: {
|
||||||
items: content.items,
|
items: content.items,
|
||||||
tags,
|
tags,
|
||||||
|
screenshotApi,
|
||||||
},
|
},
|
||||||
exact: true,
|
exact: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -256,6 +256,7 @@ declare module '@theme/Showcase' {
|
||||||
export type Props = {
|
export type Props = {
|
||||||
items: ShowcaseItem[];
|
items: ShowcaseItem[];
|
||||||
tags: TagsOption;
|
tags: TagsOption;
|
||||||
|
screenshotApi: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Showcase(props: Props): JSX.Element;
|
export default function Showcase(props: Props): JSX.Element;
|
||||||
|
|
|
@ -10,7 +10,10 @@ import clsx from 'clsx';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate from '@docusaurus/Translate';
|
||||||
import {sortBy} from '@docusaurus/plugin-content-showcase/client';
|
import {sortBy} from '@docusaurus/plugin-content-showcase/client';
|
||||||
import {useShowcaseTags} from '@docusaurus/theme-common/internal';
|
import {
|
||||||
|
useShowcaseTags,
|
||||||
|
useShowcaseApiScreenshot,
|
||||||
|
} from '@docusaurus/theme-common/internal';
|
||||||
import Heading from '@theme/Heading';
|
import Heading from '@theme/Heading';
|
||||||
import FavoriteIcon from '@theme/Showcase/FavoriteIcon';
|
import FavoriteIcon from '@theme/Showcase/FavoriteIcon';
|
||||||
import type {ShowcaseItem, TagType} from '@docusaurus/plugin-content-showcase';
|
import type {ShowcaseItem, TagType} from '@docusaurus/plugin-content-showcase';
|
||||||
|
@ -36,6 +39,7 @@ function TagItem({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move tag reorder logic into hook
|
||||||
function ShowcaseCardTag({tags}: {tags: TagType[]}) {
|
function ShowcaseCardTag({tags}: {tags: TagType[]}) {
|
||||||
const Tags = useShowcaseTags();
|
const Tags = useShowcaseTags();
|
||||||
const TagList = Object.keys(Tags) as TagType[];
|
const TagList = Object.keys(Tags) as TagType[];
|
||||||
|
@ -56,18 +60,13 @@ function ShowcaseCardTag({tags}: {tags: TagType[]}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCardImage(item: ShowcaseItem): string {
|
function getCardImage(item: ShowcaseItem, api: string): string {
|
||||||
return (
|
return item.preview ?? `${api}/${encodeURIComponent(item.website)}/showcase`;
|
||||||
item.preview ??
|
|
||||||
// TODO make it configurable
|
|
||||||
`https://slorber-api-screenshot.netlify.app/${encodeURIComponent(
|
|
||||||
item.website,
|
|
||||||
)}/showcase`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowcaseCard({item}: {item: ShowcaseItem}) {
|
function ShowcaseCard({item}: {item: ShowcaseItem}) {
|
||||||
const image = getCardImage(item);
|
const api = useShowcaseApiScreenshot();
|
||||||
|
const image = getCardImage(item, api);
|
||||||
return (
|
return (
|
||||||
<li key={item.title} className="card shadow--md">
|
<li key={item.title} className="card shadow--md">
|
||||||
<div className={clsx('card__image', styles.showcaseCardImage)}>
|
<div className={clsx('card__image', styles.showcaseCardImage)}>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import Translate, {translate} from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import {TagsProvider, ItemsProvider} from '@docusaurus/theme-common/internal';
|
import {ShowcaseProvider} from '@docusaurus/theme-common/internal';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
import Heading from '@theme/Heading';
|
import Heading from '@theme/Heading';
|
||||||
import ShowcaseSearchBar from '@theme/Showcase/ShowcaseSearchBar';
|
import ShowcaseSearchBar from '@theme/Showcase/ShowcaseSearchBar';
|
||||||
|
@ -37,21 +37,22 @@ function ShowcaseHeader() {
|
||||||
|
|
||||||
export default function Showcase(props: Props): JSX.Element {
|
export default function Showcase(props: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<ItemsProvider items={props.items}>
|
<ShowcaseProvider
|
||||||
<TagsProvider tags={props.tags}>
|
items={props.items}
|
||||||
<Layout title={TITLE} description={DESCRIPTION}>
|
tags={props.tags}
|
||||||
<main className="margin-vert--lg">
|
screenshotApi={props.screenshotApi}>
|
||||||
<ShowcaseHeader />
|
<Layout title={TITLE} description={DESCRIPTION}>
|
||||||
<ShowcaseFilters />
|
<main className="margin-vert--lg">
|
||||||
<div
|
<ShowcaseHeader />
|
||||||
style={{display: 'flex', marginLeft: 'auto'}}
|
<ShowcaseFilters />
|
||||||
className="container">
|
<div
|
||||||
<ShowcaseSearchBar />
|
style={{display: 'flex', marginLeft: 'auto'}}
|
||||||
</div>
|
className="container">
|
||||||
<ShowcaseCards />
|
<ShowcaseSearchBar />
|
||||||
</main>
|
</div>
|
||||||
</Layout>
|
<ShowcaseCards />
|
||||||
</TagsProvider>
|
</main>
|
||||||
</ItemsProvider>
|
</Layout>
|
||||||
|
</ShowcaseProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,31 @@ import type {
|
||||||
TagsOption,
|
TagsOption,
|
||||||
} from '@docusaurus/plugin-content-showcase';
|
} from '@docusaurus/plugin-content-showcase';
|
||||||
|
|
||||||
|
// duplicated from theme classic showcase
|
||||||
|
type Props = {
|
||||||
|
items: ShowcaseItem[];
|
||||||
|
tags: TagsOption;
|
||||||
|
screenshotApi: string;
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
const ItemsContext = React.createContext<ShowcaseItem[] | null>(null);
|
const ItemsContext = React.createContext<ShowcaseItem[] | null>(null);
|
||||||
|
const ApiContext = React.createContext<string | null>(null);
|
||||||
const TagsContext = React.createContext<TagsOption | null>(null);
|
const TagsContext = React.createContext<TagsOption | null>(null);
|
||||||
|
|
||||||
function useItemsContextValue(content: ShowcaseItem[]): ShowcaseItem[] {
|
function useItemsContextValue(content: ShowcaseItem[]): ShowcaseItem[] {
|
||||||
return useMemo(() => content, [content]);
|
return useMemo(() => content, [content]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useApiScreenshotContextValue(content: string): string {
|
||||||
|
return useMemo(() => content, [content]);
|
||||||
|
}
|
||||||
|
|
||||||
function useTagsContextValue(tags: TagsOption): TagsOption {
|
function useTagsContextValue(tags: TagsOption): TagsOption {
|
||||||
return useMemo(() => tags, [tags]);
|
return useMemo(() => tags, [tags]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ItemsProvider({
|
function ItemsProvider({
|
||||||
children,
|
children,
|
||||||
items,
|
items,
|
||||||
}: {
|
}: {
|
||||||
|
@ -38,7 +51,20 @@ export function ItemsProvider({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TagsProvider({
|
function ApiScreenshotProvider({
|
||||||
|
children,
|
||||||
|
api,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
api: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
const contextValue = useApiScreenshotContextValue(api);
|
||||||
|
return (
|
||||||
|
<ApiContext.Provider value={contextValue}>{children}</ApiContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TagsProvider({
|
||||||
children,
|
children,
|
||||||
tags,
|
tags,
|
||||||
}: {
|
}: {
|
||||||
|
@ -51,6 +77,23 @@ export function TagsProvider({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ShowcaseProvider({
|
||||||
|
items,
|
||||||
|
tags,
|
||||||
|
screenshotApi,
|
||||||
|
children,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
return (
|
||||||
|
<ItemsProvider items={items}>
|
||||||
|
<TagsProvider tags={tags}>
|
||||||
|
<ApiScreenshotProvider api={screenshotApi}>
|
||||||
|
{children}
|
||||||
|
</ApiScreenshotProvider>
|
||||||
|
</TagsProvider>
|
||||||
|
</ItemsProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function useShowcaseItems(): ShowcaseItem[] {
|
export function useShowcaseItems(): ShowcaseItem[] {
|
||||||
const showcaseItems = useContext(ItemsContext);
|
const showcaseItems = useContext(ItemsContext);
|
||||||
if (showcaseItems === null) {
|
if (showcaseItems === null) {
|
||||||
|
@ -59,6 +102,14 @@ export function useShowcaseItems(): ShowcaseItem[] {
|
||||||
return showcaseItems;
|
return showcaseItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useShowcaseApiScreenshot(): string {
|
||||||
|
const showcaseItems = useContext(ApiContext);
|
||||||
|
if (showcaseItems === null) {
|
||||||
|
throw new ReactContextError('ItemsProvider');
|
||||||
|
}
|
||||||
|
return showcaseItems;
|
||||||
|
}
|
||||||
|
|
||||||
export function useShowcaseTags(): TagsOption {
|
export function useShowcaseTags(): TagsOption {
|
||||||
const tags = useContext(TagsContext);
|
const tags = useContext(TagsContext);
|
||||||
if (tags === null) {
|
if (tags === null) {
|
||||||
|
|
|
@ -27,10 +27,10 @@ export {DocsSidebarProvider, useDocsSidebar} from './contexts/docsSidebar';
|
||||||
|
|
||||||
export {DocProvider, useDoc, type DocContextValue} from './contexts/doc';
|
export {DocProvider, useDoc, type DocContextValue} from './contexts/doc';
|
||||||
export {
|
export {
|
||||||
ItemsProvider,
|
|
||||||
TagsProvider,
|
|
||||||
useShowcaseItems,
|
useShowcaseItems,
|
||||||
useShowcaseTags,
|
useShowcaseTags,
|
||||||
|
useShowcaseApiScreenshot,
|
||||||
|
ShowcaseProvider,
|
||||||
} from './contexts/showcase';
|
} from './contexts/showcase';
|
||||||
export {
|
export {
|
||||||
BlogPostProvider,
|
BlogPostProvider,
|
||||||
|
|
12
website/showcase/tags.yml
Normal file
12
website/showcase/tags.yml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
favorite:
|
||||||
|
label: 'Favorite'
|
||||||
|
description:
|
||||||
|
message: 'Our favorite Docusaurus sites that you must absolutely check out!'
|
||||||
|
id: 'showcase.tag.favorite.description'
|
||||||
|
color: '#e9669e'
|
||||||
|
opensource:
|
||||||
|
label: 'Open Source'
|
||||||
|
description:
|
||||||
|
message: 'These sites are open source, so you can learn from them!'
|
||||||
|
id: 'showcase.tag.opensource.description'
|
||||||
|
color: '#f6993f'
|
Loading…
Add table
Reference in a new issue