diff --git a/packages/console/src/scss/normalized.scss b/packages/console/src/scss/normalized.scss index 448c46af3..168faaf98 100644 --- a/packages/console/src/scss/normalized.scss +++ b/packages/console/src/scss/normalized.scss @@ -1,5 +1,5 @@ @use '@/scss/underscore' as _; -@use '@/scss/fonts'; +@use '@logto/shared/scss/fonts'; body { margin: 0; diff --git a/packages/demo-app/package.json b/packages/demo-app/package.json index 6f1810086..e887c1390 100644 --- a/packages/demo-app/package.json +++ b/packages/demo-app/package.json @@ -9,7 +9,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "precommit": "lint-staged", "start": "parcel src/index.html", - "dev": "PORT=5003 parcel src/index.html --public-url /demo-app --no-cache --hmr-port 6003", + "dev": "cross-env PORT=5003 parcel src/index.html --public-url /demo-app --no-cache --hmr-port 6003", "check": "tsc --noEmit", "build": "pnpm check && rm -rf dist && parcel build src/index.html --no-autoinstall --no-cache --public-url /demo-app", "lint": "eslint --ext .ts --ext .tsx src", @@ -17,6 +17,7 @@ "stylelint": "stylelint \"src/**/*.scss\"" }, "devDependencies": { + "@logto/phrases": "^0.1.0", "@logto/react": "^0.1.14", "@logto/schemas": "^0.1.0", "@logto/shared": "^0.1.0", @@ -28,13 +29,17 @@ "@silverhand/ts-config-react": "^0.14.0", "@types/react": "^17.0.14", "@types/react-dom": "^17.0.9", + "cross-env": "^7.0.3", "eslint": "^8.10.0", + "i18next": "^21.6.12", + "i18next-browser-languagedetector": "^6.1.3", "lint-staged": "^13.0.0", "parcel": "2.5.0", "postcss": "^8.4.6", "prettier": "^2.3.2", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-i18next": "^11.15.4", "stylelint": "^14.8.2", "typescript": "^4.7.2" }, diff --git a/packages/demo-app/src/App.module.scss b/packages/demo-app/src/App.module.scss index 9b0adf8da..ba3789a21 100644 --- a/packages/demo-app/src/App.module.scss +++ b/packages/demo-app/src/App.module.scss @@ -1,15 +1,10 @@ @use '@/scss/underscore' as _; +@use '@logto/shared/scss/fonts'; @use '@logto/shared/scss/console-themes' as themes; -body { - background: #edebf6; -} - .app { - @include themes.light; - .card { - background: var(--color-background); + background: var(--color-layer-1); border-radius: 16px; position: absolute; left: 50%; @@ -28,27 +23,30 @@ body { .title { margin-top: _.unit(6); color: var(--color-neutral-10); - font-weight: 600; - font-size: 16px; - line-height: 24px; + font: var(--font-title-medium); } .text { margin-top: _.unit(1); + font: var(--font-body-medium); color: var(--color-caption); } .infoCard { margin-top: _.unit(4); - padding: _.unit(1.5) _.unit(4); + padding: _.unit(4); + font: var(--font-body-medium); color: var(--color-text); background: var(--color-layer-2); border-radius: 8px; width: 400px; + span { + font: var(--font-label-large); + } - p { - margin: _.unit(2.5) 0; + div + div { + margin-top: _.unit(2.5); } } @@ -58,7 +56,7 @@ body { border: 1px solid var(--color-outline); border-radius: 8px; padding: _.unit(3) _.unit(6); - font-weight: 500; + font: var(--font-button); color: var(--color-text); transition: background ease-in-out 0.2s; @@ -107,3 +105,15 @@ body { } } } + +@media (prefers-color-scheme: light) { + body { + @include themes.light; + } +} + +@media (prefers-color-scheme: dark) { + body { + @include themes.dark; + } +} diff --git a/packages/demo-app/src/App.tsx b/packages/demo-app/src/App.tsx index d1d24e250..1d32cb03f 100644 --- a/packages/demo-app/src/App.tsx +++ b/packages/demo-app/src/App.tsx @@ -1,36 +1,44 @@ -import { LogtoProvider, useLogto } from '@logto/react'; +import { LogtoProvider, useLogto, UserInfoResponse } from '@logto/react'; import { signInNotificationStorageKey } from '@logto/schemas'; import { demoAppApplicationId } from '@logto/schemas/lib/seeds'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import '@/scss/normalized.scss'; import * as styles from './App.module.scss'; import Callback from './Callback'; import congrats from './assets/congrats.svg'; +import initI18n from './i18n/init'; + +void initI18n(); const Main = () => { - const { isAuthenticated, signIn } = useLogto(); + const { isAuthenticated, fetchUserInfo, signIn, signOut } = useLogto(); + const [user, setUser] = useState(); + const { t } = useTranslation(undefined, { keyPrefix: 'demo_app' }); const isInCallback = Boolean(new URL(window.location.href).searchParams.get('code')); - // Pending SDK fix - const username = 'foo'; - const userId = 'bar'; - useEffect(() => { if (!isAuthenticated && !isInCallback) { - sessionStorage.setItem( - signInNotificationStorageKey, - 'Use the admin username and password to sign in this demo.' - ); + sessionStorage.setItem(signInNotificationStorageKey, t('notification')); void signIn(window.location.href); } - }, [isAuthenticated, isInCallback, signIn]); + }, [isAuthenticated, isInCallback, signIn, t]); + + useEffect(() => { + (async () => { + if (isAuthenticated) { + const userInfo = await fetchUserInfo(); + setUser(userInfo); + } + })(); + }, [isAuthenticated, fetchUserInfo]); if (isInCallback) { return ; } - if (!isAuthenticated) { + if (!isAuthenticated || !user) { return null; } @@ -38,29 +46,35 @@ const Main = () => {
Congrats -
You've successfully signed in the demo app!
-
Here is your personal information:
+
{t('title')}
+
{t('subtitle')}
-

- Username: {username} -

-

- User ID: {userId} -

+
+ {t('username')} + {user.username} +
+
+ {t('user_id')} + {user.sub} +
+
+
signOut(`${window.location.origin}/demo-app`)} + > + {t('sign_out')}
- {/* Pending SDK fix */} -
Sign out the demo app
diff --git a/packages/demo-app/src/Callback.tsx b/packages/demo-app/src/Callback.tsx index fd83d63d8..c76ca3598 100644 --- a/packages/demo-app/src/Callback.tsx +++ b/packages/demo-app/src/Callback.tsx @@ -2,14 +2,7 @@ import { useHandleSignInCallback } from '@logto/react'; import React from 'react'; const Callback = () => { - const { error, isAuthenticated } = useHandleSignInCallback('.'); - - if (isAuthenticated) { - const { href } = window.location; - window.location.assign(href.slice(0, href.indexOf('?'))); - - return null; - } + const { error } = useHandleSignInCallback('demo-app'); if (error) { return ( diff --git a/packages/demo-app/src/i18n/init.ts b/packages/demo-app/src/i18n/init.ts new file mode 100644 index 000000000..79fdadd8a --- /dev/null +++ b/packages/demo-app/src/i18n/init.ts @@ -0,0 +1,19 @@ +import resources, { Language } from '@logto/phrases'; +import i18next from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + +const initI18n = async (language?: Language) => + i18next + .use(initReactI18next) + .use(LanguageDetector) + .init({ + resources, + fallbackLng: 'en', + interpolation: { + escapeValue: false, + }, + lng: language, + }); + +export default initI18n; diff --git a/packages/demo-app/src/scss/normalized.scss b/packages/demo-app/src/scss/normalized.scss index 40c6a46b4..572892f67 100644 --- a/packages/demo-app/src/scss/normalized.scss +++ b/packages/demo-app/src/scss/normalized.scss @@ -2,6 +2,7 @@ body { margin: 0; padding: 0; font-family: sans-serif; + background: var(--color-base); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: auto; } @@ -16,3 +17,22 @@ input { border: none; outline: none; } + +::-webkit-scrollbar { + width: 16px; +} + +::-webkit-scrollbar:horizontal { + height: 16px; +} + +::-webkit-scrollbar-thumb { + background: var(--color-neutral-variant-80); + background-clip: content-box; + border: 4px solid transparent; + border-radius: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; +} diff --git a/packages/phrases/src/locales/en.ts b/packages/phrases/src/locales/en.ts index f76429e85..bbd647cfa 100644 --- a/packages/phrases/src/locales/en.ts +++ b/packages/phrases/src/locales/en.ts @@ -549,6 +549,18 @@ const translation = { button: 'Sign in again', }, }, + demo_app: { + notification: 'Use the admin username and password to sign in this demo.', + title: "You've successfully signed in the demo app!", + subtitle: 'Here is your personal information:', + username: 'Username: ', + user_id: 'User ID: ', + sign_out: 'Sign out the demo app', + continue_explore: 'Or continue to explore', + customize_sign_in_experience: 'Customize sign-in experience', + enable_passwordless: 'Enable passwordless', + add_social_connector: 'Add a social connector', + }, }; const errors = { diff --git a/packages/phrases/src/locales/zh-cn.ts b/packages/phrases/src/locales/zh-cn.ts index 3c3682ac1..95dca1cf8 100644 --- a/packages/phrases/src/locales/zh-cn.ts +++ b/packages/phrases/src/locales/zh-cn.ts @@ -533,6 +533,18 @@ const translation = { button: '重新登录', }, }, + demo_app: { + notification: '请使用管理员账号密码登录本示例应用', + title: '恭喜!你已成功登录到示例应用!', + subtitle: '以下是你本次登录的用户信息:', + username: '用户名:', + user_id: '用户 ID:', + sign_out: '登出', + continue_explore: '或继续探索', + customize_sign_in_experience: '自定义登录体验', + enable_passwordless: '启用无密码登录', + add_social_connector: '添加社会化连接器', + }, }; const errors = { diff --git a/packages/console/src/scss/_fonts.scss b/packages/shared/scss/_fonts.scss similarity index 100% rename from packages/console/src/scss/_fonts.scss rename to packages/shared/scss/_fonts.scss diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9636c6598..d6cf57af0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -900,6 +900,7 @@ importers: packages/demo-app: specifiers: + '@logto/phrases': ^0.1.0 '@logto/react': ^0.1.14 '@logto/schemas': ^0.1.0 '@logto/shared': ^0.1.0 @@ -911,16 +912,21 @@ importers: '@silverhand/ts-config-react': ^0.14.0 '@types/react': ^17.0.14 '@types/react-dom': ^17.0.9 + cross-env: ^7.0.3 eslint: ^8.10.0 + i18next: ^21.6.12 + i18next-browser-languagedetector: ^6.1.3 lint-staged: ^13.0.0 parcel: 2.5.0 postcss: ^8.4.6 prettier: ^2.3.2 react: ^17.0.2 react-dom: ^17.0.2 + react-i18next: ^11.15.4 stylelint: ^14.8.2 typescript: ^4.7.2 devDependencies: + '@logto/phrases': link:../phrases '@logto/react': 0.1.14_react@17.0.2 '@logto/schemas': link:../schemas '@logto/shared': link:../shared @@ -932,13 +938,17 @@ importers: '@silverhand/ts-config-react': 0.14.0_typescript@4.7.2 '@types/react': 17.0.37 '@types/react-dom': 17.0.11 + cross-env: 7.0.3 eslint: 8.10.0 + i18next: 21.6.12 + i18next-browser-languagedetector: 6.1.3 lint-staged: 13.0.0 parcel: 2.5.0_postcss@8.4.14 postcss: 8.4.14 prettier: 2.5.1 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 + react-i18next: 11.15.4_fq32mavcto3l2u7t3zyhvdh4yu stylelint: 14.8.2 typescript: 4.7.2