update
This commit is contained in:
parent
894d296159
commit
e729426370
@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@3rapp/code-config/react')],
|
||||
extends: [require.resolve('@3rapp/code-config/stylelint')],
|
||||
};
|
@ -12,17 +12,21 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@3rapp/common": "workspace:*",
|
||||
"@3rapp/api": "workspace:*",
|
||||
"@3rapp/common": "workspace:*",
|
||||
"@ant-design/cssinjs": "^1.20.0",
|
||||
"antd": "^5.17.0",
|
||||
"axios": "^1.6.8",
|
||||
"clsx": "^2.1.1",
|
||||
"deepmerge": "^4.3.1",
|
||||
"immer": "^10.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@3rapp/code-config": "workspace:*",
|
||||
"@types/lodash": "^4.17.1",
|
||||
"@types/node": "^20.12.10",
|
||||
"@types/react": "^18.2.66",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
|
@ -1,5 +1,5 @@
|
||||
.app {
|
||||
@apply tw-bg-yellow-300 tw-flex tw-flex-auto tw-items-center tw-justify-center;
|
||||
@apply tw-flex tw-flex-auto tw-flex-wrap tw-items-center tw-justify-center;
|
||||
|
||||
& > .container {
|
||||
@apply tw-shadow-md tw-p-5 tw-bg-black tw-text-center tw-text-white tw-text-lg;
|
||||
|
@ -1,69 +1,30 @@
|
||||
// src/app.tsx
|
||||
|
||||
import { PostEntity } from '@3rapp/api/modules/content/entities/post.entity';
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { Button, ConfigProvider, theme, App as AntdApp } from 'antd';
|
||||
import { ConfigProvider, theme, App as AntdApp } from 'antd';
|
||||
// import 'dayjs/locale/zh-cn';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
|
||||
import axios from 'axios';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { FC } from 'react';
|
||||
|
||||
import $styles from './app.module.css';
|
||||
|
||||
const getPosts = async () => {
|
||||
let data: PostEntity[] = [];
|
||||
try {
|
||||
const res = await axios.get('/api/posts');
|
||||
data = res.data;
|
||||
} catch (err) {
|
||||
console.log('Error:', err);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
import EffectDemo from './components/demo/effect';
|
||||
import RefDemo from './components/demo/ref';
|
||||
import StateDemo from './components/demo/state';
|
||||
|
||||
const App: FC = () => {
|
||||
const [data, setData] = useState<PostEntity[]>([]);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setData(await getPosts());
|
||||
})();
|
||||
}, []);
|
||||
return (
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
theme={{
|
||||
algorithm: theme.defaultAlgorithm,
|
||||
token: {
|
||||
colorPrimary: '#00B96B',
|
||||
},
|
||||
components: {
|
||||
Layout: {
|
||||
colorBgBody: '',
|
||||
},
|
||||
},
|
||||
token: {},
|
||||
}}
|
||||
>
|
||||
<StyleProvider hashPriority="high">
|
||||
<AntdApp>
|
||||
<div className={$styles.app}>
|
||||
<div className={$styles.container}>
|
||||
欢迎来到3R教室,这是<span>React课程第一节</span>
|
||||
<Button
|
||||
type="primary"
|
||||
className="!bg-lime-400 !text-emerald-900"
|
||||
href="https://pincman.com/3r"
|
||||
target="_blank"
|
||||
>
|
||||
点此打开
|
||||
</Button>
|
||||
<h2>文章列表</h2>
|
||||
<ul>
|
||||
{data.map((item) => (
|
||||
<li key={item.id}>{item.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<StateDemo />
|
||||
<EffectDemo />
|
||||
<RefDemo />
|
||||
</div>
|
||||
</AntdApp>
|
||||
</StyleProvider>
|
||||
|
BIN
apps/admin/src/assets/images/bg-dark.png
Normal file
BIN
apps/admin/src/assets/images/bg-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 266 KiB |
BIN
apps/admin/src/assets/images/bg-light.png
Normal file
BIN
apps/admin/src/assets/images/bg-light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 923 KiB |
43
apps/admin/src/components/demo/effect.tsx
Normal file
43
apps/admin/src/components/demo/effect.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { Button } from 'antd';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
|
||||
import $styles from './style.module.css';
|
||||
|
||||
const EffectDemo: FC = () => {
|
||||
const [red, setRed] = useState<boolean>(false);
|
||||
const [ghost, setGhost] = useState<boolean>(false);
|
||||
const [width, setWidth] = useState(window.innerWidth);
|
||||
const toggleGhostBtn = () => setGhost(!ghost);
|
||||
const resizeHandle = () => setWidth(window.innerWidth);
|
||||
useEffect(() => {
|
||||
console.log('浏览器宽度改变');
|
||||
window.addEventListener('resize', resizeHandle);
|
||||
}, [width]);
|
||||
useEffect(() => {
|
||||
console.log('切换幽灵按钮');
|
||||
}, [ghost]);
|
||||
useEffect(() => {
|
||||
console.log('只在第一次或重新渲染组件时触发');
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(() => resolve(true), 1000);
|
||||
});
|
||||
setRed(ghost);
|
||||
})();
|
||||
}, [ghost]);
|
||||
return (
|
||||
<div className={$styles.container}>
|
||||
<h2 className="tw-text-center">useEffect Demo</h2>
|
||||
<p className="tw-text-center tw-py-5">{ghost ? 'ghost' : '普通'}按钮</p>
|
||||
<div className="tw-flex tw-justify-center tw-flex-col">
|
||||
<Button type="primary" onClick={toggleGhostBtn} ghost={ghost} danger={red}>
|
||||
切换按钮样式
|
||||
</Button>
|
||||
<p className="tw-pt-5 tw-text-center">宽度为: {width}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default EffectDemo;
|
75
apps/admin/src/components/demo/ref.tsx
Normal file
75
apps/admin/src/components/demo/ref.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { Button } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import { isNaN, isNil } from 'lodash';
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
FC,
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import $styles from './style.module.css';
|
||||
|
||||
interface RefFunc {
|
||||
focus: () => void;
|
||||
memo: () => number;
|
||||
}
|
||||
|
||||
const MyInput = forwardRef<RefFunc, { value: number; changeValue: (v: number) => void }>(
|
||||
({ value, changeValue }, ref) => {
|
||||
const [local, setLocal] = useState<number | string>(value);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
focus: () => inputRef.current.focus(),
|
||||
memo: () => value,
|
||||
}),
|
||||
[value],
|
||||
);
|
||||
useEffect(() => {
|
||||
changeValue(isNaN(Number(local)) ? 0 : Number(local));
|
||||
}, [changeValue, local]);
|
||||
const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback((e) => {
|
||||
setLocal(e.target.value);
|
||||
}, []);
|
||||
return (
|
||||
<input value={value} ref={inputRef} placeholder="请输入值" onChange={handleChange} />
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const RefDemo: FC = () => {
|
||||
const [count, setCount] = useState(0);
|
||||
const inited = useRef(count);
|
||||
const ref = useRef<RefFunc | null>(null);
|
||||
useEffect(() => {
|
||||
ref.current.focus();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (inited.current !== count) {
|
||||
inited.current = count;
|
||||
console.log('changed');
|
||||
}
|
||||
}, [count]);
|
||||
return (
|
||||
<div className={clsx($styles.container, 'tw-w-[20rem]')}>
|
||||
<h2 className="tw-text-center">useRef Demo</h2>
|
||||
<p className="tw-text-center tw-py-5">{count}</p>
|
||||
<div className="tw-flex tw-justify-around">
|
||||
<Button onClick={() => setCount(Math.ceil(Math.random() * 10))} type="dashed">
|
||||
变化
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
{!isNil(ref.current) && <p className="tw-my-3">前一个值:{ref.current.memo()}</p>}
|
||||
<MyInput ref={ref} value={count} changeValue={setCount} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default RefDemo;
|
29
apps/admin/src/components/demo/state.tsx
Normal file
29
apps/admin/src/components/demo/state.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { Button } from 'antd';
|
||||
import { clsx } from 'clsx';
|
||||
import { FC, useState } from 'react';
|
||||
|
||||
import $styles from './style.module.css';
|
||||
|
||||
const StateDemo: FC = () => {
|
||||
const [count, setCount] = useState(1);
|
||||
const [isShow, toggleShow] = useState(true);
|
||||
|
||||
return (
|
||||
<div className={clsx($styles.container, 'tw-w-[20rem]')}>
|
||||
<h2 className="tw-text-center">useState Demo</h2>
|
||||
{isShow && <p className="tw-text-center tw-py-5">{count}</p>}
|
||||
<div className="tw-flex tw-justify-around">
|
||||
<Button onClick={() => setCount(count + 1)} type="dashed">
|
||||
增加
|
||||
</Button>
|
||||
<Button onClick={() => setCount(count - 1)} type="dashed">
|
||||
减少
|
||||
</Button>
|
||||
<Button onClick={() => toggleShow(!isShow)} type="dashed">
|
||||
{isShow ? '显示' : '隐藏'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default StateDemo;
|
9
apps/admin/src/components/demo/style.module.css
Normal file
9
apps/admin/src/components/demo/style.module.css
Normal file
@ -0,0 +1,9 @@
|
||||
.container {
|
||||
@apply tw-bg-neutral-100/40 tw-shadow-black/20 tw-backdrop-blur-sm tw-shadow-md tw-rounded-md tw-p-5 tw-m-5 tw-min-w-[20rem];
|
||||
}
|
||||
|
||||
body(:global(.dark)) {
|
||||
.container {
|
||||
@apply tw-bg-neutral-800/40 tw-shadow-slate-100/30;
|
||||
}
|
||||
}
|
@ -4,3 +4,7 @@ body,
|
||||
.ant-app {
|
||||
@apply tw-h-[100vh] tw-w-full tw-flex tw-p-0 tw-m-0;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply tw-bg-[url(@/assets/images/bg-light.png)];
|
||||
}
|
||||
|
12103
pnpm-lock.yaml
12103
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user