diff --git a/Dockerfile b/Dockerfile index eb1668005..13994132b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -127,6 +127,9 @@ COPY --from=builder /app/apps/site-projects/next.config.js \ COPY --from=builder /app/apps/dev-recruiters/next.config.js \ /app/apps/dev-recruiters/package.json \ ./apps/dev-recruiters/ +COPY --from=builder /app/apps/gptbot/next.config.js \ + /app/apps/gptbot/package.json \ + ./apps/gptbot/ COPY --from=builder /app/apps/app/public ./apps/app/public COPY --from=builder --chown=nextjs:nodejs /app/apps/app/.next ./apps/app/.next COPY --from=builder --chown=nextjs:nodejs /app/apps/app/.env.production ./apps/app/.env.production diff --git a/apps/app/next.config.js b/apps/app/next.config.js index e7b2ef2ee..554458a2e 100644 --- a/apps/app/next.config.js +++ b/apps/app/next.config.js @@ -7,6 +7,7 @@ const withTM = require('next-transpile-modules')([ '@devlaunchers/site-projects', '@devlaunchers/dev-recruiters', '@devlaunchers/website', + '@devlaunchers/gptbot', ]); // pass the modules you would like to see transpiled /** @type {import('next').NextConfig} */ @@ -39,18 +40,21 @@ const nextConfig = { 'devlaunchersstaging.blob.core.windows.net', 'lh3.googleusercontent.com', 'localhost', - 'apiv4-staging.devlaunchers.org' + 'apiv4-staging.devlaunchers.org', ], disableStaticImages: true, - unoptimized: false + unoptimized: false, }, webpack: ( config, { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack } ) => { // Important: return the modified config - config.resolve.alias['styled-components'] = path.resolve("./node_modules", "styled-components"); - return config + config.resolve.alias['styled-components'] = path.resolve( + './node_modules', + 'styled-components' + ); + return config; }, reactStrictMode: true, // It helps you avoid legacy code, and deprecated APIs. eslint: { diff --git a/apps/app/package.json b/apps/app/package.json index 120b45de8..8c46c8b01 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -7,6 +7,7 @@ "dependencies": { "@builder.io/partytown": "0.7.4", "@devlaunchers/dev-recruiters": "workspace:^", + "@devlaunchers/gptbot": "workspace:*", "@devlaunchers/ideaspace": "*", "@devlaunchers/site-projects": "*", "@devlaunchers/tailwind": "workspace:*", diff --git a/apps/app/pages/gptbot/index.jsx b/apps/app/pages/gptbot/index.jsx new file mode 100644 index 000000000..bbcf04797 --- /dev/null +++ b/apps/app/pages/gptbot/index.jsx @@ -0,0 +1,8 @@ +import Page from '@devlaunchers/gptbot/src/pages/index'; +import App from '@devlaunchers/gptbot/src/pages/_app'; +//export { getStaticProps } from '@devlaunchers/website/src/pages/index'; + +///////////////////////////////////////// + +import { constructAppPage } from '../../utils/routingTools.js'; +export default constructAppPage(App, Page); diff --git a/apps/app/styles/globals.js b/apps/app/styles/globals.js index a71eeed2a..0bd9f523c 100644 --- a/apps/app/styles/globals.js +++ b/apps/app/styles/globals.js @@ -1,284 +1,284 @@ -import { createGlobalStyle } from "styled-components"; -import { normalize } from "styled-normalize"; - -const GlobalStyle = createGlobalStyle` - ${normalize} - -html, -body { - padding: 0; - margin: 0; - /*font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, - Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;*/ - font-family: sans-serif; - font-family: "Nunito", sans-serif; - font-weight: lighter; - color: ${({ theme }) => theme.colors.NEUTRAL_1}; - background-color: #f0edee; -} - -html { - display: flex; - width: 100%; - min-height: 100%; - scroll-behavior: smooth; - /*overflow: auto;*/ -} - -body { - min-height: 100%; - margin: 0px; - width: 100%; - height: 100%; - font-size: 1.5rem; -} - -.toast-container { - width: 70vw; -} -.toast { - width: 100%; - height: 100%; - background-color: white; - color: #1c1c1c; - margin: 0; - border: 0; -} -.toast-body { - width: 100%; - height: 100%; -} -.toast-progress { - background: black !important; -} -@media (orientation: portrait) { - .toast-container { - width: 90vw; - } -} - -::-webkit-scrollbar { - width: 20px; -} - -::-webkit-scrollbar-thumb { - background: gray; - border-radius: 10px; - border-top: 5px solid transparent; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 5px solid transparent; - background-clip: content-box; -} - -#root { - overflow-x: hidden; -} - -.App { - font-family: sans-serif; - font-family: "Nunito Sans", sans-serif; - text-align: left; -} - -a { - width: auto; - display: inline; - color: ${({ theme }) => theme.colors.ACCENT_3}; - text-decoration: none; - &:hover { - color: ${({ theme }) => theme.colors.ACCENT_4}; - } -} -h1, -h2, -h3, -h4, -h5, -h6 { - margin-top: 1rem; - margin-bottom: 1rem; -} - -h1 { - font-family: ${({ theme }) => theme.fonts.headline}, sans-serif; - line-height: 1em; - margin-top: 4%; - margin-bottom: 4%; - - width: fit-content; - padding: 1rem; - // background-color:${({ theme }) => theme.colors.NEUTRAL_1}; - // color:${({ theme }) => theme.colors.NEUTRAL_2}; - - border-bottom: .3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; -} - -h2 { - font-family: "Abel", sans-serif; -} - -h3 { - font-family: "Abel", sans-serif; - font-size: 2.5rem; - font-weight: bold; -} - -h4 { - font-family: "Abel", sans-serif; -} - -/* -* { - box-sizing: border-box; -} -* - - -/* collections default to small-cards for entry elements */ -.collection { - width: 100%; - display: flex; - flex-direction: row; - justify-content: flex-start; - flex-wrap: wrap; -} -.entry { - margin: 1.5%; - /*border: 2px solid #1c1c1c;*/ - width: 30%; - - border-radius: 2px; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -} -.collection--small-cards > .entry { - /* Allows us to control card size with just the collection element's class */ - width: 30%; -} -.collection--large-cards > .entry { - /* Allows us to control card size with just the collection element's class */ - width: 90%; -} - -.entry-heading { - width: 100%; - font-size: 2rem; - background-color: #1c1c1c; -} -.entry-title { - margin-left: 4%; -} -.entry-content { - width: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; -} -.entry-image-holder { - width: 100%; - display: flex; - justify-content: center; - align-items: center; -} - -.entry-image { - background-color: red; - height: 10vw; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); - /* padding-bottom: 42.5%; */ - cursor: pointer; -} -.entry-description { - width: 90%; -} - -/* Special collection--large-cards overrides */ -.collection--large-cards > .entry > .entry-content { - flex-direction: row; - justify-content: space-between; -} -.collection--large-cards > .entry > .entry-content > .entry-image-holder { - width: 30%; - height: 100%; -} -.collection--large-cards > .entry > .entry-content > .entry-description { - width: 70%; -} - -.entry-image-holder a div { - /* temp to push image placeholders down */ - padding-right: 15vw; - background-color: lightgray; -} - - -li { - margin-bottom: 5px; -} - -/* React tabs */ -// css -.react-tabs__tab-list { - border-bottom: none; -} - -.react-tabs__tab { - // your custom style goes here - font-family: ${({ theme }) => theme.fonts.headline}; - border-radius:0; - font-size:3rem; - border:.3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; - background-color: ${({ theme }) => theme.colors.NEUTRAL_1}; - color: ${({ theme }) => theme.colors.NEUTRAL_2}; - margin-right:.5rem; -} - -.react-tabs__tab--selected { - // your custom style goes here - border-color:${({ theme }) => theme.colors.NEUTRAL_1}; - color:${({ theme }) => theme.colors.NEUTRAL_1}; - background-color:transparent; - border-bottom:none; -} - -.react-tabs__tab:focus { - // your custom style goes here -} - -.react-tabs__tab:focus:after { - // your custom style goes here -} - - -@media (orientation: portrait) { - html { - /* Scale all font down */ - font-size: 75%; - } - - .App { - } - - h1 { - font-size: 1.7rem; - } - - h2 { - font-size: 1.2rem; - } - - .collection--small-cards > .entry { - width: 100%; - } - .entry-image { - height: 20vw; - } - - .react-tabs__tab { - font-size:2rem; - } -} - -`; -export default GlobalStyle; +import { createGlobalStyle } from 'styled-components'; +import { normalize } from 'styled-normalize'; + +const GlobalStyle = createGlobalStyle` + ${normalize} + +html, +body { + padding: 0; + margin: 0; + /*font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;*/ + font-family: sans-serif; + font-family: "Nunito", sans-serif; + font-weight: lighter; + color: ${({ theme }) => theme.colors.NEUTRAL_1}; + background-color: #f0edee; +} + +html { + display: flex; + width: 100%; + min-height: 100%; + scroll-behavior: smooth; + /*overflow: auto;*/ +} + +body { + min-height: 100%; + margin: 0px; + width: 100%; + height: 100%; + font-size: 1.5rem; +} + +.toast-container { + width: 70vw; +} +.toast { + width: 100%; + height: 100%; + background-color: white; + color: #1c1c1c; + margin: 0; + border: 0; +} +.toast-body { + width: 100%; + height: 100%; +} +.toast-progress { + background: black !important; +} +@media (orientation: portrait) { + .toast-container { + width: 90vw; + } +} + +::-webkit-scrollbar { + width: 20px; +} + +::-webkit-scrollbar-thumb { + background: gray; + border-radius: 10px; + border-top: 5px solid transparent; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid transparent; + background-clip: content-box; +} + +#root { + overflow-x: hidden; +} + +.App { + font-family: sans-serif; + font-family: "Nunito Sans", sans-serif; + text-align: left; +} + +a { + width: auto; + display: inline; + color: ${({ theme }) => theme.colors.ACCENT_3}; + text-decoration: none; + &:hover { + color: ${({ theme }) => theme.colors.ACCENT_4}; + } +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +h1 { + font-family: ${({ theme }) => theme.fonts.headline}, sans-serif; + line-height: 1em; + margin-top: 4%; + margin-bottom: 4%; + + width: fit-content; + padding: 1rem; + // background-color:${({ theme }) => theme.colors.NEUTRAL_1}; + // color:${({ theme }) => theme.colors.NEUTRAL_2}; + + border-bottom: .3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; +} + +h2 { + font-family: "Abel", sans-serif; +} + +h3 { + font-family: "Abel", sans-serif; + font-size: 2.5rem; + font-weight: bold; +} + +h4 { + font-family: "Abel", sans-serif; +} + +/* +* { + box-sizing: border-box; +} +* + + +/* collections default to small-cards for entry elements */ +.collection { + width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-start; + flex-wrap: wrap; +} +.entry { + margin: 1.5%; + /*border: 2px solid #1c1c1c;*/ + width: 30%; + + border-radius: 2px; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); +} +.collection--small-cards > .entry { + /* Allows us to control card size with just the collection element's class */ + width: 30%; +} +.collection--large-cards > .entry { + /* Allows us to control card size with just the collection element's class */ + width: 90%; +} + +.entry-heading { + width: 100%; + font-size: 2rem; + background-color: #1c1c1c; +} +.entry-title { + margin-left: 4%; +} +.entry-content { + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; +} +.entry-image-holder { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.entry-image { + background-color: red; + height: 10vw; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); + /* padding-bottom: 42.5%; */ + cursor: pointer; +} +.entry-description { + width: 90%; +} + +/* Special collection--large-cards overrides */ +.collection--large-cards > .entry > .entry-content { + flex-direction: row; + justify-content: space-between; +} +.collection--large-cards > .entry > .entry-content > .entry-image-holder { + width: 30%; + height: 100%; +} +.collection--large-cards > .entry > .entry-content > .entry-description { + width: 70%; +} + +.entry-image-holder a div { + /* temp to push image placeholders down */ + padding-right: 15vw; + background-color: lightgray; +} + + +li { + margin-bottom: 5px; +} + +/* React tabs */ +// css +.react-tabs__tab-list { + border-bottom: none; +} + +.react-tabs__tab { + // your custom style goes here + font-family: ${({ theme }) => theme.fonts.headline}; + border-radius:0; + font-size:3rem; + border:.3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; + background-color: ${({ theme }) => theme.colors.NEUTRAL_1}; + color: ${({ theme }) => theme.colors.NEUTRAL_2}; + margin-right:.5rem; +} + +.react-tabs__tab--selected { + // your custom style goes here + border-color:${({ theme }) => theme.colors.NEUTRAL_1}; + color:${({ theme }) => theme.colors.NEUTRAL_1}; + background-color:transparent; + border-bottom:none; +} + +.react-tabs__tab:focus { + // your custom style goes here +} + +.react-tabs__tab:focus:after { + // your custom style goes here +} + + +@media (orientation: portrait) { + html { + /* Scale all font down */ + font-size: 75%; + } + + .App { + } + + h1 { + font-size: 1.7rem; + } + + h2 { + font-size: 1.2rem; + } + + .collection--small-cards > .entry { + width: 100%; + } + .entry-image { + height: 20vw; + } + + .react-tabs__tab { + font-size:2rem; + } +} + +`; +export default GlobalStyle; diff --git a/apps/gptbot/.babelrc b/apps/gptbot/.babelrc new file mode 100644 index 000000000..af1f9a5f5 --- /dev/null +++ b/apps/gptbot/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["next/babel"], + "plugins": [["babel-plugin-styled-components", { "ssr": true }]] +} diff --git a/apps/gptbot/.eslintignore b/apps/gptbot/.eslintignore new file mode 100644 index 000000000..83b3fa336 --- /dev/null +++ b/apps/gptbot/.eslintignore @@ -0,0 +1,11 @@ +node_modules +production +staging +workload +.next +/out/ +.vscode +.github +*.json +*.lock +*.md diff --git a/apps/gptbot/.eslintrc-example.js b/apps/gptbot/.eslintrc-example.js new file mode 100644 index 000000000..2524b6c0e --- /dev/null +++ b/apps/gptbot/.eslintrc-example.js @@ -0,0 +1,38 @@ +// Workaround for https://github.com/eslint/eslint/issues/3458 (re-export of @rushstack/eslint-patch) +require("@devlaunchers/eslint-config-bases/patch/modern-module-resolution"); + +module.exports = { + // Be sure to set root to true in monorepo. + root: true, + // Will help typescript extended rules. + parserOptions: { + tsconfigRootDir: __dirname, + project: "tsconfig.json", + }, + ignorePatterns: ["**/node_modules", "**/.cache", "build", ".next"], + extends: [ + "@devlaunchers/eslint-config-bases/typescript", + "@devlaunchers/eslint-config-bases/sonar", + "@devlaunchers/eslint-config-bases/regexp", + "@devlaunchers/eslint-config-bases/react", + "@devlaunchers/eslint-config-bases/rtl", + + + + // Add specific rules for your framework if needed. + // ie: + // - nextjs: 'plugin:@next/next/core-web-vitals', + // - remix: '@remix-run/eslint-config', + // ... + + // Post configure the prettier base so there won't be + // any conficts between eslint / prettier + // "@devlaunchers/eslint-config-bases/prettier", + ], + rules: { + // Specific global rules for your app or package + }, + overrides: [ + // Specific file rules for your app or package + ], +}; \ No newline at end of file diff --git a/apps/gptbot/.gitignore b/apps/gptbot/.gitignore new file mode 100644 index 000000000..1437c53f7 --- /dev/null +++ b/apps/gptbot/.gitignore @@ -0,0 +1,34 @@ +# 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 +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/apps/gptbot/.prettierignore b/apps/gptbot/.prettierignore new file mode 100644 index 000000000..f3144cdff --- /dev/null +++ b/apps/gptbot/.prettierignore @@ -0,0 +1,4 @@ +.next +/out/ +/node_modules/ +.github \ No newline at end of file diff --git a/apps/gptbot/README.md b/apps/gptbot/README.md new file mode 100644 index 000000000..38920c8dc --- /dev/null +++ b/apps/gptbot/README.md @@ -0,0 +1,36 @@ +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 install +npm run dev +# or +yarn install +yarn 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.js`. 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.js`. + +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. + +## 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/gptbot/next-env.d.ts b/apps/gptbot/next-env.d.ts new file mode 100644 index 000000000..3db3c4df2 --- /dev/null +++ b/apps/gptbot/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/apps/gptbot/next.config.js b/apps/gptbot/next.config.js new file mode 100644 index 000000000..151bec8e8 --- /dev/null +++ b/apps/gptbot/next.config.js @@ -0,0 +1,61 @@ +const withPlugins = require("next-compose-plugins"); +const imagesPlugin = require("next-optimized-images"); + + +/** + * @type {import('next').NextConfig} +* */ +const nextConfig = { + basePath: "/projects", + + async rewrites() { + return [ + { + source: "/:path*", + destination: `/:path*`, + }, + { + source: "/", + destination: "https://devlaunchers.org/", + basePath: false + }, + { + source: "/create", + destination: "https://devlaunchers.org/create", + basePath: false + }, + { + source: "/learn", + destination: `https://devlaunchers.org/learn`, + basePath: false + }, + { + source: "/support-us", + destination: `https://devlaunchers.org/support-us`, + basePath: false + }, + ]; + }, + + images: { + /* + next-images plugin is conflicting with Next.js 11 static import feature. + see the discussion here: + https://github.com/twopluszero/next-images/issues/73 + */ + domains: [ + "images.prismic.io", + "devlaunchersproduction.blob.core.windows.net", + ], + disableStaticImages: true, + }, + webpack5: true, + reactStrictMode: true, // It helps you avoid legacy code, and deprecated APIs. + eslint: { + // Warning: Dangerously allow production builds to successfully complete even if + // your project has ESLint errors. + // we have too many errors if you run npm run lint ,but after bug fixes we could enforce this. + ignoreDuringBuilds: true, + }, +}; +module.exports = withPlugins([[imagesPlugin], nextConfig]); diff --git a/apps/gptbot/package.json b/apps/gptbot/package.json new file mode 100644 index 000000000..4cc0b661e --- /dev/null +++ b/apps/gptbot/package.json @@ -0,0 +1,52 @@ +{ + "name": "@devlaunchers/gptbot", + "version": "0.1.0", + "private": true, + "dependencies": { + "@devlaunchers/components": "workspace:*", + "@devlaunchers/utility": "workspace:*", + "axios": "^0.27.2", + "next": "^12.2.3", + "next-optimized-images": "^2.6.2", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "devDependencies": { + "@devlaunchers/eslint-config-bases": "workspace:^", + "@types/react": "^17.0.0", + "@typescript-eslint/eslint-plugin": "^5.32.0", + "@typescript-eslint/parser": "^5.32.0", + "eslint": "8.21.0", + "eslint-config-airbnb": "19.0.4", + "eslint-config-airbnb-typescript": "^17.0.0", + "eslint-config-next": "^12.2.3", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "husky": "^8.0.1", + "lint-staged": "^13.0.3", + "prettier": "^2.7.1", + "semantic-release": "^19.0.3", + "typescript": "^4.7.4", + "webp-loader": "0.6.0", + "webpack": "^5.74.0" + }, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "prepare": "husky install", + "storybook": "start-storybook -p 6006 -s ./public", + "build-storybook": "build-storybook -s public", + "deploy-storybook": "storybook-to-ghpages", + "clean": "rimraf --no-glob ./tsconfig.tsbuildinfo", + "lint": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs,.mdx", + "fix-all-files": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs,.mdx --fix", + "typecheck": "tsc --project ./tsconfig.json --noEmit", + "test": "run-s 'test:*'", + "test:unit": "echo \"No tests yet\"", + "fix:staged-files": "lint-staged --allow-empty" + } +} diff --git a/apps/gptbot/public/favicon.ico b/apps/gptbot/public/favicon.ico new file mode 100644 index 000000000..4965832f2 Binary files /dev/null and b/apps/gptbot/public/favicon.ico differ diff --git a/apps/gptbot/public/vercel.svg b/apps/gptbot/public/vercel.svg new file mode 100644 index 000000000..fbf0e25a6 --- /dev/null +++ b/apps/gptbot/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/apps/gptbot/src/components/README.md b/apps/gptbot/src/components/README.md new file mode 100644 index 000000000..b650795ab --- /dev/null +++ b/apps/gptbot/src/components/README.md @@ -0,0 +1,7 @@ +Our components should be relatively aligned with the Smart vs Dumb aka Container component pattern seen here: https://medium.com/@thejasonfile/dumb-components-and-smart-components-e7b33a698d43 + +The 'modules' directory contains specialty components grouped by feature or domain. + +The 'common' directory contains components shared across routes, used in multiple areas of the app. + +We're using folder structures and conventions very similar to those described here: https://hackernoon.com/structuring-projects-and-naming-components-in-react-1261b6e18d76 diff --git a/apps/gptbot/src/content/README.md b/apps/gptbot/src/content/README.md new file mode 100644 index 000000000..ddc58a2f3 --- /dev/null +++ b/apps/gptbot/src/content/README.md @@ -0,0 +1,24 @@ +# This folder contains data fed into our content layer + +This layer has been created with the intent of moving towards a CMS tool like 'Contentful' in the future, or serving up that data from our backend (Firebase?). It allows us to manage all of the content displayed on the site in one location. + +[Currently, we're using some hacky Google Sheets fun to act as a backend] + +## File Naming Conventions + +You can think of each file in the 'collections' folder as a MongoDB collection. Filenames should therefore follow the MongoDB conventions here: https://arkusnexus.com/2016/09/12/coding-guidelines-mongodb/ + +- Key takeaways + - The name should be a plural of the types of documents to be saved. + - Use camelCase. Normally you shouldn’t have to because the collection name will be one word (plural of the types of documents saved). + +## JSON Conventions + +Google's JSON Style Guide: +https://google.github.io/styleguide/jsoncstyleguide.xml + +- Key takeaways + - Property names are camel cased + - Use double quotes + - Array types should have plural property names, all other property names should be singular + - Data should not be arbitrarily grouped for convenience diff --git a/apps/gptbot/src/custom.d.ts b/apps/gptbot/src/custom.d.ts new file mode 100644 index 000000000..d5c901ea0 --- /dev/null +++ b/apps/gptbot/src/custom.d.ts @@ -0,0 +1 @@ +declare module "*.png?webp"; diff --git a/apps/gptbot/src/pages/_app.jsx b/apps/gptbot/src/pages/_app.jsx new file mode 100644 index 000000000..f206c4c3a --- /dev/null +++ b/apps/gptbot/src/pages/_app.jsx @@ -0,0 +1,46 @@ +import { useRouter } from "next/router"; +import Script from "next/script"; +import { ThemeProvider } from "styled-components"; +import GlobalStyle from "../styles/globals"; +import oldTheme from "../styles/theme"; + +const hashRedirect = (router) => { + // Strip out hash from url (if any) so we can transition from HashRouter to BrowserRouter + if (router.asPath.startsWith("/#")) { + router.push(router.asPath.replace("/#", "")); + } +}; + +function MyApp(props) { + const router = useRouter(); + hashRedirect(router); + + return ( + <> + + +
+ +
+ {/* */} + {props.children} +
+
+
+ + ); +} + +export default MyApp; diff --git a/apps/gptbot/src/pages/_document.js b/apps/gptbot/src/pages/_document.js new file mode 100644 index 000000000..a33fb60a3 --- /dev/null +++ b/apps/gptbot/src/pages/_document.js @@ -0,0 +1,54 @@ +// eslint-disable-next-line @next/next/no-document-import-in-page +import Document, { Html, Head, Main, NextScript } from "next/document"; + +import { ServerStyleSheet } from "styled-components"; + +export default class MyDocument extends Document { + render() { + return ( + + + + + + + +
+ + + + ); + } + + static async getInitialProps(ctx) { + const sheet = new ServerStyleSheet(); + const originalRenderPage = ctx.renderPage; + + try { + ctx.renderPage = () => + originalRenderPage({ + enhanceApp: (App) => (props) => + sheet.collectStyles(), + }); + + const initialProps = await Document.getInitialProps(ctx); + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + {sheet.getStyleElement()} + + ), + }; + } finally { + sheet.seal(); + } + } +} diff --git a/apps/gptbot/src/pages/index.jsx b/apps/gptbot/src/pages/index.jsx new file mode 100644 index 000000000..3ad8dea0f --- /dev/null +++ b/apps/gptbot/src/pages/index.jsx @@ -0,0 +1,106 @@ +import Head from "next/head"; +import React, { useEffect } from 'react'; +import Button from "@devlaunchers/components/src/components/atoms/Button"; +import OpenResponse from "@devlaunchers/components/src/components/organisms/OpenResponse"; +import BaseLayer from "@devlaunchers/components/src/components/atoms/BaseLayer"; +import { send } from "../utils/chat.js"; +import { displayText } from "../utils/chat.js"; + +const ProjectsList = () => { + useEffect(() => { + const handleKeyPress = (event) => { + // Check if the pressed key is the "Enter" key (key code 13) + if (event.key === 'Enter') { + send(); // Call the send method + } + }; + + // Add an event listener for keydown when the component mounts + document.addEventListener('keydown', handleKeyPress); + + // Remove the event listener when the component unmounts to prevent memory leaks + return () => { + document.removeEventListener('keydown', handleKeyPress); + }; + }, []); // Empty dependency array means this effect runs once on mount + + return ( + <> + + Our Projects + + + + + + + + + + + + + + + + + +
+
+ + +
+ + + + + ); +}; + +export default ProjectsList; \ No newline at end of file diff --git a/apps/gptbot/src/styled.d.ts b/apps/gptbot/src/styled.d.ts new file mode 100644 index 000000000..20c11929c --- /dev/null +++ b/apps/gptbot/src/styled.d.ts @@ -0,0 +1,9 @@ +// import original module declarations +import { Theme } from '@styles/theme'; +import {} from 'styled-components/cssprop' +import 'styled-components'; + +// and extend them! +declare module 'styled-components' { + export interface DefaultTheme extends Theme {} +} diff --git a/apps/gptbot/src/styles/globals.js b/apps/gptbot/src/styles/globals.js new file mode 100644 index 000000000..3307c41d7 --- /dev/null +++ b/apps/gptbot/src/styles/globals.js @@ -0,0 +1,272 @@ +import { createGlobalStyle } from "styled-components"; +import { normalize } from "styled-normalize"; + +const GlobalStyle = createGlobalStyle` + ${normalize} + +html, +body { + padding: 0; + margin: 0; + /*font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;*/ + font-family: sans-serif; + font-family: "Nunito", sans-serif; + font-weight: lighter; + color: ${({ theme }) => theme.colors.NEUTRAL_1}; + background-color: #f0edee; +} + +html { + display: flex; + width: 100%; + min-height: 100%; + scroll-behavior: smooth; + /*overflow: auto;*/ +} + +body { + min-height: 100%; + margin: 0px; + width: 100%; + height: 100%; + font-size: 1.5rem; +} + +::-webkit-scrollbar { + width: 20px; +} + +::-webkit-scrollbar-thumb { + background: gray; + border-radius: 10px; + border-top: 5px solid transparent; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid transparent; + background-clip: content-box; +} + +#root { + overflow-x: hidden; +} + +.App { + font-family: sans-serif; + font-family: "Nunito Sans", sans-serif; + text-align: left; +} + +a { + width: auto; + display: inline; + color: ${({ theme }) => theme.colors.ACCENT_3}; + text-decoration: none; + &:hover { + color: ${({ theme }) => theme.colors.ACCENT_4}; + } +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +h1 { + font-family: ${({ theme }) => theme.fonts.headline}, sans-serif; + line-height: 1em; + margin-top: 4%; + margin-bottom: 4%; + + width: fit-content; + padding: 1rem; + // background-color:${({ theme }) => theme.colors.NEUTRAL_1}; + // color:${({ theme }) => theme.colors.NEUTRAL_2}; + + border-bottom: .3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; +} + +h2 { + font-family: "Abel", sans-serif; +} + +h3 { + font-family: "Abel", sans-serif; + font-size: 2.5rem; + font-weight: bold; +} + +h4 { + font-family: "Abel", sans-serif; +} + +strong { + font-weight: bold; +} + +/* +* { + box-sizing: border-box; +} +* +.toast-container { +} +.toast { + background-color: white; + color: #1c1c1c; +} +.toast-progress { + background: black !important; +} + +/* collections default to small-cards for entry elements */ +.collection { + width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-start; + flex-wrap: wrap; +} +.entry { + margin: 1.5%; + /*border: 2px solid #1c1c1c;*/ + width: 30%; + + border-radius: 2px; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); +} +.collection--small-cards > .entry { + /* Allows us to control card size with just the collection element's class */ + width: 30%; +} +.collection--large-cards > .entry { + /* Allows us to control card size with just the collection element's class */ + width: 90%; +} + +.entry-heading { + width: 100%; + font-size: 2rem; + background-color: #1c1c1c; +} +.entry-title { + margin-left: 4%; +} +.entry-content { + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; +} +.entry-image-holder { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.entry-image { + background-color: red; + height: 10vw; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); + /* padding-bottom: 42.5%; */ + cursor: pointer; +} +.entry-description { + width: 90%; +} + +/* Special collection--large-cards overrides */ +.collection--large-cards > .entry > .entry-content { + flex-direction: row; + justify-content: space-between; +} +.collection--large-cards > .entry > .entry-content > .entry-image-holder { + width: 30%; + height: 100%; +} +.collection--large-cards > .entry > .entry-content > .entry-description { + width: 70%; +} + +.entry-image-holder a div { + /* temp to push image placeholders down */ + padding-right: 15vw; + background-color: lightgray; +} + + +li { + margin-bottom: 5px; +} + +/* React tabs */ +// css +.react-tabs__tab-list { + border-bottom: none; +} + +.react-tabs__tab { + // your custom style goes here + font-family: ${({ theme }) => theme.fonts.headline}; + border-radius:0; + font-size:3rem; + border:.3rem solid ${({ theme }) => theme.colors.NEUTRAL_1}; + background-color: ${({ theme }) => theme.colors.NEUTRAL_1}; + color: ${({ theme }) => theme.colors.NEUTRAL_2}; + margin-right:.5rem; +} + +.react-tabs__tab--selected { + // your custom style goes here + border-color:${({ theme }) => theme.colors.NEUTRAL_1}; + color:${({ theme }) => theme.colors.NEUTRAL_1}; + background-color:transparent; + border-bottom:none; +} + +.react-tabs__tab:focus { + // your custom style goes here +} + +.react-tabs__tab:focus:after { + // your custom style goes here +} + + +@media (orientation: portrait) { + html { + /* Scale all font down */ + font-size: 75%; + } + + .App { + } + + h1 { + font-size: 1.7rem; + } + + h2 { + font-size: 2.2rem; + } + + .collection--small-cards > .entry { + width: 100%; + } + .entry-image { + height: 20vw; + } + + .react-tabs__tab { + font-size:2rem; + } +} + +`; +export default GlobalStyle; diff --git a/apps/gptbot/src/styles/helpers.js b/apps/gptbot/src/styles/helpers.js new file mode 100644 index 000000000..4a3b9c571 --- /dev/null +++ b/apps/gptbot/src/styles/helpers.js @@ -0,0 +1,9 @@ +export const hexToRGBA = (hexColor, opacity = 1) => { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor); + return result + ? `rgba(${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt( + result[3], + 16 + )},${opacity})` + : null; +}; diff --git a/apps/gptbot/src/styles/theme.ts b/apps/gptbot/src/styles/theme.ts new file mode 100644 index 000000000..62c7dfbbd --- /dev/null +++ b/apps/gptbot/src/styles/theme.ts @@ -0,0 +1,63 @@ +const theme = { + colors: { + NEUTRAL_1: "#1c1c1c", // dark + ACCENT_1: "#ff7f0e", // orange + ACCENT_2: "#ffab00", // yellow + ACCENT_3: "#3a7ca5", // dark-blue + ACCENT_4: "#81c3d7", // loght-blue + ACCENT_5: "#ffc30f", // orange-yellow + ACCENT_6: "#C5B1A0", // beige + NEUTRAL_2: "#f0edee", // light + + NEUTRAL_3:"#59687B", + NEUTRAL_4:"#C4C4C4", + NEUTRAL_5:"#89969F", + NEUTRAL_6:"#C3C0C0", + // Dev Recruiters theme colors + White: '#FFFFFF', + Black: '#000000', + BlackT60: 'rgba(0,0,0,0.6)', + BlackT38: 'rgba(0,0,0,0.38)', + + AntiFlashWhite: '#F1F4F5', + AntiFlashWhiteT40: 'rgba(241,244,245,0.4)', + + SilverSand: '#C4C4C4', + SilverSandT20: 'rgba(196,196,196,0.2)', + + LightGray: '#D3D4D6', + LightGrayT90: 'rgba(211, 212, 214, 0.9)', + + Cultured: '#F8F8F8', + CulturedT87: 'rgba(248, 248, 248, 0.87)', + + Red: '#FF0000', + RedT31: 'rgba(255,0,0,0.31)', + + AppleT48: 'rgba(102, 176, 75, 0.48)', + + OuterSpace: '#454D58', + DarkElectricBlue: '#59687B', + Crayola: '#30363E', + Gray: '#7E8288', + CoolGrey: '#89969F', + Argent: '#C3C0C0', + BlackCoral: '#5B6068', + Platinum: '#E5E5E5', + SonicSilver: '#6F747C', + BrightGray: '#EDEDED', + DavysGrey: '#4F5154', + }, + fonts: { + headline: 'Abel', + normal: 'Nunito Sans', + }, + fontSizes: { + small: '1em', + medium: '2em', + large: '3em', + }, +} as const; +type Theme = typeof theme; +export type { Theme }; +export default theme; \ No newline at end of file diff --git a/apps/gptbot/src/utils/GoogleAnalytics.js b/apps/gptbot/src/utils/GoogleAnalytics.js new file mode 100644 index 000000000..438d7bf53 --- /dev/null +++ b/apps/gptbot/src/utils/GoogleAnalytics.js @@ -0,0 +1,10 @@ +import ReactGA from "react-ga"; + +export const initGA = () => { + ReactGA.initialize("UA-180113136-1"); +}; + +export const logPageView = () => { + ReactGA.set({ page: window.location.pathname }); + ReactGA.pageview(window.location.pathname); +}; diff --git a/apps/gptbot/src/utils/Logout.js b/apps/gptbot/src/utils/Logout.js new file mode 100644 index 000000000..855b1929f --- /dev/null +++ b/apps/gptbot/src/utils/Logout.js @@ -0,0 +1,12 @@ +import Router from "next/router"; +import axios from "axios"; + +const Logout = () => { + axios + .get(`${process.env.NEXT_PUBLIC_STRAPI_URL}/auth/logout`, { withCredentials: true }) + .then(() => { + Router.reload(window.location.pathname); + }); +}; + +export default Logout; diff --git a/apps/gptbot/src/utils/ScrollToTop.js b/apps/gptbot/src/utils/ScrollToTop.js new file mode 100644 index 000000000..bbf080b01 --- /dev/null +++ b/apps/gptbot/src/utils/ScrollToTop.js @@ -0,0 +1,16 @@ +import { useEffect } from "react"; + +function ScrollToTop({ history }) { + useEffect(() => { + const unlisten = history.listen(() => { + window.scrollTo(0, 0); + }); + return () => { + unlisten(); + }; + }, [history]); + + return null; +} + +export default ScrollToTop; diff --git a/apps/gptbot/src/utils/TimeZoneConverter.js b/apps/gptbot/src/utils/TimeZoneConverter.js new file mode 100644 index 000000000..eaec2431f --- /dev/null +++ b/apps/gptbot/src/utils/TimeZoneConverter.js @@ -0,0 +1,29 @@ +import { DateTime } from "luxon"; + +export const ConvertCentralTime = (weekday = 6, hour, minute = 0) => + DateTime.fromObject({ + weekday, + hour, + minute, + zone: "UTC-5", + }).setZone("local"); + +export const ConvertCentralTimeString = ( + weekday = 0, + hour = 0, + minute = 0, + repeat = { weeks: 1 } +) => { + let centralDate = ConvertCentralTime(weekday, hour, minute); + if (DateTime.now() > centralDate) { + centralDate = centralDate.plus(repeat); + } + const localDate = centralDate.toLocaleString({ + weekday: "long", + month: "long", + day: "numeric", + hour: "numeric", + }); + const localTz = centralDate.toFormat("ZZZZ"); + return `${localDate} ${localTz}`; +}; diff --git a/apps/gptbot/src/utils/ValidateEmail.js b/apps/gptbot/src/utils/ValidateEmail.js new file mode 100644 index 000000000..507c75f65 --- /dev/null +++ b/apps/gptbot/src/utils/ValidateEmail.js @@ -0,0 +1,5 @@ +export default function validateEmail(email) { + const re = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); +} diff --git a/apps/gptbot/src/utils/chat.js b/apps/gptbot/src/utils/chat.js new file mode 100644 index 000000000..bf9d1df4d --- /dev/null +++ b/apps/gptbot/src/utils/chat.js @@ -0,0 +1,67 @@ +let questionNumber = 0; + +export async function send() { + let d = document.getElementById('chatbox'); + var i = d.value; + d.value = ''; + questionNumber++; + displayText('User: ' + i + ' : {Question #' + questionNumber + '}'); + await response(i); +} + +function response(i) { + let d = document.getElementById('chatbox'); + let b = document.getElementById('sendButton'); + //d.disabled = true; + + // Define the URL of the server where your Flask app is running + //const serverUrl = "http://127.0.0.1:5000/question"; + + // Create an object with the data you want to send + //const data = new URLSearchParams(); + //data.append("string", i); + + // Define the configuration for the POST request + /* + const requestOptions = { + method: "POST", + body: data, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }; + */ + // Send the POST request + /* + fetch(serverUrl, requestOptions) + .then((response) => { + if (response.ok) { + return response.text(); + } else { + throw new Error(`Failed to make the request: ${response.status}`); + } + }) + .then((responseText) => { + responseNumber++; + // Handle the response here (e.g., printing it to the console) + displayText("Onboarding bot: " + responseText + "{Response #" + responseNumber + "}"); + d.disabled = false; + }) + .catch((error) => { + // Handle any errors that occurred during the request + console.error(error); + d.disabled = false; + + }); + */ + displayText('System: {Message #' + questionNumber + '} was ' + i); +} + +export function displayText(i) { + let d = document.getElementById('chat'); + d.innerHTML += msg(i); +} + +function msg(i) { + return `
${i}
`; +} diff --git a/apps/gptbot/tsconfig.json b/apps/gptbot/tsconfig.json new file mode 100644 index 000000000..60a295680 --- /dev/null +++ b/apps/gptbot/tsconfig.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": "./src", + "target": "esnext", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "esnext", + "jsx": "preserve", + "incremental": true, + "paths": { + "@/lib/*": ["./lib/*"], + "@/components/*": ["./components/*"], + "@/pages/*": ["./pages/*"], + "@/public/*": ["../public/*"], + "@/themes/*": ["./themes/*"], + "@devlaunchers/components/*": ["../../../packages/components/src/*"], + "@devlaunchers/components": ["../../../packages/components/src/index"], + "@devlaunchers/core-lib/*": ["../../../packages/core-lib/src/*"], + "@devlaunchers/core-lib": ["../../../packages/core-lib/src/index"] + } + }, + "exclude": ["**/node_modules", "**/.*/", ".next"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jsx", + "**/*.mjs", + "**/*.json" +, ".eslintrc-example.js" ] +} \ No newline at end of file diff --git a/apps/ideaspace/src/components/common/IdeaForm/IdeaForm.js b/apps/ideaspace/src/components/common/IdeaForm/IdeaForm.js index 1c89b995a..943b68a03 100644 --- a/apps/ideaspace/src/components/common/IdeaForm/IdeaForm.js +++ b/apps/ideaspace/src/components/common/IdeaForm/IdeaForm.js @@ -7,8 +7,7 @@ import SubmissionButton from './SubmissionButton'; import EditionButton from './EditionButton'; import Dropdown from '@devlaunchers/components/components/organisms/Dropdown'; import useResponsive from '@devlaunchers/components/src/hooks/useResponsive'; - - +import Checkbox from '@devlaunchers/components/src/components/Checkbox/Checkbox' const IdeaForm = ({ initialValues, @@ -22,7 +21,7 @@ const IdeaForm = ({ const { errors } = props; const [disabling, setDisabling] = React.useState(true); const { isMobile } = useResponsive(); - + const compareValuesToInitial = (values) => { const name = Object.keys(values); for (let i = 0; i < name.length; i++) { @@ -200,7 +199,7 @@ const IdeaForm = ({ - +  I have read and agree to the Terms and Conditions. * diff --git a/apps/ideaspace/src/components/modules/DashboardPage/DashboardPage.js b/apps/ideaspace/src/components/modules/DashboardPage/DashboardPage.js index 37ecaedb3..33f0fa36a 100644 --- a/apps/ideaspace/src/components/modules/DashboardPage/DashboardPage.js +++ b/apps/ideaspace/src/components/modules/DashboardPage/DashboardPage.js @@ -2,10 +2,10 @@ import React from 'react'; import { useUserDataContext } from '@devlaunchers/components/context/UserDataContext'; import { atoms } from '@devlaunchers/components/src/components'; import SignInSection from '../../common/SignInSection/SignInSection'; -import CircularIndeterminateLoader from '../Loader/CircularIndeterminateLoader' +import CircularIndeterminateLoader from '../Loader/CircularIndeterminateLoader'; import Stats from './Stats/Stats'; import Ideas from './Ideas/Ideas'; -import { cleanDataList } from '../../../utils/StrapiHelper'; +import { cleanDataList, cleanData } from '../../../utils/StrapiHelper'; import { agent } from '@devlaunchers/utility'; import { @@ -16,7 +16,6 @@ import { } from './StyledDashboardPage'; function DashboardPage() { - let { userData, isAuthenticated } = useUserDataContext(); const [loading, setLoading] = React.useState(true); @@ -25,21 +24,28 @@ function DashboardPage() { React.useEffect(async () => { if (isAuthenticated) { - const data = cleanDataList(await agent.Ideas.get( - new URLSearchParams(`populate=*pagination[pageSize]=1000`))); + const data = cleanDataList( + await agent.Ideas.get(new URLSearchParams(`populate=deep`)) + ); + + const allCards = data.map((item) => { + if (item.comments === undefined) item.comments = []; + else item.comments = cleanDataList(item.comments.data); - const allCards = data.map((item) => { - item.comments = cleanDataList(item.comments.data); - return { - ...item, - mostRecentCommentTime: new Date( - item.comments[0]?.updated_at - ).getTime(), - }; - }); + if (item.author.data !== null) { + item.author = cleanData(item.author.data); + } - setLoading(false); - setSourceCards(allCards); + return { + ...item, + mostRecentCommentTime: new Date( + item.comments[0]?.updated_at + ).getTime(), + }; + }); + + setLoading(false); + setSourceCards(allCards); } }, [isAuthenticated]); @@ -54,15 +60,17 @@ function DashboardPage() { - + Everything about your ideas in one place. {!isAuthenticated ? ( ) : ( @@ -70,18 +78,12 @@ function DashboardPage() { ) : ( <> - - - + + )} - ) - } + )} ); } diff --git a/apps/ideaspace/src/components/modules/EditIdea/EditIdea.js b/apps/ideaspace/src/components/modules/EditIdea/EditIdea.js index 2d37bf3c2..e3d975218 100644 --- a/apps/ideaspace/src/components/modules/EditIdea/EditIdea.js +++ b/apps/ideaspace/src/components/modules/EditIdea/EditIdea.js @@ -10,12 +10,7 @@ import IdeaForm from '../../common/IdeaForm/IdeaForm'; import useConfirm from '../../common/DialogBox/DialogBox'; import * as Yup from 'yup'; - -import { - HeadWapper, - Headline, - StyledRanbow, -} from './StyledEditIdea'; +import { HeadWapper, Headline, StyledRanbow } from './StyledEditIdea'; function EditIdea() { let { userData, isAuthenticated } = useUserDataContext(); @@ -28,32 +23,32 @@ function EditIdea() { const [Dialog, confirmLeave] = useConfirm( ['You have unsaved changes', '', ''], 'Are you sure you want to discard the changes and leave?', - ['alternative primary', 'CANCEL', 'LEAVE'], + ['alternative primary', 'CANCEL', 'LEAVE'] ); const [urrl, setUrrl] = useState(''); const [UpdateSucceed, confirmSucceed] = useConfirm( ['Idea updated successfully', '', ''], '', - ['primary', 'got it'], + ['primary', 'got it'] ); const [UpdateFailure, confirmFailure] = useConfirm( ['Unable to update your idea', '', ''], 'Please try again.', - ['primary', 'close'], + ['primary', 'close'] ); const [NotAuthor, confirmNotAuthor] = useConfirm( - ["This is not your idea.", '', ''], + ['This is not your idea.', '', ''], '', - ['primary', 'close'], + ['primary', 'close'] ); const [ArchivedIdea, confirmArchive] = useConfirm( - ["This idea has been archived.", '', ''], + ['This idea has been archived.', '', ''], 'To workshop on it, you need to reactivate it first.', - ['primary', 'got it'], + ['primary', 'got it'] ); const [card, setCard] = useState({ @@ -82,15 +77,17 @@ function EditIdea() { useEffect(async () => { if (ideaId) { - const idea = cleanData(await agent.Ideas.getIdea(ideaId, new URLSearchParams("populate=*"))); + const idea = cleanData( + await agent.Ideas.getIdea(ideaId, new URLSearchParams('populate=*')) + ); if (!idea || !idea.id || idea.id == 0) { setGetError(true); return; } if (userData.id !== 0) { - if (idea.author.id === userData.id) { - if (response.data?.status == 'archived') { + if (idea.author.data.id === userData.id) { + if (idea.status == 'archived') { rejectAuthor(); } @@ -125,7 +122,7 @@ function EditIdea() { if (data.ideaName) { setunsavedChanges(false); - if (await confirmNotice()){ + if (await confirmNotice()) { setUrrl(`/ideaspace/workshop/${data.id}`); } } @@ -142,7 +139,7 @@ function EditIdea() { } else { setSending(false); } - } + }; useEffect(() => { window.onbeforeunload = () => { @@ -155,7 +152,7 @@ function EditIdea() { handleDialog(url); router.events.emit('routeChangeError'); throw 'Abort route change. Please ignore this error.'; - } + }; router.events.on('routeChangeStart', routeChangeStart); return () => { router.events.off('routeChangeStart', routeChangeStart); @@ -175,12 +172,11 @@ function EditIdea() { } else { window.history.back(-1); } - } + }; if (getError) { - return + return ; } else { - return ( <> @@ -188,26 +184,28 @@ function EditIdea() { - - - Have an idea for a development project?
+ + + Have an idea for a development project? +
Share your idea with us!
{!isAuthenticated ? ( ) : ( <> - - + + + + { + if (involveString.includes("and also believe")) { + return "highly"; + } else if (involveString.includes("to help with workshopping")) { + return "medium"; + }/* else if (involveString.includes("")) { + return "minimum"; + }*/ else { + return "none" + } + }; + const initialValues = { ideaName: '', tagline: '', @@ -63,8 +75,11 @@ function SubmissionForm() { values['features'] = values['features'].trim(); values['experience'] = values['experience'].trim(); values['extraInfo'] = values['extraInfo'].trim(); - values['involveLevel'] = values['involveLevel'].trim() - setSending(true); + const involveValueForDataBase = getDBInvolveLevel( + values['involveLevel'].trim()); + + values['involveLevel'] = involveValueForDataBase; + setSending(true); try { const data = cleanData(await agent.Ideas.post(values)); diff --git a/apps/ideaspace/src/components/modules/WorkshoppingPage/IdeaOverview/IdeaSettingsCard/IdeaSettingsCard.js b/apps/ideaspace/src/components/modules/WorkshoppingPage/IdeaOverview/IdeaSettingsCard/IdeaSettingsCard.js index 989584ec8..72fe00a45 100644 --- a/apps/ideaspace/src/components/modules/WorkshoppingPage/IdeaOverview/IdeaSettingsCard/IdeaSettingsCard.js +++ b/apps/ideaspace/src/components/modules/WorkshoppingPage/IdeaOverview/IdeaSettingsCard/IdeaSettingsCard.js @@ -1,205 +1,211 @@ import React, { useState } from 'react'; -import axios from "axios"; import { useRouter } from 'next/router'; import { useUserDataContext } from '@devlaunchers/components/context/UserDataContext'; import { atoms } from '@devlaunchers/components/src/components'; import IdeaSettingsContent from './IdeaSettingsContent'; import useConfirm from '../../../../common/DialogBox/DialogBox'; import theme from '@devlaunchers/components/styles/theme'; +import { agent } from '@devlaunchers/utility'; +import { cleanData, cleanIdeaForPost } from '../../../../../utils/StrapiHelper'; const IdeaSettingsCard = ({ card }) => { - let { userData } = useUserDataContext(); - - const router = useRouter(); - const [cardStatus, setCardStatus] = useState(card.status); - const [disabling, setDisabling] = useState(false); - const [archiveButtonText, setArchiveButtonText] = useState("ARCHIVE"); - const [reactiveButtonText, setReactiveButtonText] = useState("REACTIVE"); - const [deleteButtonText, setDeleteButtonText] = useState("DELETE"); - - React.useEffect(() => { - if (card.status == "archived") { - setDisabling(true); - } - }, []); - - const [ArchiveIdea, confirmArchive] = useConfirm( - ["Archive your idea", '', ''], - 'This action will pause your idea and you can reactivate it via your dashboard.', - ['primary alternative', 'archive', 'cancel'], - ); - - const [ArchiveFailure, confirmArchiveFailure] = useConfirm( - ['Unable to archive your idea', '', ''], - 'Please try again.', - ['primary', 'close'], - ); - - const [ArchiveSuccess, confirmArchiveSuccess] = useConfirm( - ['You idea was archived successfully', 'Success', ''], - 'Your idea is archived and it can be reactivated anytime via your dashboard.', - ['alternative primary', 'browse ideas', 'dashboard'], - ); - - const [ReactivateFailure, confirmReactivateFailure] = useConfirm( - ['Unable to reactivate your idea', '', ''], - 'Please try again.', - ['primary', 'close'], - ); - - const [DeleteIdea, confirmDelete] = useConfirm( - ["You are about to delete your Idea", 'Error', theme.colors.ERROR_500], - "This action can't be undone! Are you sure you want to proceed?", - ['primary alternative', 'delete', 'cancel'], - ); - - const [DeleteFailure, confirmDeleteFailure] = useConfirm( - ['Unable to delete your idea', '', ''], - 'Please try again.', - ['primary', 'close'], - ); - - const [DeleteSuccess, confirmDeleteSuccess] = useConfirm( - ['You idea was deleted successfully', 'Success', ''], - 'Your idea workshopping page is no longer accessible.', - ['alternative primary', 'browse ideas', 'submit new idea'], - ); - - const clickEdit = () => { - router.push(`/ideaspace/edit/${card.id}`); + let { userData } = useUserDataContext(); + + const router = useRouter(); + const [cardStatus, setCardStatus] = useState(card.status); + const [disabling, setDisabling] = useState(false); + const [archiveButtonText, setArchiveButtonText] = useState('ARCHIVE'); + const [reactiveButtonText, setReactiveButtonText] = useState('REACTIVE'); + const [deleteButtonText, setDeleteButtonText] = useState('DELETE'); + + React.useEffect(() => { + if (card.status == 'archived') { + setDisabling(true); } - - const clickArchive = async () => { - setCardStatus(card["status"]); - if (await confirmArchive()) { - card["status"] = "archived"; - setArchiveButtonText(`WAIT`); - - try { - const res = await axios.put( - `${process.env.NEXT_PUBLIC_STRAPI_URL}/idea-cards/${card.id}`, - card - ); - - if (res.status === 200) { - setArchiveButtonText(`ARCHIVE`); - setDisabling(true); - if (await confirmArchiveSuccess()) { - router.push(`/ideaspace/dashboard`); - } else { - router.push(`/ideaspace/browse`); - } - } - } catch (error) { - card["status"] = cardStatus; - confirmArchiveFailure(); - setArchiveButtonText(`ARCHIVE`); - } + }, []); + + const [ArchiveIdea, confirmArchive] = useConfirm( + ['Archive your idea', '', ''], + 'This action will pause your idea and you can reactivate it via your dashboard.', + ['primary alternative', 'archive', 'cancel'] + ); + + const [ArchiveFailure, confirmArchiveFailure] = useConfirm( + ['Unable to archive your idea', '', ''], + 'Please try again.', + ['primary', 'close'] + ); + + const [ArchiveSuccess, confirmArchiveSuccess] = useConfirm( + ['You idea was archived successfully', 'Success', ''], + 'Your idea is archived and it can be reactivated anytime via your dashboard.', + ['alternative primary', 'browse ideas', 'dashboard'] + ); + + const [ReactivateFailure, confirmReactivateFailure] = useConfirm( + ['Unable to reactivate your idea', '', ''], + 'Please try again.', + ['primary', 'close'] + ); + + const [DeleteIdea, confirmDelete] = useConfirm( + ['You are about to delete your Idea', 'Error', theme.colors.ERROR_500], + "This action can't be undone! Are you sure you want to proceed?", + ['primary alternative', 'delete', 'cancel'] + ); + + const [DeleteFailure, confirmDeleteFailure] = useConfirm( + ['Unable to delete your idea', '', ''], + 'Please try again.', + ['primary', 'close'] + ); + + const [DeleteSuccess, confirmDeleteSuccess] = useConfirm( + ['You idea was deleted successfully', 'Success', ''], + 'Your idea workshopping page is no longer accessible.', + ['alternative primary', 'browse ideas', 'submit new idea'] + ); + + const clickEdit = () => { + router.push(`/ideaspace/edit/${card.id}`); + }; + + const clickArchive = async () => { + setCardStatus(card['status']); + if (await confirmArchive()) { + card['status'] = 'archived'; + setArchiveButtonText(`WAIT`); + + try { + const res = putIdea(); + + if (res.status === 200) { + setArchiveButtonText(`ARCHIVE`); + setDisabling(true); + if (await confirmArchiveSuccess()) { + router.push(`/ideaspace/dashboard`); + } else { + router.push(`/ideaspace/browse`); + } } + } catch (error) { + card['status'] = cardStatus; + confirmArchiveFailure(); + setArchiveButtonText(`ARCHIVE`); + } } - - const clickReactivate = async () => { - card["status"] = "workshopping"; - setReactiveButtonText(`WAIT`); - - try { - const res = await axios.put( - `${process.env.NEXT_PUBLIC_STRAPI_URL}/idea-cards/${card.id}`, - card - ); - - if (res.status === 200) { - setReactiveButtonText(`REACTIVE`); - setDisabling(false); - } - } catch (error) { - card["status"] = "archived"; - confirmReactivateFailure(); - setReactiveButtonText(`REACTIVE`); - } + }; + + const clickReactivate = async () => { + card['status'] = 'workshopping'; + setReactiveButtonText(`WAIT`); + + try { + const res = putIdea(); + + if (res.status === 200) { + setReactiveButtonText(`REACTIVE`); + setDisabling(false); + } + } catch (error) { + card['status'] = 'archived'; + confirmReactivateFailure(); + setReactiveButtonText(`REACTIVE`); } - - const clickDelete = async () => { - setCardStatus(card["status"]); - if (await confirmDelete()) { - card["status"] = "deleted"; - setDeleteButtonText(`WAIT`); - - try { - const res = await axios.put( - `${process.env.NEXT_PUBLIC_STRAPI_URL}/idea-cards/${card.id}`, - card - ); - if (res.status === 200) { - setDeleteButtonText(`DELETE`); - if (await confirmDeleteSuccess()) { - router.push(`/ideaspace/submit`); - } else { - router.push(`/ideaspace/browse`); - } - } - } catch (error) { - card["status"] = cardStatus; - confirmDeleteFailure(); - setDeleteButtonText(`DELETE`); - } + }; + + const clickDelete = async () => { + setCardStatus(card['status']); + if (await confirmDelete()) { + card['status'] = 'deleted'; + setDeleteButtonText(`WAIT`); + + try { + const res = putIdea(); + + if (res.status === 200) { + setDeleteButtonText(`DELETE`); + if (await confirmDeleteSuccess()) { + router.push(`/ideaspace/submit`); + } else { + router.push(`/ideaspace/browse`); + } } + } catch (error) { + card['status'] = cardStatus; + confirmDeleteFailure(); + setDeleteButtonText(`DELETE`); + } } - - if (card.author?.id !== userData.id) { - return null; - } - - return ( - - -

Idea settings

-
- - -
- {card.status == "archived" ? - - : - - } - -
- - - - - - - - - - - -
- ); + }; + + const putIdea = async () => { + const id = card.id; + const cardForPut = cleanIdeaForPost(card); + return cleanData(await agent.Ideas.put(id, cardForPut)); + }; + + if (card.author?.id !== userData.id) { + return null; + } + + return ( + + +

Idea settings

+
+ + +
+ {card.status == 'archived' ? ( + + ) : ( + + )} + +
+ + + + + + + + + + + +
+ ); }; -export default IdeaSettingsCard; \ No newline at end of file +export default IdeaSettingsCard; diff --git a/apps/ideaspace/src/utils/StrapiHelper.js b/apps/ideaspace/src/utils/StrapiHelper.js index af8f08063..1dc3faae8 100644 --- a/apps/ideaspace/src/utils/StrapiHelper.js +++ b/apps/ideaspace/src/utils/StrapiHelper.js @@ -1,7 +1,21 @@ export function cleanData(data) { - return { id: data.id, ...data?.attributes }; + return { id: data.id, ...data?.attributes }; } export function cleanDataList(dataList) { - return dataList.map(data => cleanData(data)); -} \ No newline at end of file + return dataList.map((data) => cleanData(data)); +} + +export function packageData(data) { + const result = { data }; + delete result.data.id; + return result; +} + +export function cleanIdeaForPost(card) { + let idea = packageData(card); + idea.data.author = idea.data.author.id; + idea.data.ideaOwner = idea.data.ideaOwner.id; + idea.data.comments = idea.data.comments.data.map((c) => c.id); + return idea; +} diff --git a/packages/UI/.storybook/main.ts b/packages/UI/.storybook/main.ts index b825666bf..ebd51f5e7 100644 --- a/packages/UI/.storybook/main.ts +++ b/packages/UI/.storybook/main.ts @@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook/nextjs'; import path, { dirname, join } from 'path'; const config: StorybookConfig = { - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)', '../src/**/*.mdx'], + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], staticDirs: ['../public'], addons: [ '@storybook/addon-essentials', @@ -10,10 +10,10 @@ const config: StorybookConfig = { '@storybook/addon-links', '@storybook/addon-mdx-gfm', '@storybook/addon-designs', - 'storybook-addon-pseudo-states' + 'storybook-addon-pseudo-states', ].map(getAbsolutePath), framework: { - name: getAbsolutePath('@storybook/nextjs') as "@storybook/nextjs", + name: getAbsolutePath('@storybook/nextjs') as '@storybook/nextjs', options: {}, }, webpackFinal: async (config) => { @@ -38,17 +38,17 @@ const config: StorybookConfig = { // pull radix-ui props declaration files if (prop.parent?.fileName.includes('@radix-ui')) return true; // ignore rest of node_modules props declaration file - return (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true) + return prop.parent ? !/node_modules/.test(prop.parent.fileName) : true; }, }, reactDocgen: 'react-docgen-typescript', // skipBabel: true, check: true, - } + }, }; function getAbsolutePath(value) { return dirname(require.resolve(join(value, 'package.json'))); } -export default config; \ No newline at end of file +export default config; diff --git a/packages/UI/.storybook/preview-head.html b/packages/UI/.storybook/preview-head.html index 171fd5946..4526d44fb 100644 --- a/packages/UI/.storybook/preview-head.html +++ b/packages/UI/.storybook/preview-head.html @@ -1,13 +1,13 @@ - - - - + + + + diff --git a/packages/UI/CONTRIBUTING.md b/packages/UI/CONTRIBUTING.md index 7827fbd78..1122a8bf5 100644 --- a/packages/UI/CONTRIBUTING.md +++ b/packages/UI/CONTRIBUTING.md @@ -1,62 +1,97 @@ # Getting started with the Platform Enablement Team -dev-launchers-platform is a mono repo using yarn. All yarn script lines need to be run in the root folder. +dev-launchers-platform is a mono repo using yarn. All yarn script lines need to be run in the root folder. + +## 🔎 What's inside? + +A quick look at the top-level files and directories included in this package. + + . + ├── node_modules + ├── public + ├── src + ├── .gitignore + ├── .env + ├── LICENSE + ├── package.json + ├── CONTRIBUTING.md + └── README.md + +1. **`node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages). + +2. **`public`**: This directory will contain static files that can be accessed directly via the browser using a path relative to storybook base URL. + +3. **`src`**: This directory will contain all of the code related to what you will see on your application. + +4. **`.env`**: This file will contain the necessary environment variables for your application. + +5. **`.gitignore`**: This file tells git which files it should not track or maintain during the development process of your project. + +6. **`LICENSE`**: The template is licensed under the MIT licence. + +7. **`package.json`**: Standard manifest file for Node.js projects, which typically includes project specific metadata (such as the project's name, the author among other information). It's based on this file that npm will know which packages are necessary to the project. + +8. **`README.md`**: A text file containing useful reference information about the project. + +9. **`CONTRIBUTING.md`**: A markdown file containing useful guides for contributing to the design system effectively. + +## Contribute + +If you encounter an issue with the components found in this system, we encourage you to open an issue with the Platform Enablement label or simply click [here](https://github.com/dev-launchers/dev-launchers-platform/issues/new?label=%22Platform%20Enablement%22). + +## Learning Storybook + +1. Read the offical introductory tutorial over at [Storybook tutorials](https://storybook.js.org/tutorials/intro-to-storybook/react/en/get-started/). +2. Learn how to transform your component libraries into design systems in our [Design Systems for Developers](https://storybook.js.org/tutorials/design-systems-for-developers/) tutorial. +3. See official documentation for [Storybook](https://storybook.js.org/). ## Installing and quick started -1. install yarn, below are several ways to install. - - In a terminal with admin run ```$ corepack enable``` - - ```$ npm install --global yarn``` -2. clone the repo @ https://github.com/dev-launchers/dev-launchers-platform -3. After cloning repo, navigate to /dev-launchers-platform -4. ```$ yarn install``` in the root folder to install dependencies -5. Open a new terminal and run ```$ yarn workspace @devlaunchers/tailwind dev```. to start tailwind constructor. -5. Open a 2nd terminal and run ```$ yarn workspace @devlaunchers/components storybook``` to start storybook. -7. Start Development work. +1. install yarn, below are several ways to install. -### Yarn scripts for this team + - In a terminal with admin run `$ corepack enable` -``` -$ yarn workspace @devlaunchers/tailwind dev -$ yarn workspace @devlaunchers/components storybook -$ yarn workspace @devlaunchers/components typecheck -``` -More scripts are located in the package.json file. +2. clone the repo @ https://github.com/dev-launchers/dev-launchers-platform +3. After cloning repo, navigate to /dev-launchers-platform +4. `$ yarn install` in the root folder to install dependencies +5. Open a new terminal and run `$ yarn workspace @devlaunchers/tailwind dev`. to start tailwind constructor. +6. Open a 2nd terminal and run `$ yarn workspace @devlaunchers/components storybook` to start storybook. +7. Start Development work. ### Installing packages -To install a package into a specific workspace: +To install a package to the design system: $ yarn workspace @devlaunchers/ add #### Installing Radix-ui components -Radix-ui components need to be installed individually, if you are not able to import @radix-ui follow the command below to install in devlaunchers components workspace. +> Radix UI is an open-source UI component library for building high-quality, accessible design systems and web apps. +> Radix Primitives is a low-level UI component library with a focus on accessibility, customization and developer experience. - $ yarn workspace @devlaunchers/components add +We use these low level UI components as the base layer of our design system, so when you get to build a component from our [figma style guide file](https://www.figma.com/file/EwzuhhvTulvFRMvhTD5VAh/DL-Universal-Design-System) make sure to use radix ui whenever possible! -Below is the command to install radix-ui/react-checkbox +Below is the command to install radix-ui/react-checkbox for example $ yarn workspace @devlaunchers/components add @radix-ui/react-checkbox - # Boards and issues. ### Issues in github -When looking at issues in github, you will want to filter by Platform Enablement. +When looking at issues in github, you will want to filter by Platform Enablement. https://github.com/dev-launchers/dev-launchers-platform/issues?q=is%3Aopen+is%3Aissue+label%3A%22Platform+Enablement%22 ### Zenhub -Platform Enablement Team uses zenhub as it's board. If this link does not work msg lead to invite you to the team. +Platform Enablement Team uses zenhub as it's board. If this link does not work contact enjoy2live on discord to invite you to the team. https://app.zenhub.com/workspaces/platform-enablement-63529f02029ee50018fe58c6/board ## Git branch checkout flow -We will be working out of development/components. +We will be working out of development/components. $ git checkout development/components @@ -66,12 +101,11 @@ We will be working out of development/components. $ git checkout -b components/newBranchName - ## Figma Go to universal Figma @: - https://www.figma.com/file/EwzuhhvTulvFRMvhTD5VAh/DL-Universal-Design-System?type=design&t=w1PSPgQunxcd19Bz-6 + https://www.figma.com/file/EwzuhhvTulvFRMvhTD5VAh/DL-Universal-Design-System - All component designs will be coming from the universal UI library. - Make sure dev mode is toggled in Figma. @@ -79,23 +113,21 @@ Go to universal Figma @: ## Vscode extensions -```extensions.json``` in this workspace will recommend the follow extensions when you first open the workspace: +`extensions.json` in this workspace will recommend the follow extensions when you first open the workspace: 1. Tailwind css intellisense 2. Eslint 3. ES7 + React/redux/React-native snippets. 4. Figma for vs code - - ### Storybook snippet By typing "story" in an empty file, you can get the below snippet as a starter for storybook files. When thes snippet is imported it will have selected all the parts needs to type in your Component. -``` -import type { Meta, StoryObj } from '@storybook/react'; +```jsx +import type { Meta, StoryObj } from "@storybook/react"; -import Component from './Component'; +import Component from "./Component"; const meta: Meta = { component: Component, @@ -114,7 +146,7 @@ export const Primary: Story = { }; ``` -## Storybook & tailwind dev environment. +## Storybook & tailwind dev environment. In a terminal, in order to get tailwind classes in your project you will need to run the dev command. @@ -124,55 +156,43 @@ Storybook will be the primary way you will see your design changes. Running "com $ yarn workspace @devlaunchers/components storybook - - ## Creating new components in project. When creating the folder/files in src/components : -- The Project Components folder should match the Figma design location - - Example "src/components/Checkbox" +- The Project Components folder should match the Figma design location + - Example "src/components/Checkbox" - Project Components names should match the design Name - "Capitalized" - - Example "src/components/Checkbox/Checkbox.tsx" + - Example "src/components/Checkbox/Checkbox.tsx" - Project components need a #.stories.tsx to work with storybook. - find a template or copy from another stories.tsx -- Create an index.ts file for exporting the tsx files. - ``` - export { default as Alert } from './Alert'; - export type {AlertProp} from './Alert' - ``` - - -## Adding assets - -For .tsx assets check the need too re-export all components into an index.ts for exporting in the folder that it is living in. - -``` -packages/UI/src/assets/icons/index.ts -``` - +- Create an index.ts file for exporting the tsx files. + ``` + export { default as Alert } from './Alert'; + export type {AlertProp} from './Alert' + ``` ## Jsdocs auto intergration with storybook. -Attempt to put all documentation via jsdocs. Storybook will auto import depending on the location of the jsdocs. Make it so documenation is only in one location in code, and both storybook and jsdocs draw from the same location. - -As a example - Tabs story in storybook will grab this jsdocs, at the same time it will be shown by a description in mouse hover. +Try to always add jsdocs description to each prop of your component type defination, this will allow developers to know how use the component props right within their code editor and storybook will also be able to pick it up and auto document the component you built for you. -![Example Image](example.png) +
+ +
## Submit the branch with a new pull request. In git bash, you will want to do the git push flow. - - git add . - - Git commit -m "describes what you worked on" - - git push origin branch +- git add . +- git commit -m "describes what you worked on" +- git push origin branch Go to github.com and make sure you are logged in and in the right repo. https://github.com/dev-launchers/dev-launchers-platform - - Go to "Pull Requests" tab. - - Create new "Pull request" - - the base branch is "development/components" - - the compare branch is your new branch - - Rest on technical lead to merge or give feedback. +- Go to "Pull Requests" tab. +- Create new "Pull request" +- the base branch is "development/components" +- the compare branch is your new branch +- Rest on technical lead to merge or give feedback. diff --git a/packages/UI/README.md b/packages/UI/README.md index 38e90dde4..33dc6b82f 100644 --- a/packages/UI/README.md +++ b/packages/UI/README.md @@ -1,83 +1,39 @@ -

- - Chromatic + + Devlaunchers Logo

- Chromatic's Design Systems for Developers tutorial template + Devlaunchers Design System

-This template ships with the main React configuration files you'll need to get up and running fast. +Components, styles, and utilities are the core of the Devlaunchers brand shared across its websites. They're most notably used on [devlaunchers.org](https://devlaunchers.org) but are also found on our internal websites and tools. -## 🚅 Quick start +This storybook represents components found in the Devlaunchers monorepo, specifically the [@devlaunchers/components](https://github.com/dev-launchers/dev-launchers-platform/tree/master/packages/UI) package and derived from the amazing work of the universal design team's [figma file](https://www.figma.com/file/EwzuhhvTulvFRMvhTD5VAh/DL-Universal-Design-System). -1. **Create the application.** +Its organization roughly aligns with variations of [Atomic Design](https://bradfrost.com/blog/post/atomic-web-design/). - Use [degit](https://github.com/Rich-Harris/degit) to get this template. - - ```shell - # Clone the template - npx degit chromaui/learnstorybook-design-system-template learnstorybook-design-system - ``` +## 🚀 Quick start 1. **Install the dependencies.** - Navigate into your new site’s directory and install the necessary dependencies. - ```shell - # Navigate to the directory - cd learnstorybook-design-system/ - - # Install the dependencies yarn ``` -1. **Open the source code and start editing!** - - Open the `learnstorybook-design-system` directory in your code editor of choice and building your first component! - -## 🔎 What's inside? - -A quick look at the top-level files and directories included with this template. - - . - ├── node_modules - ├── public - ├── src - ├── .gitignore - ├── .env - ├── LICENSE - ├── package.json - ├── yarn.lock - └── README.md +1. **Spin up a development server.** + In order to see how to use a certain component you have to start a local development server of storybook. -1. **`node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages). - -2. **`public`**: This directory will contain the development and production build of the site. - -3. **`src`**: This directory will contain all of the code related to what you will see on your application. - -4. **`.env`**: This file will contain the necessary environment variables for your application. - -5. **`.gitignore`**: This file tells git which files it should not track or maintain during the development process of your project. - -6. **`LICENSE`**: The template is licensed under the MIT licence. - -7. **`package.json`**: Standard manifest file for Node.js projects, which typically includes project specific metadata (such as the project's name, the author among other information). It's based on this file that npm will know which packages are necessary to the project. + ```shell + yarn workspace @devlaunchers/components storybook + ``` -8. **`yarn.lock`**: This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(Do not change it manually).** +1. **Start using components!** -9. **`README.md`**: A text file containing useful reference information about the project. + Open http://localhost:6006 in your browser (should happen automatically) and start reading the documentation from within storybook. ## Contribute -If you encounter an issue with the template, we encourage you to open an issue in this template's repository. - -## Learning Storybook - -1. Read our introductory tutorial over at [Storybook tutorials](https://storybook.js.org/tutorials/intro-to-storybook/react/en/get-started/). -2. Learn how to transform your component libraries into design systems in our [Design Systems for Developers](https://storybook.js.org/tutorials/design-systems-for-developers/) tutorial. -2. See our official documentation at [Storybook](https://storybook.js.org/). \ No newline at end of file +If you encounter an issue with the components found in this system, we encourage you to open an issue with the Platform Enablement label or simply click [here](https://github.com/dev-launchers/dev-launchers-platform/issues/new?label=%22Platform%20Enablement%22). diff --git a/packages/UI/example.png b/packages/UI/example.png deleted file mode 100644 index 3271be235..000000000 Binary files a/packages/UI/example.png and /dev/null differ diff --git a/packages/UI/package.json b/packages/UI/package.json index 608c16b9a..b792d19c8 100644 --- a/packages/UI/package.json +++ b/packages/UI/package.json @@ -10,6 +10,7 @@ "@radix-ui/react-checkbox": "1.0.4", "@radix-ui/react-dialog": "1.0.5", "@radix-ui/react-dropdown-menu": "2.0.6", + "@radix-ui/react-progress": "1.0.3", "@radix-ui/react-switch": "1.0.3", "@radix-ui/react-tabs": "1.0.4", "axios": "^0.27.2", @@ -21,6 +22,7 @@ "iso8601-duration": "2.1.2", "lucide-react": "0.314.0", "next": "^12.2.3", + "next-share": "0.27.0", "polished": "^4.2.2", "react": "^17.0.2", "react-burger-menu": "^3.0.8", diff --git a/packages/UI/public/android-chrome-192x192.png b/packages/UI/public/android-chrome-192x192.png new file mode 100644 index 000000000..cfd837b80 Binary files /dev/null and b/packages/UI/public/android-chrome-192x192.png differ diff --git a/packages/UI/public/android-chrome-512x512.png b/packages/UI/public/android-chrome-512x512.png new file mode 100644 index 000000000..ed0b6790a Binary files /dev/null and b/packages/UI/public/android-chrome-512x512.png differ diff --git a/packages/UI/public/apple-touch-icon.png b/packages/UI/public/apple-touch-icon.png new file mode 100644 index 000000000..bc28234f8 Binary files /dev/null and b/packages/UI/public/apple-touch-icon.png differ diff --git a/packages/UI/public/browserconfig.xml b/packages/UI/public/browserconfig.xml new file mode 100644 index 000000000..ba08c67f4 --- /dev/null +++ b/packages/UI/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #ff8000 + + + diff --git a/packages/UI/public/favicon-16x16.png b/packages/UI/public/favicon-16x16.png new file mode 100644 index 000000000..6b2673ac9 Binary files /dev/null and b/packages/UI/public/favicon-16x16.png differ diff --git a/packages/UI/public/favicon-32x32.png b/packages/UI/public/favicon-32x32.png new file mode 100644 index 000000000..41ed327c9 Binary files /dev/null and b/packages/UI/public/favicon-32x32.png differ diff --git a/packages/UI/public/favicon.ico b/packages/UI/public/favicon.ico index a11777cc4..48b8fa56e 100644 Binary files a/packages/UI/public/favicon.ico and b/packages/UI/public/favicon.ico differ diff --git a/packages/UI/public/images/logo-monogram.png b/packages/UI/public/images/logo-monogram.png new file mode 100644 index 000000000..8d968e842 Binary files /dev/null and b/packages/UI/public/images/logo-monogram.png differ diff --git a/packages/UI/public/index.html b/packages/UI/public/index.html index 1837da27f..82c265131 100644 --- a/packages/UI/public/index.html +++ b/packages/UI/public/index.html @@ -1,20 +1,50 @@ - - - - + + + + + - + + + + + + + + + - React App + Dev Launchers Design System + - +