Skip to content

Commit

Permalink
feat: demo app dev panel
Browse files Browse the repository at this point in the history
  • Loading branch information
gao-sun committed Jun 25, 2024
1 parent bede80e commit f4525f0
Show file tree
Hide file tree
Showing 23 changed files with 478 additions and 118 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-moose-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@logto/demo-app": minor
---

add dev panel
2 changes: 1 addition & 1 deletion packages/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@logto/language-kit": "workspace:^1.1.0",
"@logto/phrases": "workspace:^1.11.0",
"@logto/phrases-experience": "workspace:^1.6.1",
"@logto/react": "^3.0.8",
"@logto/react": "^3.0.11",
"@logto/schemas": "workspace:^1.17.0",
"@logto/shared": "workspace:^3.1.1",
"@mdx-js/react": "^1.6.22",
Expand Down
3 changes: 2 additions & 1 deletion packages/demo-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@logto/core-kit": "workspace:^2.4.0",
"@logto/language-kit": "workspace:^1.1.0",
"@logto/phrases": "workspace:^1.10.0",
"@logto/react": "^3.0.8",
"@logto/react": "^3.0.11",
"@logto/schemas": "workspace:^1.15.0",
"@parcel/core": "2.9.3",
"@parcel/transformer-sass": "2.9.3",
Expand All @@ -37,6 +37,7 @@
"eslint": "^8.56.0",
"i18next": "^22.4.15",
"i18next-browser-languagedetector": "^8.0.0",
"jose": "^5.0.0",
"lint-staged": "^15.0.0",
"parcel": "2.9.3",
"postcss": "^8.4.31",
Expand Down
129 changes: 94 additions & 35 deletions packages/demo-app/src/App.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,113 @@
@use '@logto/core-kit/scss/console-themes' as themes;

.app {
input {
background-color: var(--color-layer-1);
font: var(--font-body-2);
color: var(--color-text);
padding: 0 _.unit(3);
height: 36px;
border: 1px solid var(--color-border);
outline: 3px solid transparent;
border-radius: 6px;
}

.button {
display: inline-block;
user-select: none;
border: 1px solid var(--color-border);
background-color: var(--color-layer-1);
border-radius: 8px;
padding: _.unit(3) _.unit(6);
font: var(--font-label-2);
color: var(--color-text);
transition: background ease-in-out 0.2s;

&:hover {
cursor: pointer;
background: var(--color-hover);
}

&:focus {
outline: 3px solid var(--color-focused-variant);
}
}


.card {
background: var(--color-layer-1);
border-radius: 16px;
position: absolute;
left: 50%;
top: 50%;
width: 640px;
height: 640px;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
font-size: 14px;
line-height: 20px;

img {
margin-top: _.unit(25);
width: 120px;
height: 120px;
}

.title {
margin-top: _.unit(6);
color: var(--color-neutral-10);
font: var(--font-title-2);
}

.text {
margin-top: _.unit(1);
font: var(--font-body-2);
color: var(--color-text-secondary);
}

&.congrats {
position: absolute;
left: 50%;
top: 50%;
align-items: center;
text-align: center;
width: 640px;
height: 640px;
transform: translate(-50%, -50%);

.title {
margin-top: _.unit(6);
}

.text {
margin-top: _.unit(1);
}

.button {
margin-top: _.unit(8);
}
}

&.devPanel {
max-width: 800px;
width: 25vw;
position: fixed;
left: _.unit(2);
top: _.unit(2);
padding: _.unit(4);
gap: _.unit(3);

.item {
margin: _.unit(2) 0;
display: flex;
flex-direction: column;
gap: _.unit(1);
}

.button {
align-self: flex-end;
}

.action {
display: flex;
justify-content: space-between;
align-items: center;
}
}

img {
margin-top: _.unit(25);
width: 120px;
height: 120px;
}

.infoCard {
margin-top: _.unit(4);
padding: _.unit(4);
Expand All @@ -61,25 +134,6 @@
}
}

.button {
user-select: none;
margin-top: _.unit(8);
border: 1px solid var(--color-border);
border-radius: 8px;
padding: _.unit(3) _.unit(6);
font: var(--font-label-2);
color: var(--color-text);
transition: background ease-in-out 0.2s;

&:hover {
cursor: pointer;
background: var(--color-hover);
}

&:focus {
outline: 3px solid var(--color-focused-variant);
}
}

.continue {
margin-top: _.unit(12);
Expand Down Expand Up @@ -121,6 +175,11 @@
}
}

