From 08c54a910fa25cc6b6a7ea5584967729ba736d71 Mon Sep 17 00:00:00 2001 From: Samantha Date: Sun, 22 Jan 2023 01:42:25 -0600 Subject: [PATCH 01/72] Adding Spanish translation to the README --- i18n/README.es.md | 346 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 i18n/README.es.md diff --git a/i18n/README.es.md b/i18n/README.es.md new file mode 100644 index 0000000000..0139bdd655 --- /dev/null +++ b/i18n/README.es.md @@ -0,0 +1,346 @@ +

+ infisical + infisical +

+

+

Herramienta simple de código abierto cifrado de extremo a extremo (E2EE) para gestionar secretos y configuraciones dentro de su equipo e infraestructura.

+

+ +

+ Slack | + Infisical Cloud | + Self-Hosting | + Documentación | + Sitio web +

+ +

+ + Medusa is released under the MIT license. + + + PRs welcome! + + + git commit activity + + + Cloudsmith downloads + + + Slack community channel + + + Infisical Twitter + +

+ +Dashboard + +**[Infisical](https://infisical.com)** es una herramienta de código abierto que busca ayudar a equipos a gestionar y sincronizar secretos y configuraciones dentro de su flujo de trabajo e infraestructura. Está diseñada para ser simple y solo tomar minutos para implementar. + +- **[Tablero fácil de usar](https://infisical.com/docs/getting-started/dashboard/project)** para gestionar los secretos y configuraciones de su equipo dentro de proyectos +- **[Infraestructura de lenguaje común (CLI) independiente del lenguaje](https://infisical.com/docs/cli/overview)** que extrae e inyecta secretos y configuraciones a su flujo de trabajo local +- **[Control total sobre sus datos:](https://infisical.com/docs/self-hosting/overview)** alójelos en cualquier infraestructura +- **Navega múltiples entornos** por proyecto (ej. Desarrollo, evaluación, producción, etc.) +- **Mando manual** para secretos y configuraciones +- **[Integraciones](https://infisical.com/docs/integrations/overview)** con CI/CD e infraestructura de producción +- **[API de Infisical:](https://infisical.com/docs/api-reference/overview/introduction)** administra secretos a través de solicitudes HTTPS a la plataforma +- **[Control de versiones ](https://infisical.com/docs/getting-started/dashboard/versioning)** para ver el historial de cambios de cualquier secreto +- **[Registros de actividad](https://infisical.com/docs/getting-started/dashboard/audit-logs)** para documentar cada acción tomada en el proyecto +- **[Recuperación de secretos en el momento](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** para retroceder a cualquier instancia de alguno +- 🔜 **Implementación de 1 clic** para Digital Ocean y Heroku +- 🔜 **Autenticación/Autorización** para proyectos (controles de lectura/escritura próximamente) +- 🔜 **Rotación automática de secretos** +- 🔜 **Autenticación de dos factores** +- 🔜 **Integraciones con Slack y MS Teams** + +Y más. + +## 🚀 Para empezar + +Para empezar rápidamente visita nuestra [guía de inicio](https://infisical.com/docs/getting-started/introduction). + +

+ + + +

+ +## 🔥 ¿En qué es bueno? + +Infisical hace la gestión de secretos simple y está cifrada de extremo a extremo de manera predeterminada. Tenemos la misión de hacerla más accesible a todos los desarrolladores, no solo los equipos de seguridad. + +Según un [reporte](https://www.ekransystem.com/en/blog/secrets-management), solo el 10% de las organizaciones utilizan soluciones para gestionar secretos a pesar de que todas usan secretos digitales en cierta medida. + +Si está interesado en la eficiencia y la seguridad, Infisical es para ti. + +Actualmente estamos trabajando duro para hacer Infisical más extenso. ¿Necesitas una integración o quieres una nueva función? Siente libre de [crear un issue](https://github.com/Infisical/infisical/issues) o [contribuir](https://infisical.com/docs/contributing/overview) directamente al repositorio. + +## 🌱 Contribuir + +Sea de manera pequeña o grande, nos encantan las contribuciones ❤️ Cheque nuestra guía de [cómo empezar](https://infisical.com/docs/contributing/overview). + +¿No está seguro de dónde empezar? Usted puede: + +- ¡[Agendar una sesión gratis, sin presión con uno de nuestros integrantes](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! (inglés) +- Unesé a nuestro Slack y preguntenos ahí (inglés) + +## 💚 Soporte y comunidad + +- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (Para discusiones en vivo con la comunidad y el equipo de Infisical) +- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (Para ayudar en construir y profundizar conversaciones acerca de funciones) +- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (Para cualquier bug o error que encuentre usando Infisical) +- [Twitter](https://twitter.com/infisical) (Obtén las noticias rápidamente) + +## 🐥 Estatus + +- [x] Alpha público: Cualquiera puede registrarse en [infisical.com](https://infisical.com) pero ténganos paciencia, hay problemas y apenas estamos comenzando. +- [ ] Beta público: Suficientemente estable para la mayoría de los casos de uso no empresariales. +- [ ] Público: Listo para producción. + +Estamos actualmente en Alpha público. + +## 🔌 Integraciones + +Actualmente estamos sentando bases y construyendo [integraciones](https://infisical.com/docs/integrations/overview) para que los secretos se puedan sincronizar en todas partes. ¡Cualquier ayuda es bienvenida! :) + + + + + + + + + + +
Plataformas Marcos
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + ✔️ Docker + + + + ✔️ Docker Compose + + + + ✔️ Heroku + +
+ + ✔️ Vercel + + + + ✔️ Kubernetes + + + 🔜 Fly.io +
+ 🔜 AWS + + + ✔️ GitHub Actions + + + 🔜 Railway +
+ 🔜 GCP + + 🔜 GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) + + 🔜 CircleCI (https://github.com/Infisical/infisical/issues/91) +
+ 🔜 Jenkins + + 🔜 Digital Ocean + + 🔜 Azure +
+ 🔜 TravisCI + + + ✔️ Netlify + + + 🔜 Railway +
+ 🔜 Bitbucket + + 🔜 Supabase + + 🔜 Render (https://github.com/Infisical/infisical/issues/132) +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + ✔️ React + + + + ✔️ Express + +
+ + ✔️ Gatsby + + + + ✔️ Flask + +
+ + ✔️ Django + + + + ✔️ Laravel + +
+ + ✔️ NestJS + + + + ✔️ Remix + +
+ + ✔️ Next.js + + + + ✔️ Vite + +
+ + ✔️ Vue + + + + ✔️ Ruby on Rails + +
+ + ✔️ Fiber + + + + ✔️ Nuxt + +
+ + ✔️ .NET + + + And more... +
+ +
+ +## 🏘 Código abierto vs pagado + +Este repositorio es enteramente licenciado con MIT, con la excepción del directorio `ee` que contendrá funciones empresariales premium que requerirán una licencia de Infisical en el futuro. Actualmente estamos enfocados en desarrollar primero ofertas no empresariales que deberían adaptarse a la mayoría de los casos de uso. + +## 🛡 Seguridad + +¿Quiere reportar alguna vulnerabilidad en seguridad? Por favor, no lo publique en Github issues. En su lugar consulte nuestro archivo de [SECURITY.md](./SECURITY.md). + +## 🚨 Manténgase al tanto + +Infisical se lanzó oficialmente como v.1.0 el 21 de noviembre de 2022. Hay muchas funciones nuevas que llegan con mucha frecuencia. Mire los **lanzamientos** de este repositorio para recibir notificaciones sobre futuras actualizaciones: + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + +## 🦸 Contribuyentes + +[//]: contributor-faces + + + + + + + +## 🌎 Traducciones + +Infisical está actualmente disponible en inglés, coreano, francés y portugués (Brasil). ¡Ayúdanos a traducir Infisical a tu idioma! + +Puedes encontrar toda la información en [este issue](https://github.com/Infisical/infisical/issues/181). \ No newline at end of file From 4db4c172c14c8370bd6cf1ee8e685219e8f81d92 Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Sun, 22 Jan 2023 00:35:36 -0800 Subject: [PATCH 02/72] Fix the start guide redirect issue --- backend/src/variables/integration.ts | 2 +- frontend/src/pages/home/[id].tsx | 75 +++++++++++++--------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/backend/src/variables/integration.ts b/backend/src/variables/integration.ts index 7cecb54c2c..872b3e096d 100644 --- a/backend/src/variables/integration.ts +++ b/backend/src/variables/integration.ts @@ -90,7 +90,7 @@ const INTEGRATION_OPTIONS = [ name: 'Fly.io', slug: 'flyio', image: 'Flyio.svg', - isAvailable: true, + isAvailable: false, type: 'pat', clientId: '', docsLink: '' diff --git a/frontend/src/pages/home/[id].tsx b/frontend/src/pages/home/[id].tsx index 72ed8bb4d3..9ec1199732 100644 --- a/frontend/src/pages/home/[id].tsx +++ b/frontend/src/pages/home/[id].tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; -import Link from 'next/link'; import { useRouter } from 'next/router'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faSlack } from '@fortawesome/free-brands-svg-icons'; @@ -40,47 +39,45 @@ const learningItem = ({ }: ItemProps): JSX.Element => { if (link) { return ( - - +
null} + role="button" + tabIndex={0} + onClick={async () => { + if (userAction && userAction !== 'first_time_secrets_pushed') { + await registerUserAction({ + action: userAction + }); + } + }} + className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" > -
null} - role="button" - tabIndex={0} - onClick={async () => { - if (userAction && userAction !== 'first_time_secrets_pushed') { - await registerUserAction({ - action: userAction - }); - } - }} - className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" - > -
- - {complete && ( -
- -
- )} -
-
{text}
-
{subText}
+
+ + {complete && ( +
+
+ )} +
+
{text}
+
{subText}
-
- {complete ? 'Complete!' : `About ${time}`} -
- {complete &&
}
-
- +
+ {complete ? 'Complete!' : `About ${time}`} +
+ {complete &&
} +
+ ); } return ( @@ -157,7 +154,7 @@ export default function Home() { icon: faHandPeace, time: '3 min', userAction: 'intro_cta_clicked', - link: 'https://www.youtube.com/watch?v=JS3OKYU2078' + link: 'https://www.youtube.com/watch?v=3F7FNYX94zA' })} {learningItem({ text: 'Add your secrets', From 4b4e8e2bfcb62d66b0c6c8f54ae529af0701cc81 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Sun, 22 Jan 2023 12:49:50 -0800 Subject: [PATCH 03/72] Update docker integration --- docs/integrations/platforms/docker.mdx | 30 ++++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/integrations/platforms/docker.mdx b/docs/integrations/platforms/docker.mdx index 6f08c9ec84..2a2baa9b1d 100644 --- a/docs/integrations/platforms/docker.mdx +++ b/docs/integrations/platforms/docker.mdx @@ -31,25 +31,22 @@ Infisical can be used in a Dockerfile to inject environment variables into a Doc -## Modify the start command in your Dockerfile + ## Modify your Dockerfile start command -```dockerfile -CMD ["infisical", "--env=[env]", "projectId=[projectId]", "run", "---", "[your application start command]"] + To make your Docker container consume Infisical secrets, you can start your application with Infisical. + This will automatically pull the necessary secrets and make them available to your application as if they were natively exposed within the container. -# example -CMD ["infisical", "--env=prod", "projectId=62faf98ae0b05e83239b5da41", "run", "---", "npm run start"] -``` + ```dockerfile + CMD ["infisical", "run", "---", "[your application start command]"] -Required options: + # example with single single command + CMD ["infisical", "run", "---", "npm run start"] -| Option | Description | Default value | -| ------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | -| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | -| `--projectId` | Used to link a local project to the platform | `None` | + # example with multiple commands + CMD ["infisical", "run", "--command" "npm run start && ..."] + ``` -## Generate an Infisical Token - -[Generate an Infisical Token](../../getting-started/dashboard/token) and keep it handy. + View more options for the `run` command [here](../../cli/commands/run) ## Feed Docker your Infisical Token @@ -58,3 +55,8 @@ The CLI looks out for an environment variable called `INFISICAL_TOKEN`. If the t ```bash docker run --env INFISICAL_TOKEN=[token]... ``` + +## Generate an Infisical Token + +[Generate an Infisical Token](../../getting-started/dashboard/token) and keep it handy. + From a0f0ffe5666acc707864fdd8861d469857ccf8cc Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Sun, 22 Jan 2023 14:03:09 -0800 Subject: [PATCH 04/72] improve i-dev command --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9e1f5c3f61..7ef83d9486 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ up-dev: docker-compose -f docker-compose.dev.yml up --build i-dev: - infisical export && infisical export > .env && docker-compose -f docker-compose.dev.yml up --build + infisical run -- docker-compose -f docker-compose.dev.yml up --build up-prod: docker-compose -f docker-compose.yml up --build From 201c8352e3eb3f8e90ae553ca776d0f03a3dd45e Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Sun, 22 Jan 2023 16:50:45 -0800 Subject: [PATCH 05/72] fix typo in k8 self host --- docs/self-hosting/deployments/kubernetes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/self-hosting/deployments/kubernetes.mdx b/docs/self-hosting/deployments/kubernetes.mdx index 48dc8de076..27d7d4ec87 100644 --- a/docs/self-hosting/deployments/kubernetes.mdx +++ b/docs/self-hosting/deployments/kubernetes.mdx @@ -23,7 +23,7 @@ If you're less technical and looking for a hands-free experience with minimal ov Before you can deploy the Helm chart, you must fill out the required environment variables. To do so, please copy the below file to a `.yaml` file. Refer to the available [environment variables](../../self-hosting/configuration/envars) to learn more - + ```yaml ##### # INFISICAL K8 DEFAULT VALUES FIL From 68f1887d665958a7cf6ca3c70b831359ba0e85aa Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Thu, 19 Jan 2023 19:55:52 +0530 Subject: [PATCH 06/72] feat(ui): implemented button component --- frontend/package-lock.json | 51 +++++- frontend/package.json | 3 +- .../components/v2/Button/Button.stories.tsx | 71 ++++++++- frontend/src/components/v2/Button/Button.tsx | 148 +++++++++++++++++- frontend/src/components/v2/Button/index.tsx | 1 + frontend/src/components/v2/index.tsx | 1 + 6 files changed, 264 insertions(+), 11 deletions(-) create mode 100644 frontend/src/components/v2/index.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 44d791bb0c..cff1b80fb0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,8 +28,10 @@ "add": "^2.0.6", "axios": "^0.27.2", "axios-auth-refresh": "^3.3.3", + "class-variance-authority": "^0.4.0", "classnames": "^2.3.1", "cookies": "^0.8.0", + "cva": "npm:class-variance-authority@^0.4.0", "fs": "^0.0.1-security", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", @@ -9299,6 +9301,22 @@ "node": ">=0.10.0" } }, + "node_modules/class-variance-authority": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", + "funding": { + "url": "https://joebell.co.uk" + }, + "peerDependencies": { + "typescript": ">= 4.5.5 < 5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", @@ -9938,6 +9956,23 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" }, + "node_modules/cva": { + "name": "class-variance-authority", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", + "funding": { + "url": "https://joebell.co.uk" + }, + "peerDependencies": { + "typescript": ">= 4.5.5 < 5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -21135,7 +21170,7 @@ "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -28787,6 +28822,12 @@ } } }, + "class-variance-authority": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", + "requires": {} + }, "classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", @@ -29292,6 +29333,12 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" }, + "cva": { + "version": "npm:class-variance-authority@0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", + "requires": {} + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -37538,7 +37585,7 @@ "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true + "devOptional": true }, "uc.micro": { "version": "1.0.6", diff --git a/frontend/package.json b/frontend/package.json index 8c30f749ec..60b8eda85e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,7 +8,7 @@ "start:docker": "next build && next start", "lint": "eslint --fix --ext js,ts,tsx ./src", "type-check": "tsc --project tsconfig.json", - "storybook": "storybook dev -p 6006", + "storybook": "storybook dev -p 6006 -s ./public", "build-storybook": "storybook build" }, "dependencies": { @@ -37,6 +37,7 @@ "axios-auth-refresh": "^3.3.3", "classnames": "^2.3.1", "cookies": "^0.8.0", + "cva": "npm:class-variance-authority@^0.4.0", "fs": "^0.0.1-security", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", diff --git a/frontend/src/components/v2/Button/Button.stories.tsx b/frontend/src/components/v2/Button/Button.stories.tsx index 0e78b96491..51e58d0da1 100644 --- a/frontend/src/components/v2/Button/Button.stories.tsx +++ b/frontend/src/components/v2/Button/Button.stories.tsx @@ -1,3 +1,5 @@ +import { faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './Button'; @@ -6,7 +8,16 @@ const meta: Meta = { title: 'Components/Button', component: Button, tags: ['v2'], - argTypes: {} + argTypes: { + isRounded: { + defaultValue: true, + type: 'boolean' + }, + isFullWidth: { + defaultValue: false, + type: 'boolean' + } + } }; export default meta; @@ -18,3 +29,61 @@ export const Primary: Story = { children: 'Hello Infisical' } }; + +export const Secondary: Story = { + args: { + children: 'Hello Infisical', + colorSchema: 'secondary', + variant: 'outline' + } +}; + +export const Danger: Story = { + args: { + children: 'Hello Infisical', + colorSchema: 'danger', + variant: 'solid' + } +}; + +export const Plain: Story = { + args: { + children: 'Hello Infisical', + variant: 'plain' + } +}; + +export const Disabled: Story = { + args: { + children: 'Hello Infisical', + disabled: true + } +}; + +export const FullWidth: Story = { + args: { + children: 'Hello Infisical', + isFullWidth: true + } +}; + +export const Loading: Story = { + args: { + children: 'Hello Infisical', + isLoading: true + } +}; + +export const LeftIcon: Story = { + args: { + children: 'Hello Infisical', + leftIcon: + } +}; + +export const RightIcon: Story = { + args: { + children: 'Hello Infisical', + rightIcon: + } +}; diff --git a/frontend/src/components/v2/Button/Button.tsx b/frontend/src/components/v2/Button/Button.tsx index a1edb26bf7..f00d1d0a36 100644 --- a/frontend/src/components/v2/Button/Button.tsx +++ b/frontend/src/components/v2/Button/Button.tsx @@ -1,32 +1,166 @@ import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react'; +import { cva, VariantProps } from 'cva'; import { twMerge } from 'tailwind-merge'; type Props = { children: ReactNode; isDisabled?: boolean; + leftIcon?: ReactNode; + rightIcon?: ReactNode; // loading state isLoading?: boolean; - // various button sizes - size: 'sm' | 'md' | 'lg'; }; -export type ButtonProps = ButtonHTMLAttributes & Props; +const buttonVariants = cva( + [ + 'button', + 'transition-all', + 'font-medium', + 'cursor-pointer', + 'inline-flex items-center justify-center', + 'relative' + ], + { + variants: { + colorSchema: { + primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'], + secondary: ['bg-mineshaft-200', 'text-white', 'border-mineshaft-200'], + danger: ['bg-red', 'text-white', 'border-red'] + }, + variant: { + solid: '', + outline: ['bg-transparent', 'border', 'border-solid'], + plain: '' + }, + isDisabled: { + true: 'bg-opacity-70', + false: '' + }, + isFullWidth: { + true: 'w-full', + false: '' + }, + isRounded: { + true: 'rounded-md', + false: '' + }, + size: { + xs: ['text-xs', 'py-1', 'px-2'], + sm: ['text-sm', 'py-2', 'px-4'], + md: ['text-md', 'py-2', 'px-6'], + lg: ['text-lg', 'py-2', 'px-8'] + } + }, + compoundVariants: [ + { + colorSchema: 'primary', + variant: 'outline', + className: 'text-primary hover:bg-primary hover:text-black' + }, + { + colorSchema: 'secondary', + variant: 'outline', + className: 'text-mineshaft-200 hover:bg-mineshaft-400 hover:text-white' + }, + { + colorSchema: 'danger', + variant: 'outline', + className: 'text-red hover:bg-red hover:text-black' + }, + { + colorSchema: 'primary', + variant: 'plain', + className: 'text-primary' + }, + { + colorSchema: 'secondary', + variant: 'plain', + className: 'text-mineshaft-400' + }, + { + colorSchema: 'danger', + variant: 'plain', + className: 'text-red' + }, + { + colorSchema: ['danger', 'primary', 'secondary'], + variant: ['plain'], + className: 'bg-transparent py-1 px-1' + } + ] + } +); + +export type ButtonProps = ButtonHTMLAttributes & + VariantProps & + Props; export const Button = forwardRef( - ({ children, isDisabled = false, className, ...props }, ref): JSX.Element => { + ( + { + children, + isDisabled = false, + className = '', + size = 'md', + variant = 'solid', + isFullWidth, + isRounded = true, + leftIcon, + rightIcon, + isLoading, + colorSchema = 'primary', + ...props + }, + ref + ): JSX.Element => { + const loadingToggleClass = isLoading ? 'opacity-0' : 'opacity-100'; + return ( ); } diff --git a/frontend/src/components/v2/Button/index.tsx b/frontend/src/components/v2/Button/index.tsx index fe9c53c511..9cad84da16 100644 --- a/frontend/src/components/v2/Button/index.tsx +++ b/frontend/src/components/v2/Button/index.tsx @@ -1 +1,2 @@ +export type { ButtonProps } from './Button'; export { Button } from './Button'; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx new file mode 100644 index 0000000000..8b166a86e4 --- /dev/null +++ b/frontend/src/components/v2/index.tsx @@ -0,0 +1 @@ +export * from './Button'; From b80504ae0026adc64416f55843d466ceebfb0e02 Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Thu, 19 Jan 2023 21:07:44 +0530 Subject: [PATCH 07/72] feat(ui): implemented new input component --- .../src/components/v2/Input/Input.stories.tsx | 66 ++++++++++++ frontend/src/components/v2/Input/Input.tsx | 102 ++++++++++++++++++ frontend/src/components/v2/Input/index.tsx | 2 + 3 files changed, 170 insertions(+) create mode 100644 frontend/src/components/v2/Input/Input.stories.tsx create mode 100644 frontend/src/components/v2/Input/Input.tsx create mode 100644 frontend/src/components/v2/Input/index.tsx diff --git a/frontend/src/components/v2/Input/Input.stories.tsx b/frontend/src/components/v2/Input/Input.stories.tsx new file mode 100644 index 0000000000..288805b21d --- /dev/null +++ b/frontend/src/components/v2/Input/Input.stories.tsx @@ -0,0 +1,66 @@ +import { faEye, faMailBulk } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { Input } from './Input'; + +const meta: Meta = { + title: 'Components/Input', + component: Input, + tags: ['v2'], + argTypes: { + isRounded: { + defaultValue: true, + type: 'boolean' + }, + placeholder: { + defaultValue: 'Type anything', + type: 'string' + } + } +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Filled: Story = { + args: {} +}; + +export const Outline: Story = { + args: { + variant: 'outline' + } +}; + +export const Plain: Story = { + args: { + variant: 'plain' + } +}; + +export const Error: Story = { + args: { + isError: true + } +}; + +export const AutoWidth: Story = { + args: { + isFullWidth: false, + className: 'w-auto' + } +}; + +export const RightIcon: Story = { + args: { + rightIcon: + } +}; + +export const LeftIcon: Story = { + args: { + leftIcon: + } +}; diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx new file mode 100644 index 0000000000..e7b63e3add --- /dev/null +++ b/frontend/src/components/v2/Input/Input.tsx @@ -0,0 +1,102 @@ +import { forwardRef, InputHTMLAttributes, ReactNode } from 'react'; +import { cva, VariantProps } from 'cva'; +import { twMerge } from 'tailwind-merge'; + +type Props = { + placeholder?: string; + isFullWidth?: boolean; + isRequired?: boolean; + leftIcon?: ReactNode; + rightIcon?: ReactNode; +}; + +const inputVariants = cva( + 'input w-full py-2 text-gray-400 placeholder-gray-500 placeholder-opacity-50', + { + variants: { + size: { + xs: ['text-xs'], + sm: ['text-sm'], + md: ['text-md'], + lg: ['text-lg'] + }, + isRounded: { + true: ['rounded-md'], + false: '' + }, + variant: { + filled: ['bg-bunker-800', 'text-gray-400'], + outline: ['bg-transparent'], + plain: 'bg-transparent outline-none' + }, + isError: { + true: 'focus:ring-red/50 placeholder-red-300', + false: 'focus:ring-primary/50' + } + }, + compoundVariants: [] + } +); + +const inputParentContainerVariants = cva('inline-flex items-center border relative', { + variants: { + isRounded: { + true: ['rounded-md'], + false: '' + }, + isError: { + true: 'border-red', + false: 'border-mineshaft-400' + }, + isFullWidth: { + true: 'w-full', + false: '' + }, + variant: { + filled: ['bg-bunker-800', 'text-gray-400'], + outline: ['bg-transparent'], + plain: 'border-none' + } + } +}); + +export type InputProps = Omit, 'size'> & + VariantProps & + Props; + +export const Input = forwardRef( + ( + { + className, + isRounded = true, + isFullWidth = true, + isError = false, + isRequired, + leftIcon, + rightIcon, + variant = 'filled', + size = 'md', + ...props + }, + ref + ): JSX.Element => { + return ( +
+ {leftIcon && {leftIcon}} + + {rightIcon && {rightIcon}} +
+ ); + } +); + +Input.displayName = 'Input'; diff --git a/frontend/src/components/v2/Input/index.tsx b/frontend/src/components/v2/Input/index.tsx new file mode 100644 index 0000000000..803d2fbab4 --- /dev/null +++ b/frontend/src/components/v2/Input/index.tsx @@ -0,0 +1,2 @@ +export type { InputProps } from './Input'; +export { Input } from './Input'; From e7ac74c5a0b73bf63ba6703e4d4f68da4ec549b5 Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Thu, 19 Jan 2023 23:16:59 +0530 Subject: [PATCH 08/72] feat(ui): implemented form control components --- .../v2/FormControl/FormControl.stories.tsx | 40 +++++++++++ .../components/v2/FormControl/FormControl.tsx | 72 +++++++++++++++++++ .../src/components/v2/FormControl/index.tsx | 2 + frontend/src/components/v2/index.tsx | 2 + 4 files changed, 116 insertions(+) create mode 100644 frontend/src/components/v2/FormControl/FormControl.stories.tsx create mode 100644 frontend/src/components/v2/FormControl/FormControl.tsx create mode 100644 frontend/src/components/v2/FormControl/index.tsx diff --git a/frontend/src/components/v2/FormControl/FormControl.stories.tsx b/frontend/src/components/v2/FormControl/FormControl.stories.tsx new file mode 100644 index 0000000000..2e36922289 --- /dev/null +++ b/frontend/src/components/v2/FormControl/FormControl.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +// Be careful on dep cycle +import { Input } from '../Input/Input'; +import { FormControl } from './FormControl'; + +const meta: Meta = { + title: 'Components/FormControl', + component: FormControl, + tags: ['v2'], + argTypes: {} +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Basic: Story = { + args: { + children: , + label: 'Email', + id: 'email', + helperText: 'Type something..' + } +}; + +export const RequiredInput: Story = { + args: { + ...Basic.args, + isRequired: true + } +}; + +export const ErrorInput: Story = { + args: { + ...Basic.args, + errorText: 'Some random error', + isError: true + } +}; diff --git a/frontend/src/components/v2/FormControl/FormControl.tsx b/frontend/src/components/v2/FormControl/FormControl.tsx new file mode 100644 index 0000000000..d609b24f40 --- /dev/null +++ b/frontend/src/components/v2/FormControl/FormControl.tsx @@ -0,0 +1,72 @@ +import { cloneElement, ReactNode } from 'react'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import * as Label from '@radix-ui/react-label'; +import { twMerge } from 'tailwind-merge'; + +export type FormLabelProps = { + id?: string; + isRequired?: boolean; + label?: ReactNode; +}; + +export const FormLabel = ({ id, label, isRequired }: FormLabelProps) => ( + + {label} + {isRequired && *} + +); + +export type FormHelperTextProps = { + isError?: boolean; + text?: ReactNode; +}; + +export const FormHelperText = ({ isError, text }: FormHelperTextProps) => ( +
+ {isError && ( + + + + )} + {text} +
+); + +export type FormControlProps = { + id?: string; + isRequired?: boolean; + isError?: boolean; + label?: ReactNode; + helperText?: ReactNode; + errorText?: ReactNode; + children: JSX.Element; +}; + +export const FormControl = ({ + children, + isRequired, + label, + helperText, + errorText, + id, + isError +}: FormControlProps): JSX.Element => { + return ( +
+ {typeof label === 'string' ? ( + + ) : ( + label + )} + {cloneElement(children, { isRequired, 'data-required': isRequired, isError })} + {!isError && helperText && } + {isError && errorText && } +
+ ); +}; diff --git a/frontend/src/components/v2/FormControl/index.tsx b/frontend/src/components/v2/FormControl/index.tsx new file mode 100644 index 0000000000..806103759c --- /dev/null +++ b/frontend/src/components/v2/FormControl/index.tsx @@ -0,0 +1,2 @@ +export type { FormControlProps, FormHelperTextProps, FormLabelProps } from './FormControl'; +export { FormControl, FormHelperText, FormLabel } from './FormControl'; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx index 8b166a86e4..71d91fc1e0 100644 --- a/frontend/src/components/v2/index.tsx +++ b/frontend/src/components/v2/index.tsx @@ -1 +1,3 @@ export * from './Button'; +export * from './FormControl'; +export * from './Input'; From ad504fa84eb40080862b35e527e1485f5fde3b59 Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Fri, 20 Jan 2023 23:12:12 +0530 Subject: [PATCH 09/72] feat(ui) added select, spinner components --- frontend/.storybook/preview.js | 4 + frontend/package-lock.json | 116 ++++++++++-------- frontend/package.json | 2 +- .../components/v2/Select/Select.stories.tsx | 113 +++++++++++++++++ frontend/src/components/v2/Select/Select.tsx | 96 +++++++++++++++ frontend/src/components/v2/Select/index.tsx | 1 + .../src/components/v2/Spinner/Spinner.tsx | 42 +++++++ frontend/src/components/v2/Spinner/index.tsx | 1 + frontend/src/styles/globals.css | 6 + 9 files changed, 330 insertions(+), 51 deletions(-) create mode 100644 frontend/src/components/v2/Select/Select.stories.tsx create mode 100644 frontend/src/components/v2/Select/Select.tsx create mode 100644 frontend/src/components/v2/Select/index.tsx create mode 100644 frontend/src/components/v2/Spinner/Spinner.tsx create mode 100644 frontend/src/components/v2/Spinner/index.tsx diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index 4a19aa4c96..94133eee3d 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -1,3 +1,4 @@ +import { themes } from '@storybook/theming'; import '../src/styles/globals.css'; export const parameters = { @@ -7,5 +8,8 @@ export const parameters = { color: /(background|color)$/i, date: /Date$/ } + }, + darkMode: { + dark: { ...themes.dark, appContentBg: '#0e1014', appBg: '#0e1014' } } }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cff1b80fb0..042c695768 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,7 +28,6 @@ "add": "^2.0.6", "axios": "^0.27.2", "axios-auth-refresh": "^3.3.3", - "class-variance-authority": "^0.4.0", "classnames": "^2.3.1", "cookies": "^0.8.0", "cva": "npm:class-variance-authority@^0.4.0", @@ -96,7 +95,7 @@ "prettier": "^2.8.3", "storybook": "^7.0.0-beta.30", "storybook-dark-mode": "^2.0.5", - "tailwindcss": "^3.1.4", + "tailwindcss": "3.2", "typescript": "^4.9.3" } }, @@ -9301,22 +9300,6 @@ "node": ">=0.10.0" } }, - "node_modules/class-variance-authority": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", - "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", - "funding": { - "url": "https://joebell.co.uk" - }, - "peerDependencies": { - "typescript": ">= 4.5.5 < 5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", @@ -12028,9 +12011,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -17203,12 +17186,12 @@ } }, "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.6" + "postcss-selector-parser": "^6.0.10" }, "engines": { "node": ">=12.0" @@ -20420,9 +20403,9 @@ "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==" }, "node_modules/tailwindcss": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz", - "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", + "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", "dev": true, "dependencies": { "arg": "^5.0.2", @@ -20431,18 +20414,19 @@ "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.18", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", + "postcss-nested": "6.0.0", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", @@ -20459,6 +20443,30 @@ "postcss": "^8.0.9" } }, + "node_modules/tailwindcss/node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -28822,12 +28830,6 @@ } } }, - "class-variance-authority": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", - "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", - "requires": {} - }, "classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", @@ -30927,9 +30929,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -34637,12 +34639,12 @@ } }, "postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.6" + "postcss-selector-parser": "^6.0.10" } }, "postcss-selector-parser": { @@ -37007,9 +37009,9 @@ "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==" }, "tailwindcss": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz", - "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", + "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", "dev": true, "requires": { "arg": "^5.0.2", @@ -37018,22 +37020,36 @@ "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.18", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", + "postcss-nested": "6.0.0", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", "resolve": "^1.22.1" + }, + "dependencies": { + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + } } }, "tapable": { diff --git a/frontend/package.json b/frontend/package.json index 60b8eda85e..43fa01a8bd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -102,7 +102,7 @@ "prettier": "^2.8.3", "storybook": "^7.0.0-beta.30", "storybook-dark-mode": "^2.0.5", - "tailwindcss": "^3.1.4", + "tailwindcss": "3.2", "typescript": "^4.9.3" } } diff --git a/frontend/src/components/v2/Select/Select.stories.tsx b/frontend/src/components/v2/Select/Select.stories.tsx new file mode 100644 index 0000000000..51f75ae530 --- /dev/null +++ b/frontend/src/components/v2/Select/Select.stories.tsx @@ -0,0 +1,113 @@ +import { useEffect, useState } from 'react'; +import { SelectProps } from '@radix-ui/react-select'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { Meta, StoryObj } from '@storybook/react'; + +import { Select, SelectItem } from './Select'; + +const meta: Meta = { + title: 'Components/Select', + component: Select, + tags: ['v2'], + argTypes: { + placeholder: { + defaultValue: 'Type something...' + } + } +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => ( +
+ +
+ ) +}; + +const Controlled = (args: SelectProps) => { + const [isOpen, setIsOpen] = useState(false); + const [selected, setSelected] = useState(''); + + return ( +
+ +
+ ); +}; + +export const Control: Story = { + render: (args) => +}; + +export const Disabled: Story = { + render: (args) => ( +
+ +
+ ) +}; + +export const Loading: Story = { + render: (args) => ( +
+ +
+ ) +}; + +const AsyncSelectOptions = () => { + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + // eslint-disable-next-line no-new + new Promise((resolve): void => { + setTimeout(() => { + setIsLoading(false); + resolve(); + }, 1000); + }); + }, []); + + return ( +
+ +
+ ); +}; + +export const Async: Story = { + render: (args) => +}; diff --git a/frontend/src/components/v2/Select/Select.tsx b/frontend/src/components/v2/Select/Select.tsx new file mode 100644 index 0000000000..7b45a18481 --- /dev/null +++ b/frontend/src/components/v2/Select/Select.tsx @@ -0,0 +1,96 @@ +import { forwardRef, ReactNode } from 'react'; +import { faCheck, faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import * as SelectPrimitive from '@radix-ui/react-select'; +import { twMerge } from 'tailwind-merge'; + +import { Spinner } from '../Spinner'; + +type Props = { + children: ReactNode; + placeholder?: string; + className?: string; + isLoading?: boolean; +}; + +type SelectProps = SelectPrimitive.SelectProps & Props; + +export const Select = forwardRef( + ({ children, placeholder, className, isLoading, ...props }, ref): JSX.Element => { + return ( + + + + + + + + + + + + + + {isLoading ? ( +
+ + Loading... +
+ ) : ( + children + )} +
+ + + +
+
+
+ ); + } +); + +Select.displayName = 'Select'; + +type SelectItemProps = Omit & { + isDisabled?: boolean; + isSelected?: boolean; +}; + +export const SelectItem = forwardRef( + ({ children, className, isSelected, isDisabled, ...props }, forwardedRef) => { + return ( + + + + + {children} + + ); + } +); + +SelectItem.displayName = 'SelectItem'; diff --git a/frontend/src/components/v2/Select/index.tsx b/frontend/src/components/v2/Select/index.tsx new file mode 100644 index 0000000000..d42fd8d593 --- /dev/null +++ b/frontend/src/components/v2/Select/index.tsx @@ -0,0 +1 @@ +export {Select} from './Select' \ No newline at end of file diff --git a/frontend/src/components/v2/Spinner/Spinner.tsx b/frontend/src/components/v2/Spinner/Spinner.tsx new file mode 100644 index 0000000000..0fcbf1ce09 --- /dev/null +++ b/frontend/src/components/v2/Spinner/Spinner.tsx @@ -0,0 +1,42 @@ +import { twMerge } from 'tailwind-merge'; + +type SizeOptions = 'xs' | 'sm' | 'md' | 'lg'; + +type Props = { + className?: string; + size?: SizeOptions; +}; + +const sizeChart: Record = { + xs: 'w-4 h-4', + sm: 'w-6 h-6', + md: 'w-8 h-8', + lg: 'w-12 h-12' +}; + +export const Spinner = ({ className, size = 'md' }: Props): JSX.Element => { + return ( +
+ +
+ ); +}; diff --git a/frontend/src/components/v2/Spinner/index.tsx b/frontend/src/components/v2/Spinner/index.tsx new file mode 100644 index 0000000000..1ce6cab2eb --- /dev/null +++ b/frontend/src/components/v2/Spinner/index.tsx @@ -0,0 +1 @@ +export { Spinner } from './Spinner'; diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css index b5c61c9567..18814e2242 100644 --- a/frontend/src/styles/globals.css +++ b/frontend/src/styles/globals.css @@ -1,3 +1,9 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer components { + .select[data-placeholder] { + color: theme("colors.gray.500") + } +} From f859bf528ef959d76cc2b6f6b59a4cfd6cf35403 Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Sat, 21 Jan 2023 12:55:43 +0530 Subject: [PATCH 10/72] feat(ui): added icon button component, updated secondary button style and added select to barrel export --- frontend/src/components/v2/Button/Button.tsx | 12 +- .../v2/IconButton/IconButton.stories.tsx | 60 ++++++++ .../components/v2/IconButton/IconButton.tsx | 131 ++++++++++++++++++ .../src/components/v2/IconButton/index.tsx | 2 + frontend/src/components/v2/Select/Select.tsx | 4 +- frontend/src/components/v2/Select/index.tsx | 3 +- frontend/src/components/v2/index.tsx | 2 + 7 files changed, 205 insertions(+), 9 deletions(-) create mode 100644 frontend/src/components/v2/IconButton/IconButton.stories.tsx create mode 100644 frontend/src/components/v2/IconButton/IconButton.tsx create mode 100644 frontend/src/components/v2/IconButton/index.tsx diff --git a/frontend/src/components/v2/Button/Button.tsx b/frontend/src/components/v2/Button/Button.tsx index f00d1d0a36..c0894f261a 100644 --- a/frontend/src/components/v2/Button/Button.tsx +++ b/frontend/src/components/v2/Button/Button.tsx @@ -24,16 +24,16 @@ const buttonVariants = cva( variants: { colorSchema: { primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'], - secondary: ['bg-mineshaft-200', 'text-white', 'border-mineshaft-200'], + secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'], danger: ['bg-red', 'text-white', 'border-red'] }, variant: { solid: '', - outline: ['bg-transparent', 'border', 'border-solid'], + outline: ['bg-transparent', 'border-2', 'border-solid'], plain: '' }, isDisabled: { - true: 'bg-opacity-70', + true: 'bg-opacity-70 cursor-not-allowed', false: '' }, isFullWidth: { @@ -60,7 +60,7 @@ const buttonVariants = cva( { colorSchema: 'secondary', variant: 'outline', - className: 'text-mineshaft-200 hover:bg-mineshaft-400 hover:text-white' + className: 'hover:bg-mineshaft' }, { colorSchema: 'danger', @@ -75,7 +75,7 @@ const buttonVariants = cva( { colorSchema: 'secondary', variant: 'plain', - className: 'text-mineshaft-400' + className: 'text-mineshaft' }, { colorSchema: 'danger', @@ -139,7 +139,7 @@ export const Button = forwardRef( src="/images/loading/loadingblack.gif" width={36} alt="loading animation" - className="rounded-xl absolute" + className="absolute rounded-xl" /> )} = { + title: 'Components/IconButton', + component: IconButton, + tags: ['v2'], + argTypes: { + isRounded: { + defaultValue: true, + type: 'boolean' + }, + ariaLabel: { + defaultValue: 'Some buttons...' + } + } +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Primary: Story = { + args: { + children: + } +}; + +export const Secondary: Story = { + args: { + children: , + colorSchema: 'secondary', + variant: 'outline' + } +}; + +export const Danger: Story = { + args: { + children: , + colorSchema: 'danger', + variant: 'solid' + } +}; + +export const Plain: Story = { + args: { + children: , + variant: 'plain' + } +}; + +export const Disabled: Story = { + args: { + children: , + disabled: true + } +}; diff --git a/frontend/src/components/v2/IconButton/IconButton.tsx b/frontend/src/components/v2/IconButton/IconButton.tsx new file mode 100644 index 0000000000..9790d9d7bb --- /dev/null +++ b/frontend/src/components/v2/IconButton/IconButton.tsx @@ -0,0 +1,131 @@ +import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react'; +import { cva, VariantProps } from 'cva'; +import { twMerge } from 'tailwind-merge'; + +type Props = { + children: ReactNode; + // This is kept as required because by accessibility convention and eslint + // when button doesn't have text an aria-label needs to be passed + ariaLabel: string; + isDisabled?: boolean; +}; + +const iconButtonVariants = cva( + [ + 'button', + 'transition-all', + 'font-medium', + 'cursor-pointer', + 'inline-flex items-center justify-center', + 'relative' + ], + { + variants: { + colorSchema: { + primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'], + secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'], + danger: ['bg-red', 'text-white', 'border-red'] + }, + variant: { + solid: '', + outline: ['bg-transparent', 'border-2', 'border-solid'], + plain: '' + }, + isDisabled: { + true: 'bg-opacity-70 cursor-not-allowed', + false: '' + }, + isRounded: { + true: 'rounded-md', + false: '' + }, + size: { + xs: ['text-xs', 'py-1', 'px-2'], + sm: ['text-sm', 'py-2', 'px-3'], + md: ['text-md', 'py-3', 'px-4'], + lg: ['text-lg', 'py-3', 'px-6'] + } + }, + compoundVariants: [ + { + colorSchema: 'primary', + variant: 'outline', + className: 'text-primary hover:bg-primary hover:text-black' + }, + { + colorSchema: 'secondary', + variant: 'outline', + className: 'hover:bg-mineshaft' + }, + { + colorSchema: 'danger', + variant: 'outline', + className: 'text-red hover:bg-red hover:text-black' + }, + { + colorSchema: 'primary', + variant: 'plain', + className: 'text-primary' + }, + { + colorSchema: 'secondary', + variant: 'plain', + className: 'text-mineshaft' + }, + { + colorSchema: 'danger', + variant: 'plain', + className: 'text-red' + }, + { + colorSchema: ['danger', 'primary', 'secondary'], + variant: ['plain'], + className: 'bg-transparent py-1 px-1' + } + ] + } +); + +export type IconButtonProps = Omit, 'aria-label'> & + VariantProps & + Props; + +export const IconButton = forwardRef( + ( + { + children, + ariaLabel, + isDisabled = false, + className, + size = 'md', + variant = 'solid', + isRounded = true, + colorSchema = 'primary', + ...props + }, + ref + ): JSX.Element => ( + + ) +); + +IconButton.displayName = 'IconButton'; diff --git a/frontend/src/components/v2/IconButton/index.tsx b/frontend/src/components/v2/IconButton/index.tsx new file mode 100644 index 0000000000..e920c3d6a0 --- /dev/null +++ b/frontend/src/components/v2/IconButton/index.tsx @@ -0,0 +1,2 @@ +export type { IconButtonProps } from './IconButton'; +export { IconButton } from './IconButton'; diff --git a/frontend/src/components/v2/Select/Select.tsx b/frontend/src/components/v2/Select/Select.tsx index 7b45a18481..3fee8b7c79 100644 --- a/frontend/src/components/v2/Select/Select.tsx +++ b/frontend/src/components/v2/Select/Select.tsx @@ -13,7 +13,7 @@ type Props = { isLoading?: boolean; }; -type SelectProps = SelectPrimitive.SelectProps & Props; +export type SelectProps = SelectPrimitive.SelectProps & Props; export const Select = forwardRef( ({ children, placeholder, className, isLoading, ...props }, ref): JSX.Element => { @@ -64,7 +64,7 @@ export const Select = forwardRef( Select.displayName = 'Select'; -type SelectItemProps = Omit & { +export type SelectItemProps = Omit & { isDisabled?: boolean; isSelected?: boolean; }; diff --git a/frontend/src/components/v2/Select/index.tsx b/frontend/src/components/v2/Select/index.tsx index d42fd8d593..269099af6e 100644 --- a/frontend/src/components/v2/Select/index.tsx +++ b/frontend/src/components/v2/Select/index.tsx @@ -1 +1,2 @@ -export {Select} from './Select' \ No newline at end of file +export type { SelectItemProps, SelectProps } from './Select'; +export { Select, SelectItem } from './Select'; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx index 71d91fc1e0..0d6c14ea21 100644 --- a/frontend/src/components/v2/index.tsx +++ b/frontend/src/components/v2/index.tsx @@ -1,3 +1,5 @@ export * from './Button'; export * from './FormControl'; +export * from './IconButton'; export * from './Input'; +export * from './Select'; From 606a5e5317385ac5edc7a533fec2c7b98ab4237c Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Sat, 21 Jan 2023 20:49:46 +0530 Subject: [PATCH 11/72] feat(ui): added card component --- .../src/components/v2/Card/Card.stories.tsx | 40 ++++++++++++ frontend/src/components/v2/Card/Card.tsx | 62 +++++++++++++++++++ frontend/src/components/v2/Card/index.tsx | 2 + frontend/src/components/v2/index.tsx | 1 + 4 files changed, 105 insertions(+) create mode 100644 frontend/src/components/v2/Card/Card.stories.tsx create mode 100644 frontend/src/components/v2/Card/Card.tsx create mode 100644 frontend/src/components/v2/Card/index.tsx diff --git a/frontend/src/components/v2/Card/Card.stories.tsx b/frontend/src/components/v2/Card/Card.stories.tsx new file mode 100644 index 0000000000..e21625cb42 --- /dev/null +++ b/frontend/src/components/v2/Card/Card.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Card, CardBody, CardFooter, CardProps, CardTitle } from './Card'; + +const meta: Meta = { + title: 'Components/Card', + component: Card, + tags: ['v2'], + argTypes: { + isRounded: { + type: 'boolean', + defaultValue: true + } + } +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +const Template = (args: CardProps) => ( +
+ + Title + Content + Footer + +
+); + +export const Basic: Story = { + render: (args) =>