Skip to content

Commit a19e525

Browse files
committed
feat(docs): add plugin store
users can submit plugins and/or view plugins made by the community
1 parent 3910793 commit a19e525

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1418
-54
lines changed

apps/docs/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DISCORD_CLIENT_ID=<CLIENT ID>
2+
DISCORD_CLIENT_SECRET=<CLIENT SECRET>
3+
DATABASE_URL=<MONGODB DATABASE>
4+
NEXTAUTH_SECRET=<NEXTAUTH SECRET TOKEN>

apps/docs/next.config.js renamed to apps/docs/next.config.mjs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
1-
const withNextra = require('nextra')({
1+
import nextra from 'nextra';
2+
3+
const withNextra = nextra({
24
theme: 'nextra-theme-docs',
35
themeConfig: './theme.config.js',
46
unstable_flexsearch: true,
57
unstable_staticImage: true,
68
});
79

10+
/**
11+
* @type {import('next').Config}
12+
*/
813
const nextConfig = withNextra({
914
reactStrictMode: true,
1015
experimental: {
1116
legacyBrowsers: false,
17+
topLevelAwait: true,
18+
},
19+
images: {
20+
remotePatterns: [
21+
{
22+
protocol: 'https',
23+
hostname: 'cdn.discordapp.com',
24+
},
25+
],
1226
},
1327
async redirects() {
1428
return [
@@ -21,4 +35,4 @@ const nextConfig = withNextra({
2135
},
2236
});
2337

24-
module.exports = nextConfig;
38+
export default nextConfig;

apps/docs/package.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,31 @@
1313
"license": "MIT",
1414
"dependencies": {
1515
"@heroicons/react": "1.0.6",
16+
"@hookform/resolvers": "^2.9.10",
17+
"@prisma/client": "^4.7.1",
1618
"@react-aria/ssr": "3.3.0",
19+
"@tanstack/react-query": "^4.20.4",
20+
"@trpc/client": "^10.6.0",
21+
"@trpc/next": "^10.6.0",
22+
"@trpc/react-query": "^10.6.0",
23+
"@trpc/server": "^10.6.0",
1724
"copy-to-clipboard": "3.3.2",
1825
"next": "12.3.1",
26+
"next-auth": "^4.18.6",
27+
"next-mdx-remote": "^4.2.0",
1928
"nextra": "2.0.0-beta.32",
2029
"nextra-theme-docs": "2.0.0-beta.28",
2130
"react": "17.0.2",
2231
"react-dom": "17.0.2",
32+
"react-hook-form": "^7.41.0",
2333
"react-hot-toast": "2.4.0",
24-
"swr": "1.3.0"
34+
"rehype-add-classes": "^1.0.0",
35+
"rehype-pretty-code": "^0.6.0",
36+
"remark-gfm": "^3.0.1",
37+
"shiki": "^0.12.1",
38+
"superjson": "^1.12.1",
39+
"swr": "1.3.0",
40+
"zod": "^3.20.2"
2541
},
2642
"devDependencies": {
2743
"@babel/core": "7.19.3",
@@ -34,6 +50,7 @@
3450
"eslint-config-prettier": "8.5.0",
3551
"gray-matter": "4.0.3",
3652
"postcss": "8.4.18",
53+
"prisma": "^4.7.1",
3754
"tailwindcss": "3.1.8",
3855
"typescript": "4.8.4"
3956
},

apps/docs/prisma/schema.prisma

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// This is your Prisma schema file,
2+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
3+
4+
generator client {
5+
provider = "prisma-client-js"
6+
}
7+
8+
datasource db {
9+
provider = "mongodb"
10+
url = env("DATABASE_URL")
11+
}
12+
13+
model Plugin {
14+
id String @id @default(auto()) @map("_id") @db.ObjectId
15+
name String
16+
description String?
17+
author Author
18+
createdAt DateTime @default(now())
19+
}
20+
21+
type Author {
22+
name String
23+
image String
24+
}

apps/docs/src/components/Callout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export default function Callout({
3535
icon,
3636
}: {
3737
children: ReactNode;
38-
type: keyof typeof THEMES;
39-
icon: ReactElement;
38+
type?: keyof typeof THEMES;
39+
icon?: ReactElement;
4040
}) {
4141
return (
4242
<div className={`${THEMES[type].classes} flex rounded-lg callout mt-6`}>

apps/docs/src/components/Container.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ReactNode } from 'react';
1+
import { ReactNode } from 'react';
22

33
type Props = {
44
children?: ReactNode;

apps/docs/src/components/Feature.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import Link from 'next/link';
2-
import type { Feature as Feat } from '~/content/features';
2+
import { Feature as Feat } from '~/content/features';
33

44
type FeatureProps = {
55
feature: Omit<Feat, 'page'>;
66
detailed?: boolean;
77
};
88

9-
const DetailedFeatureInner = (props: { feature: FeatureProps['feature'] }) => {
9+
const DetailedFeatureInner = (props: { feature: FeatureProps['feature']; }) => {
1010
const { Icon, name, description } = props.feature;
1111
return (
1212
<>
@@ -41,11 +41,11 @@ export const DetailedFeatureLink = (props: {
4141
href: string;
4242
feature: FeatureProps['feature'];
4343
}) => (
44-
<Link href={props.href}>
45-
<a className={featureWrapperClasses}>
46-
<DetailedFeatureInner feature={props.feature}></DetailedFeatureInner>
47-
</a>
48-
</Link>
44+
<Link href={props.href}>
45+
<a className={featureWrapperClasses}>
46+
<DetailedFeatureInner feature={props.feature}></DetailedFeatureInner>
47+
</a>
48+
</Link>
4949
);
5050

5151
export default function Feature(props: FeatureProps) {

apps/docs/src/components/Features.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import React from 'react';
1+
import { ReactNode } from 'react';
22
import { DOCS_FEATURES, HOME_FEATURES } from '~/content/features';
33
import Feature from './Feature';
44

55
export function DetailedFeaturesGrid({
66
children,
77
}: {
8-
children?: React.ReactNode;
8+
children?: ReactNode;
99
}) {
1010
return (
1111
<div className="grid grid-cols-1 mt-12 gap-x-6 gap-y-12 sm:grid-cols-2 lg:mt-16 lg:grid-cols-3 lg:gap-x-8 lg:gap-y-12">
@@ -30,7 +30,7 @@ export function HomeFeatures() {
3030

3131
export function DocsFeatures({ detailed = true }: { detailed?: boolean; }) {
3232
return (
33-
<div className="grid grid-cols-2 gap-6 my-12 sm:grid-cols-3 ">
33+
<div className="grid grid-cols-2 gap-6 my-12 sm:grid-cols-3">
3434
{DOCS_FEATURES.map((feature) => (
3535
<Feature
3636
key={feature.name.split(' ').join('-')}

apps/docs/src/components/Footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export function Footer() {
77
Footer
88
</h2>
99
<div className="md:flex md:items-center md:justify-between">
10-
<p className="text-xs text-gray-500 ">
10+
<p className="text-xs text-gray-500">
1111
<SparkLogo height={48} />
1212
&copy; {new Date().getFullYear()} Spark. All rights reserved.
1313
</p>

apps/docs/src/components/Plugin.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import Image from 'next/image';
2+
import Link from 'next/link';
3+
import Callout from './Callout';
4+
import { trpc } from '~/utils/trpc';
5+
6+
interface Author {
7+
name: string;
8+
image: string;
9+
}
10+
11+
interface PluginProps {
12+
name: string;
13+
id: string;
14+
author: Author;
15+
}
16+
17+
export function PluginCard({ plugin }: { plugin: PluginProps; }) {
18+
return (
19+
<a href={`/plugins/${plugin.id}`} className="relative block overflow-hidden p-10 bg-white shadow-lg rounded-xl dark:bg-opacity-5 no-underline text-black dark:text-white">
20+
<h3 className="m-0 text-lg font-semibold leading-6 tracking-tight text-gray-900 dark:text-white">
21+
{plugin.name}
22+
</h3>
23+
<div className="text-base font-medium text-gray-400 dark:text-gray-500 flex items-center mt-2">
24+
<div className="w-8 h-8 mr-2">
25+
<Image className="rounded-full"
26+
src={plugin.author.image}
27+
height={128}
28+
width={128}
29+
objectFit="cover"
30+
/>
31+
</div>
32+
{plugin.author.name}
33+
</div>
34+
<style jsx global>{`
35+
html.dark .icon-circle {
36+
background: linear-gradient(180deg, rgba(50, 134, 241, 0.2) 0%, rgba(195, 58, 195, 0.2) 100%);
37+
}
38+
`}</style>
39+
</a>
40+
);
41+
}
42+
43+
export function PluginShowcase() {
44+
const { data: plugins, status } = trpc.plugins.findAll.useQuery();
45+
46+
if (status === 'error') {
47+
return (
48+
<Callout type="error">An error occured. Please refresh and try again.</Callout>
49+
);
50+
}
51+
52+
if (status === 'loading') {
53+
return (
54+
<div className="flex items-center justify-center">
55+
<div style={{ borderTopColor: 'transparent' }} className="w-8 h-8 border-4 border-gray-400 rounded-full animate-spin" />
56+
<h1 className="ml-2 font-extrabold text-lg">Loading Plugins...</h1>
57+
</div>
58+
);
59+
}
60+
61+
const sortedPlugins = plugins.sort(
62+
(a, b) => a.createdAt.getMilliseconds() - b.createdAt.getMilliseconds(),
63+
);
64+
65+
return (
66+
<>
67+
<Link href="/plugins/new">
68+
<a className="flex items-center justify-center w-full px-8 py-3 text-base font-medium text-white no-underline bg-black border border-transparent rounded-md dark:bg-white dark:text-black betterhover:dark:hover:bg-gray-300 betterhover:hover:bg-gray-700 md:py-3 md:text-lg md:px-10 md:leading-6 mt-6">
69+
Submit Plugin →
70+
</a>
71+
</Link>
72+
<div className="grid grid-cols-1 mt-12 gap-x-6 gap-y-12 sm:grid-cols-2 lg:mt-16 lg:gap-x-8 lg:gap-y-12">
73+
{sortedPlugins.map((plugin: PluginProps) => (
74+
<PluginCard plugin={plugin} key={plugin.id} />
75+
))}
76+
</div>
77+
</>
78+
);
79+
}

0 commit comments

Comments
 (0)