.error {
color: var(--color-neutral-10);
margin: _.unit(3);
}

@media (prefers-color-scheme: light) {
body {
@include themes.light;
Expand Down
72 changes: 63 additions & 9 deletions packages/demo-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
import type { IdTokenClaims } from '@logto/react';
import { LogtoProvider, useLogto, Prompt, UserScope } from '@logto/react';
import { type IdTokenClaims, LogtoProvider, useLogto, type Prompt } from '@logto/react';
import { demoAppApplicationId } from '@logto/schemas';
import { useEffect, useState } from 'react';
import { useCallback, 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 DevPanel from './DevPanel';
import congratsDark from './assets/congrats-dark.svg';
import congrats from './assets/congrats.svg';
import initI18n from './i18n/init';
import { getLocalData, setLocalData } from './utils';

void initI18n();

const Main = () => {
const params = new URL(window.location.href).searchParams;
const { isAuthenticated, isLoading, getIdTokenClaims, signIn, signOut } = useLogto();
const [user, setUser] = useState<Pick<IdTokenClaims, 'sub' | 'username'>>();
const { t } = useTranslation(undefined, { keyPrefix: 'demo_app' });
const isInCallback = Boolean(new URL(window.location.href).searchParams.get('code'));
const isInCallback = Boolean(params.get('code'));
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const [congratsIcon, setCongratsIcon] = useState<string>(isDarkMode ? congratsDark : congrats);
const [showDevPanel, setShowDevPanel] = useState(getLocalData('ui').showDevPanel ?? false);
const error = params.get('error');
const errorDescription = params.get('error_description');

const toggleDevPanel = useCallback(() => {
setShowDevPanel((previous) => {
setLocalData('ui', { showDevPanel: !previous });
return !previous;
});
}, []);

useEffect(() => {
if (isInCallback || isLoading) {
if (isInCallback || isLoading || error) {
return;
}

Expand All @@ -43,7 +56,7 @@ const Main = () => {
extraParams: Object.fromEntries(new URLSearchParams(window.location.search).entries()),
});
}
}, [getIdTokenClaims, isAuthenticated, isInCallback, isLoading, signIn, user]);
}, [error, getIdTokenClaims, isAuthenticated, isInCallback, isLoading, signIn, user]);

useEffect(() => {
const onThemeChange = (event: MediaQueryListEvent) => {
Expand All @@ -64,13 +77,37 @@ const Main = () => {
return <Callback />;
}

if (error) {
return (
<div className={styles.app}>
<div className={styles.error}>
<p>
Error occurred: {error}
<br />
{errorDescription}
</p>
<button
className={styles.button}
onClick={() => {
setLocalData('config', {});
window.location.assign('/demo-app');
}}
>
Reset config and retry
</button>
</div>
</div>
);
}

if (!isAuthenticated || !user) {
return null;
}

return (
<div className={styles.app}>
<div className={styles.card}>
{showDevPanel && <DevPanel />}
<div className={[styles.card, styles.congrats].join(' ')}>
{congratsIcon && <img src={congratsIcon} alt="Congrats" />}
<div className={styles.title}>{t('title')}</div>
<div className={styles.text}>{t('subtitle')}</div>
Expand Down Expand Up @@ -99,19 +136,36 @@ const Main = () => {
>
{t('sign_out')}
</div>
<div
role="button"
tabIndex={0}
className={styles.button}
onClick={toggleDevPanel}
onKeyDown={({ key }) => {
if (key === 'Enter' || key === ' ') {
toggleDevPanel();
}
}}
>
{showDevPanel ? 'Close' : 'Open'} dev panel
</div>
</div>
</div>
);
};

const App = () => {
const config = getLocalData('config');

return (
<LogtoProvider
config={{
endpoint: window.location.origin,
appId: demoAppApplicationId,
prompt: [Prompt.Login, Prompt.Consent],
scopes: [UserScope.Organizations, UserScope.OrganizationRoles],
// eslint-disable-next-line no-restricted-syntax
prompt: config.prompt ? (config.prompt.split(' ') as Prompt[]) : [],
scopes: config.scope ? config.scope.split(' ') : [],
resources: config.resource ? config.resource.split(' ') : [],
}}
>
<Main />
Expand Down
Loading

0 comments on commit f4525f0

Please sign in to comment.