diff --git a/apps/cyberstorm-storybook/stories/components/ProfilePanel.stories.tsx b/apps/cyberstorm-storybook/stories/components/ProfilePanel.stories.tsx new file mode 100644 index 000000000..6e2a5f23d --- /dev/null +++ b/apps/cyberstorm-storybook/stories/components/ProfilePanel.stories.tsx @@ -0,0 +1,41 @@ +import { StoryFn, Meta } from "@storybook/react"; +import { ProfilePanel } from "@thunderstore/cyberstorm"; +import React from "react"; + +export default { + title: "Cyberstorm/Components/ProfilePanel", + component: ProfilePanel, +} as Meta; + +const style: React.CSSProperties = { + height: "500px", +}; +const mods = [ + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { + name: "LongNamedBeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeMod", + version: "1.0.0", + url: "example.com", + }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, + { name: "TestMod1", version: "1.0.0", url: "example.com" }, +]; +const profile = { name: "Test Profile", code: "test_code", mods: mods }; + +const Template: StoryFn = (args) => ( +
+ +
+); + +const ReferenceProfilePanel = Template.bind({}); +ReferenceProfilePanel.args = { profile: profile }; + +export { ReferenceProfilePanel }; diff --git a/apps/twitch-extensions-nextjs/.eslintrc.json b/apps/twitch-extensions-nextjs/.eslintrc.json new file mode 100644 index 000000000..bffb357a7 --- /dev/null +++ b/apps/twitch-extensions-nextjs/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/apps/twitch-extensions-nextjs/.gitignore b/apps/twitch-extensions-nextjs/.gitignore new file mode 100644 index 000000000..8f322f0d8 --- /dev/null +++ b/apps/twitch-extensions-nextjs/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/apps/twitch-extensions-nextjs/README.md b/apps/twitch-extensions-nextjs/README.md new file mode 100644 index 000000000..965a1228c --- /dev/null +++ b/apps/twitch-extensions-nextjs/README.md @@ -0,0 +1,38 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/twitch-extensions-nextjs/next.config.js b/apps/twitch-extensions-nextjs/next.config.js new file mode 100644 index 000000000..c25e89557 --- /dev/null +++ b/apps/twitch-extensions-nextjs/next.config.js @@ -0,0 +1,10 @@ +const withPreconstruct = require("@preconstruct/next"); + +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + transpilePackages: ["react"], + output: "export", +}; + +module.exports = withPreconstruct(nextConfig); diff --git a/apps/twitch-extensions-nextjs/package.json b/apps/twitch-extensions-nextjs/package.json new file mode 100644 index 000000000..13eb538fc --- /dev/null +++ b/apps/twitch-extensions-nextjs/package.json @@ -0,0 +1,25 @@ +{ + "name": "@thunderstore/twitch-extensions-nextjs", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@preconstruct/next": "^4.0.0", + "@thunderstore/cyberstorm": "^0.1.0", + "@thunderstore/cyberstorm-styles": "^0.1.0", + "@types/node": "18.15.11", + "@types/react": "18.0.35", + "@types/react-dom": "18.0.11", + "eslint": "8.38.0", + "eslint-config-next": "13.3.0", + "next": "13.3.0", + "react": "18.2.0", + "react-dom": "18.2.0", + "typescript": "5.0.4" + } +} diff --git a/apps/twitch-extensions-nextjs/pages/_app.tsx b/apps/twitch-extensions-nextjs/pages/_app.tsx new file mode 100644 index 000000000..87642f5ec --- /dev/null +++ b/apps/twitch-extensions-nextjs/pages/_app.tsx @@ -0,0 +1,6 @@ +import type { AppProps } from "next/app"; +import "@thunderstore/cyberstorm-styles"; + +export default function App({ Component, pageProps }: AppProps) { + return ; +} diff --git a/apps/twitch-extensions-nextjs/pages/_document.tsx b/apps/twitch-extensions-nextjs/pages/_document.tsx new file mode 100644 index 000000000..129cdcca2 --- /dev/null +++ b/apps/twitch-extensions-nextjs/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from "next/document"; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/apps/twitch-extensions-nextjs/pages/api/hello.ts b/apps/twitch-extensions-nextjs/pages/api/hello.ts new file mode 100644 index 000000000..74a3605db --- /dev/null +++ b/apps/twitch-extensions-nextjs/pages/api/hello.ts @@ -0,0 +1,13 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; + +type Data = { + name: string; +}; + +export default function handler( + req: NextApiRequest, + res: NextApiResponse +) { + res.status(200).json({ name: "John Doe" }); +} diff --git a/apps/twitch-extensions-nextjs/pages/twitchpanel.tsx b/apps/twitch-extensions-nextjs/pages/twitchpanel.tsx new file mode 100644 index 000000000..4a1b3b5cc --- /dev/null +++ b/apps/twitch-extensions-nextjs/pages/twitchpanel.tsx @@ -0,0 +1,9 @@ +import { TwitchProfilePanelLayout } from "@thunderstore/cyberstorm"; + +export default function Communities() { + return ( +
+ +
+ ); +} diff --git a/apps/twitch-extensions-nextjs/public/favicon.ico b/apps/twitch-extensions-nextjs/public/favicon.ico new file mode 100644 index 000000000..718d6fea4 Binary files /dev/null and b/apps/twitch-extensions-nextjs/public/favicon.ico differ diff --git a/apps/twitch-extensions-nextjs/public/images/logo.png b/apps/twitch-extensions-nextjs/public/images/logo.png new file mode 100644 index 000000000..fad79748f Binary files /dev/null and b/apps/twitch-extensions-nextjs/public/images/logo.png differ diff --git a/apps/twitch-extensions-nextjs/public/next.svg b/apps/twitch-extensions-nextjs/public/next.svg new file mode 100644 index 000000000..5174b28c5 --- /dev/null +++ b/apps/twitch-extensions-nextjs/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/twitch-extensions-nextjs/public/vercel.svg b/apps/twitch-extensions-nextjs/public/vercel.svg new file mode 100644 index 000000000..d2f842227 --- /dev/null +++ b/apps/twitch-extensions-nextjs/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/twitch-extensions-nextjs/tsconfig.json b/apps/twitch-extensions-nextjs/tsconfig.json new file mode 100644 index 000000000..08528e2bf --- /dev/null +++ b/apps/twitch-extensions-nextjs/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/twitchpanel.html"], + "exclude": ["node_modules"] +} diff --git a/packages/cyberstorm/src/components/Layout/TwitchProfilePanelLayout/TwitchProfilePanelLayout.tsx b/packages/cyberstorm/src/components/Layout/TwitchProfilePanelLayout/TwitchProfilePanelLayout.tsx new file mode 100644 index 000000000..c0a1d5e8e --- /dev/null +++ b/packages/cyberstorm/src/components/Layout/TwitchProfilePanelLayout/TwitchProfilePanelLayout.tsx @@ -0,0 +1,24 @@ +import { ProfilePanel } from "../../ProfilePanel/ProfilePanel"; + +/** + * Cyberstorm TwitchPanelLayout Layout + */ +export function TwitchProfilePanelLayout() { + const profile = getProfileData(); + return ; +} + +TwitchProfilePanelLayout.displayName = "ProfilePanelLayout"; +TwitchProfilePanelLayout.defaultProps = {}; + +function getProfileData() { + return { + code: "TEST_CODE", + name: "TEST_NAME", + mods: [ + { name: "TEST_MOD_NAME_1", version: "0.0.1", url: "example.com" }, + { name: "TEST_MOD_NAME_2", version: "0.0.2", url: "example.com" }, + { name: "TEST_MOD_NAME_3", version: "0.0.3", url: "example.com" }, + ], + }; +} diff --git a/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.module.css b/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.module.css new file mode 100644 index 000000000..599582742 --- /dev/null +++ b/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.module.css @@ -0,0 +1,103 @@ +/* Common PackageCard styles */ +.root { + display: flex; + flex-direction: column; + gap: var(--gap--12); + align-items: center; + width: 318px; + height: 496px; + padding: var(--space--20); + border-radius: var(--border-radius--16); + background: linear-gradient(to right bottom, #9d30e4 0%, #23ffb0 100%); +} + +.header { + display: flex; + flex-direction: column; + gap: var(--gap--12); + align-items: center; +} + +.logo { + display: flex; + flex-direction: row; + gap: var(--gap--8); + align-items: center; +} + +.title { + color: var(--color-default); + font: var(--font-body); + font-weight: 700; + line-height: var(--line-height--18); +} + +.profileTitle { + color: var(--color-default); + font: var(--font-body); + font-weight: 700; + line-height: var(--line-height--18); +} + +.content { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: var(--gap--12); + padding: var(--space--10) var(--space--20) var(--space--20); + overflow-y: scroll; +} + +.modrow { + display: flex; + flex-direction: row; + gap: var(--gap--4); + align-items: center; + justify-content: space-between; + padding: var(--space--10); + border-radius: var(--space--10); + background-color: var(--color-default); +} + +.modInfo { + display: flex; + flex-basis: 85%; + flex-flow: column; + align-items: flex-start; + text-overflow: ellipsis; + overflow-wrap: anywhere; +} + +.modName { + color: var(--color-highlight); + font: var(--font-body); + font-weight: 700; + line-height: var(--line-height--18); +} + +.modVersion { + color: var(--color-text--default); + font: var(--font-body); + font-weight: 400; + font-size: var(--font-size--14); + line-height: var(--line-height--18); +} + +.modLink { + color: var(--color-highlight); +} + +.content::-webkit-scrollbar { + width: 12px; + border-radius: 10px; + background-color: #0000; +} + +.content::-webkit-scrollbar-track { + border-radius: 10px; +} + +.content::-webkit-scrollbar-thumb { + border-radius: 10px; + background-image: var(--color-gradient-purple-green--darker); +} diff --git a/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.tsx b/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.tsx new file mode 100644 index 000000000..4799a684e --- /dev/null +++ b/packages/cyberstorm/src/components/ProfilePanel/ProfilePanel.tsx @@ -0,0 +1,58 @@ +import styles from "./ProfilePanel.module.css"; +import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { ThunderstoreLogo } from "../ThunderstoreLogo/ThunderstoreLogo"; +import { Title } from "../Title/Title"; + +export interface ProfileModsProps { + name: string; + version: string; + url: string; +} + +export interface ProfileProps { + code: string; + name: string; + mods: ProfileModsProps[]; +} + +export interface ProfilePanelProps { + profile: ProfileProps; +} + +/** + * Cyberstorm ProfilePanel component + */ +export function ProfilePanel(props: ProfilePanelProps) { + const { profile } = props; + + return ( +
+
+
+ + + </div> + <div className={styles.profileTitle}>Profile: {profile.name}</div> + <div className={styles.profileTitle}>Code: {profile.code}</div> + </div> + <div className={styles.content}> + {profile.mods.map(function (mod, i) { + return ( + <div key={String(i)} className={styles.modrow}> + <div className={styles.modInfo}> + <div className={styles.modName}>{mod.name}</div> + <div className={styles.modVersion}>{mod.version}</div> + </div> + <a className={styles.modLink} href={mod.url}> + <FontAwesomeIcon fixedWidth icon={faArrowUpRightFromSquare} /> + </a> + </div> + ); + })} + </div> + </div> + ); +} + +ProfilePanel.displayName = "ProfilePanel"; diff --git a/packages/cyberstorm/src/index.ts b/packages/cyberstorm/src/index.ts index 6c5a2f397..e568543ab 100644 --- a/packages/cyberstorm/src/index.ts +++ b/packages/cyberstorm/src/index.ts @@ -10,6 +10,7 @@ export * from "./components/Links/Links"; export * from "./components/MenuItem/MenuItem"; export * from "./components/MetaItem/MetaItem"; export * from "./components/PackageCard/PackageCard"; +export * from "./components/ProfilePanel/ProfilePanel"; export * from "./components/PackageFlag/PackageFlag"; export * from "./components/PackageIcon/PackageIcon"; export * from "./components/Pagination/Pagination"; @@ -28,6 +29,7 @@ export * from "./components/Layout/PackageDetailLayout/PackageDetailLayout"; export * from "./components/Layout/PackageListLayout/PackageListLayout"; export * from "./components/Layout/Settings/SettingsLayout"; export * from "./components/Layout/Teams/TeamsLayout"; +export * from "./components/Layout/TwitchProfilePanelLayout/TwitchProfilePanelLayout"; export * from "./components/Layout/Developers/ManifestValidator/ManifestValidatorLayout"; export * from "./components/Layout/Developers/MarkdownPreview/MarkdownPreviewLayout";