mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(console): init app create form
This commit is contained in:
parent
387ee50684
commit
2196b217fd
10 changed files with 143 additions and 15 deletions
|
@ -26,6 +26,7 @@
|
|||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-i18next": "^11.15.4",
|
||||
"react-modal": "^3.14.4",
|
||||
"react-router-dom": "^6.2.2",
|
||||
"swr": "^1.2.2"
|
||||
},
|
||||
|
@ -39,6 +40,7 @@
|
|||
"@types/lodash.kebabcase": "^4.1.6",
|
||||
"@types/react": "^17.0.14",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-modal": "^3.13.1",
|
||||
"eslint": "^8.10.0",
|
||||
"lint-staged": "^11.1.1",
|
||||
"parcel": "^2.3.1",
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
.app {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { ReactNode } from 'react';
|
||||
import React, { ReactNode, useEffect } from 'react';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
|
@ -11,7 +10,16 @@ type Props = {
|
|||
};
|
||||
|
||||
const AppContent = ({ children, theme }: Props) => {
|
||||
return <div className={classNames(styles.app, styles.web, styles[theme])}>{children}</div>;
|
||||
useEffect(() => {
|
||||
const classes = [styles.web, styles[theme]].filter((value): value is string => Boolean(value));
|
||||
document.body.classList.add(...classes);
|
||||
|
||||
return () => {
|
||||
document.body.classList.remove(...classes);
|
||||
};
|
||||
}, [theme]);
|
||||
|
||||
return <div className={styles.app}>{children}</div>;
|
||||
};
|
||||
|
||||
export default AppContent;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Card = ({ children }: Props) => {
|
||||
return <div className={styles.card}>{children}</div>;
|
||||
const Card = ({ children, className }: Props) => {
|
||||
return <div className={classNames(styles.card, className)}>{children}</div>;
|
||||
};
|
||||
|
||||
export default Card;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
padding: _.unit(8);
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> *:not(:first-child) {
|
||||
margin-left: _.unit(3);
|
||||
}
|
||||
|
||||
> svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import React, { SVGProps } from 'react';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const Close = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M7.05727 7.05703C7.57797 6.53633 8.42219 6.53633 8.94289 7.05703L16.0001 14.1142L23.0573 7.05703C23.578 6.53633 24.4222 6.53633 24.9429 7.05703C25.4636 7.57773 25.4636 8.42195 24.9429 8.94265L17.8857 15.9998L24.9429 23.057C25.4636 23.5777 25.4636 24.4219 24.9429 24.9426C24.4222 25.4633 23.578 25.4633 23.0573 24.9426L16.0001 17.8855L8.94289 24.9426C8.42219 25.4633 7.57797 25.4633 7.05727 24.9426C6.53657 24.4219 6.53657 23.5777 7.05727 23.057L14.1145 15.9998L7.05727 8.94265C6.53657 8.42195 6.53657 7.57773 7.05727 7.05703Z"
|
||||
fill="#333333"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
type Props = {
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
const Create = ({ onClose }: Props) => {
|
||||
return (
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<CardTitle title="applications.create" subtitle="applications.subtitle" />
|
||||
<Close onClick={onClose} />
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Create;
|
|
@ -1,6 +1,7 @@
|
|||
import { Application } from '@logto/schemas';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Modal from 'react-modal';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Button from '@/components/Button';
|
||||
|
@ -9,12 +10,15 @@ import CardTitle from '@/components/CardTitle';
|
|||
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
import { RequestError } from '@/swr';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
|
||||
import Create from './components/Create';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const Applications = () => {
|
||||
const [isCreateFormOpen, setIsCreateFormOpen] = useState(false);
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data, error } = useSWR<Application[], RequestError>('/api/applications');
|
||||
const isLoading = !data && !error;
|
||||
|
@ -23,7 +27,23 @@ const Applications = () => {
|
|||
<Card>
|
||||
<div className={styles.headline}>
|
||||
<CardTitle title="applications.title" subtitle="applications.subtitle" />
|
||||
<Button disabled title="admin_console.applications.create" />
|
||||
<Button
|
||||
title="admin_console.applications.create"
|
||||
onClick={() => {
|
||||
setIsCreateFormOpen(true);
|
||||
}}
|
||||
/>
|
||||
<Modal
|
||||
isOpen={isCreateFormOpen}
|
||||
className={modalStyles.content}
|
||||
overlayClassName={modalStyles.overlay}
|
||||
>
|
||||
<Create
|
||||
onClose={() => {
|
||||
setIsCreateFormOpen(false);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
<table className={styles.table}>
|
||||
<thead>
|
||||
|
|
13
packages/console/src/scss/modal.module.scss
Normal file
13
packages/console/src/scss/modal.module.scss
Normal file
|
@ -0,0 +1,13 @@
|
|||
.content {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
background: rgba(0, 0, 0, 40%);
|
||||
inset: 0;
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
.content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
inset: 0;
|
||||
background: var(--color-background);
|
||||
color: var(--color-body);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ importers:
|
|||
'@types/lodash.kebabcase': ^4.1.6
|
||||
'@types/react': ^17.0.14
|
||||
'@types/react-dom': ^17.0.9
|
||||
'@types/react-modal': ^3.13.1
|
||||
classnames: ^2.3.1
|
||||
eslint: ^8.10.0
|
||||
i18next: ^21.6.12
|
||||
|
@ -45,6 +46,7 @@ importers:
|
|||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
react-i18next: ^11.15.4
|
||||
react-modal: ^3.14.4
|
||||
react-router-dom: ^6.2.2
|
||||
stylelint: ^13.13.1
|
||||
swr: ^1.2.2
|
||||
|
@ -60,6 +62,7 @@ importers:
|
|||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
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
|
||||
swr: 1.2.2_react@17.0.2
|
||||
devDependencies:
|
||||
|
@ -72,6 +75,7 @@ importers:
|
|||
'@types/lodash.kebabcase': 4.1.6
|
||||
'@types/react': 17.0.37
|
||||
'@types/react-dom': 17.0.11
|
||||
'@types/react-modal': 3.13.1
|
||||
eslint: 8.10.0
|
||||
lint-staged: 11.2.6
|
||||
parcel: 2.3.1_postcss@8.4.6
|
||||
|
@ -3566,6 +3570,12 @@ packages:
|
|||
'@types/react': 17.0.37
|
||||
dev: true
|
||||
|
||||
/@types/react-modal/3.13.1:
|
||||
resolution: {integrity: sha512-iY/gPvTDIy6Z+37l+ibmrY+GTV4KQTHcCyR5FIytm182RQS69G5ps4PH2FxtC7bAQ2QRHXMevsBgck7IQruHNg==}
|
||||
dependencies:
|
||||
'@types/react': 17.0.37
|
||||
dev: true
|
||||
|
||||
/@types/react-router-dom/5.3.2:
|
||||
resolution: {integrity: sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==}
|
||||
dependencies:
|
||||
|
@ -6004,6 +6014,10 @@ packages:
|
|||
clone-regexp: 2.2.0
|
||||
dev: true
|
||||
|
||||
/exenv/1.2.2:
|
||||
resolution: {integrity: sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=}
|
||||
dev: false
|
||||
|
||||
/exit/0.1.2:
|
||||
resolution: {integrity: sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -11251,6 +11265,25 @@ packages:
|
|||
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||
dev: true
|
||||
|
||||
/react-lifecycles-compat/3.0.4:
|
||||
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
|
||||
dev: false
|
||||
|
||||
/react-modal/3.14.4_react-dom@17.0.2+react@17.0.2:
|
||||
resolution: {integrity: sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
react: ^0.14.0 || ^15.0.0 || ^16 || ^17
|
||||
react-dom: ^0.14.0 || ^15.0.0 || ^16 || ^17
|
||||
dependencies:
|
||||
exenv: 1.2.2
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-lifecycles-compat: 3.0.4
|
||||
warning: 4.0.3
|
||||
dev: false
|
||||
|
||||
/react-refresh/0.9.0:
|
||||
resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -13245,6 +13278,12 @@ packages:
|
|||
makeerror: 1.0.12
|
||||
dev: true
|
||||
|
||||
/warning/4.0.3:
|
||||
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/wcwidth/1.0.1:
|
||||
resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=}
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue