diff --git a/packages/console/package.json b/packages/console/package.json index 1ab3076f0..37c0b0675 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -20,6 +20,7 @@ "@logto/schemas": "^0.1.0", "@silverhand/essentials": "^1.1.6", "classnames": "^2.3.1", + "csstype": "^3.0.11", "i18next": "^21.6.12", "i18next-browser-languagedetector": "^6.1.3", "ky": "^0.30.0", @@ -27,6 +28,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-hook-form": "^7.27.1", + "react-hot-toast": "^2.2.0", "react-i18next": "^11.15.4", "react-modal": "^3.14.4", "react-router-dom": "^6.2.2", diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index d3ea782af..259f693e0 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -7,6 +7,7 @@ import * as styles from './App.module.scss'; import AppContent from './components/AppContent'; import Content from './components/Content'; import Sidebar, { getPath, sections } from './components/Sidebar'; +import Toast from './components/Toast'; import Topbar from './components/Topbar'; import initI18n from './i18n/init'; import ApiResourceDetails from './pages/ApiResourceDetails'; @@ -33,6 +34,7 @@ const Main = () => { return ( +
diff --git a/packages/console/src/components/AppContent/index.module.scss b/packages/console/src/components/AppContent/index.module.scss index 731230c56..637cbcfed 100644 --- a/packages/console/src/components/AppContent/index.module.scss +++ b/packages/console/src/components/AppContent/index.module.scss @@ -43,6 +43,7 @@ --color-disabled: #c4c7c7; --color-border: #c4c7c7; --color-green: #66bb6a; + --shadow-light-s1: 0 2px 8px rgba(0, 0, 0, 8%); } $font-family: 'SF UI Text', 'SF Pro Display', sans-serif; diff --git a/packages/console/src/components/Toast/index.module.scss b/packages/console/src/components/Toast/index.module.scss new file mode 100644 index 000000000..7b867118b --- /dev/null +++ b/packages/console/src/components/Toast/index.module.scss @@ -0,0 +1,19 @@ +@use '@/scss/underscore' as _; + +div.toast { + padding: _.unit(3) _.unit(4); + font: var(--font-body-2); + color: var(--color-component-text); + box-shadow: var(--light-shadow-s1); + border-radius: _.unit(2); + max-width: none; + + > div[role='status'] { + margin: 0 0 0 _.unit(3); + } + + &.success { + border: 1px solid #66bb6a; + background: linear-gradient(0deg, rgba(102, 187, 106, 15%), rgba(102, 187, 106, 15%)), #fff; + } +} diff --git a/packages/console/src/components/Toast/index.tsx b/packages/console/src/components/Toast/index.tsx new file mode 100644 index 000000000..62ae00197 --- /dev/null +++ b/packages/console/src/components/Toast/index.tsx @@ -0,0 +1,18 @@ +import classNames from 'classnames'; +import React from 'react'; +import { Toaster } from 'react-hot-toast'; + +import * as styles from './index.module.scss'; + +const Toast = () => { + return ( + + ); +}; + +export default Toast; diff --git a/packages/console/src/components/Tooltip/index.module.scss b/packages/console/src/components/Tooltip/index.module.scss index a3df86dac..9439d7e06 100644 --- a/packages/console/src/components/Tooltip/index.module.scss +++ b/packages/console/src/components/Tooltip/index.module.scss @@ -6,7 +6,7 @@ border-radius: 8px; background: #191c1d; color: #e0e3e3; - box-shadow: 0 2px 8px rgba(0, 0, 0, 8%); + box-shadow: var(--light-shadow-s1); padding: _.unit(2) _.unit(3); font: var(--font-body); @@ -20,6 +20,6 @@ left: 50%; top: 100%; transform: translateX(-50%); - box-shadow: 0 2px 8px rgba(0, 0, 0, 8%); + box-shadow: var(--light-shadow-s1); } } diff --git a/packages/console/src/pages/Applications/index.tsx b/packages/console/src/pages/Applications/index.tsx index 05a00dfdb..27c8da4b4 100644 --- a/packages/console/src/pages/Applications/index.tsx +++ b/packages/console/src/pages/Applications/index.tsx @@ -1,9 +1,7 @@ import { Application, Setting } from '@logto/schemas'; -import { - conditional, - conditionalString, -} from '@silverhand/essentials/lib/utilities/conditional.js'; +import { conditional } from '@silverhand/essentials/lib/utilities/conditional.js'; import React, { useState } from 'react'; +import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import Modal from 'react-modal'; import { useNavigate } from 'react-router-dom'; @@ -52,11 +50,13 @@ const Applications = () => { if (createdApp) { void mutate(conditional(data && [...data, createdApp])); - navigate( - `/applications/${createdApp.id}${conditionalString( - !setting?.adminConsole.applicationSkipGetStarted && '/get-started' - )}` - ); + + if (setting?.adminConsole.applicationSkipGetStarted) { + toast.success(t('applications.application_created', { name: createdApp.name })); + navigate(`/applications/${createdApp.id}`); + } else { + navigate(`/applications/${createdApp.id}/get-started`); + } } }} /> diff --git a/packages/phrases/src/locales/en.ts b/packages/phrases/src/locales/en.ts index e1bf69f8d..68dcc3125 100644 --- a/packages/phrases/src/locales/en.ts +++ b/packages/phrases/src/locales/en.ts @@ -53,6 +53,8 @@ const translation = { application_description: 'Application Description', select_application_type: 'Select an Application Type', no_application_type_selected: 'You have to select an application type to proceed.', + application_created: + 'The application {{name}} has been successfully created! \nNow finish your application settings.', client_id: 'Client ID', type: { native: { diff --git a/packages/phrases/src/locales/zh-cn.ts b/packages/phrases/src/locales/zh-cn.ts index 3adf456d2..fc9250c7a 100644 --- a/packages/phrases/src/locales/zh-cn.ts +++ b/packages/phrases/src/locales/zh-cn.ts @@ -55,6 +55,8 @@ const translation = { application_description: 'Application Description', select_application_type: 'Select an application type', no_application_type_selected: 'You have to select an application type to proceed.', + application_created: + 'The application {{name}} has been successfully created! \nNow finish your application settings.', client_id: 'Client ID', type: { native: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 071b69aed..c7df51d72 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,7 @@ importers: '@types/react-dom': ^17.0.9 '@types/react-modal': ^3.13.1 classnames: ^2.3.1 + csstype: ^3.0.11 eslint: ^8.10.0 i18next: ^21.6.12 i18next-browser-languagedetector: ^6.1.3 @@ -47,6 +48,7 @@ importers: react: ^17.0.2 react-dom: ^17.0.2 react-hook-form: ^7.27.1 + react-hot-toast: ^2.2.0 react-i18next: ^11.15.4 react-modal: ^3.14.4 react-router-dom: ^6.2.2 @@ -58,6 +60,7 @@ importers: '@logto/schemas': link:../schemas '@silverhand/essentials': 1.1.6 classnames: 2.3.1 + csstype: 3.0.11 i18next: 21.6.12 i18next-browser-languagedetector: 6.1.3 ky: 0.30.0 @@ -65,6 +68,7 @@ importers: react: 17.0.2 react-dom: 17.0.2_react@17.0.2 react-hook-form: 7.27.1_react@17.0.2 + react-hot-toast: 2.2.0_383bc679f6b8b3c30a924b2c4a84e8d7 react-i18next: 11.15.4_2c37a602a29bb6bd53f3de707a8cfcc5 react-modal: 3.14.4_react-dom@17.0.2+react@17.0.2 react-router-dom: 6.2.2_react-dom@17.0.2+react@17.0.2 @@ -3668,7 +3672,7 @@ packages: dependencies: '@types/prop-types': 15.7.4 '@types/scheduler': 0.16.2 - csstype: 3.0.10 + csstype: 3.0.11 dev: true /@types/responselike/1.0.0: @@ -5231,9 +5235,8 @@ packages: cssom: 0.3.8 dev: true - /csstype/3.0.10: - resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==} - dev: true + /csstype/3.0.11: + resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} /dargs/7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} @@ -6773,6 +6776,14 @@ packages: minimist: 1.2.5 dev: true + /goober/2.1.8_csstype@3.0.11: + resolution: {integrity: sha512-S0C85gCzcfFCMSdjD/CxyQMt1rbf2qEg6hmDzxk2FfD7+7Ogk55m8ZFUMtqNaZM4VVX/qaU9AzSORG+Gf4ZpAQ==} + peerDependencies: + csstype: ^3.0.10 + dependencies: + csstype: 3.0.11 + dev: false + /got/11.8.3: resolution: {integrity: sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==} engines: {node: '>=10.19.0'} @@ -11420,6 +11431,20 @@ packages: react: 17.0.2 dev: false + /react-hot-toast/2.2.0_383bc679f6b8b3c30a924b2c4a84e8d7: + resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + goober: 2.1.8_csstype@3.0.11 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + transitivePeerDependencies: + - csstype + dev: false + /react-i18next/11.15.4_2c37a602a29bb6bd53f3de707a8cfcc5: resolution: {integrity: sha512-jKJNAcVcbPGK+yrTcXhLblgPY16n6NbpZZL3Mk8nswj1v3ayIiUBVDU09SgqnT+DluyQBS97hwSvPU5yVFG0yg==} peerDependencies: