feat(samples): add sample plugin
This commit is contained in:
parent
a0981e2668
commit
34f2d708dd
34
package.json
34
package.json
@ -41,45 +41,45 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pm2": "^5.3.1",
|
"pm2": "^5.4.2",
|
||||||
"rimraf": "^3.0.2"
|
"rimraf": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^16.3.0",
|
"@commitlint/cli": "^16.3.0",
|
||||||
"@commitlint/config-conventional": "^16.2.4",
|
"@commitlint/config-conventional": "^16.2.4",
|
||||||
"@commitlint/prompt-cli": "^16.3.0",
|
"@commitlint/prompt-cli": "^16.3.0",
|
||||||
"@eslint/compat": "^1.1.1",
|
"@eslint/compat": "^1.2.0",
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
"@eslint/js": "^9.10.0",
|
"@eslint/js": "^9.12.0",
|
||||||
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
|
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
|
||||||
"@tachybase/build": "workspace:*",
|
"@tachybase/build": "workspace:*",
|
||||||
"@tachybase/cli": "workspace:*",
|
"@tachybase/cli": "workspace:*",
|
||||||
"@tachybase/preset-tachybase": "workspace:*",
|
"@tachybase/preset-tachybase": "workspace:*",
|
||||||
"@tachybase/test": "workspace:*",
|
"@tachybase/test": "workspace:*",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.11",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.1",
|
||||||
"auto-changelog": "^2.4.0",
|
"auto-changelog": "^2.5.0",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.7.7",
|
||||||
"commander": "^9.5.0",
|
"commander": "^9.5.0",
|
||||||
"eslint": "^9.10.0",
|
"eslint": "^9.12.0",
|
||||||
"eslint-plugin-jest-dom": "^5.4.0",
|
"eslint-plugin-jest-dom": "^5.4.0",
|
||||||
"eslint-plugin-react": "^7.33.0",
|
"eslint-plugin-react": "^7.37.1",
|
||||||
"eslint-plugin-testing-library": "^5.11.1",
|
"eslint-plugin-testing-library": "^5.11.1",
|
||||||
"globals": "^15.9.0",
|
"globals": "^15.11.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.1.6",
|
||||||
"lint-staged": "^13.3.0",
|
"lint-staged": "^13.3.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-packagejson": "^2.5.0",
|
"prettier-plugin-packagejson": "^2.5.3",
|
||||||
"prettier-plugin-sort-json": "^4.0.0",
|
"prettier-plugin-sort-json": "^4.0.0",
|
||||||
"prettier-plugin-sql": "^0.17.1",
|
"prettier-plugin-sql": "^0.17.1",
|
||||||
"pretty-format": "^24.9.0",
|
"pretty-format": "^24.9.0",
|
||||||
"pretty-quick": "^3.3.1",
|
"pretty-quick": "^3.3.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"tsx": "^4.15.2",
|
"tsx": "^4.19.1",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
"typescript-eslint": "^8.4.0",
|
"typescript-eslint": "^8.9.0",
|
||||||
"umi": "^4.3.3",
|
"umi": "^4.3.27",
|
||||||
"vitest": "^1.6.0"
|
"vitest": "^1.6.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.12.1",
|
"packageManager": "pnpm@9.12.1",
|
||||||
|
2
packages/plugins/@samples/plugin-replace-page/.npmignore
Executable file
2
packages/plugins/@samples/plugin-replace-page/.npmignore
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
/node_modules
|
||||||
|
/src
|
1
packages/plugins/@samples/plugin-replace-page/README.md
Executable file
1
packages/plugins/@samples/plugin-replace-page/README.md
Executable file
@ -0,0 +1 @@
|
|||||||
|
# @samples/plugin-replace-page
|
2
packages/plugins/@samples/plugin-replace-page/client.d.ts
vendored
Executable file
2
packages/plugins/@samples/plugin-replace-page/client.d.ts
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './dist/client';
|
||||||
|
export { default } from './dist/client';
|
1
packages/plugins/@samples/plugin-replace-page/client.js
Executable file
1
packages/plugins/@samples/plugin-replace-page/client.js
Executable file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./dist/client/index.js');
|
15
packages/plugins/@samples/plugin-replace-page/package.json
Executable file
15
packages/plugins/@samples/plugin-replace-page/package.json
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "@samples/plugin-replace-page",
|
||||||
|
"version": "0.21.61",
|
||||||
|
"main": "dist/server/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"antd": "^5.18.3",
|
||||||
|
"react-router-dom": "^6.11.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tachybase/client": "workspace:*",
|
||||||
|
"@tachybase/plugin-auth": "workspace:*",
|
||||||
|
"@tachybase/server": "workspace:*",
|
||||||
|
"@tachybase/test": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
2
packages/plugins/@samples/plugin-replace-page/server.d.ts
vendored
Executable file
2
packages/plugins/@samples/plugin-replace-page/server.d.ts
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './dist/server';
|
||||||
|
export { default } from './dist/server';
|
1
packages/plugins/@samples/plugin-replace-page/server.js
Executable file
1
packages/plugins/@samples/plugin-replace-page/server.js
Executable file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./dist/server/index.js');
|
65
packages/plugins/@samples/plugin-replace-page/src/client/AuthLayout.tsx
Executable file
65
packages/plugins/@samples/plugin-replace-page/src/client/AuthLayout.tsx
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { css, PoweredBy, useAPIClient, useRequest, useSystemSettings } from '@tachybase/client';
|
||||||
|
import { AuthenticatorsContext } from '@tachybase/plugin-auth/client';
|
||||||
|
|
||||||
|
import { Col, Row } from 'antd';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
|
||||||
|
import authImg from './image.png';
|
||||||
|
|
||||||
|
export function CustomAuthLayout() {
|
||||||
|
const { data } = useSystemSettings();
|
||||||
|
const api = useAPIClient();
|
||||||
|
const { data: authenticators = [], error } = useRequest(() =>
|
||||||
|
api
|
||||||
|
.resource('authenticators')
|
||||||
|
.publicList()
|
||||||
|
.then((res) => {
|
||||||
|
return res?.data?.data || [];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row style={{ height: '100%' }}>
|
||||||
|
<Col xs={{ span: 0 }} md={{ span: 12 }}>
|
||||||
|
<img
|
||||||
|
src={authImg}
|
||||||
|
style={{
|
||||||
|
objectFit: 'cover',
|
||||||
|
objectPosition: 'center',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
maxWidth: '100%',
|
||||||
|
display: 'block',
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col xs={{ span: 24 }} md={{ span: 12 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
maxWidth: 320,
|
||||||
|
margin: '0 auto',
|
||||||
|
paddingTop: '20vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h1>{data?.data?.title}</h1>
|
||||||
|
<AuthenticatorsContext.Provider value={authenticators as any}>
|
||||||
|
<Outlet />
|
||||||
|
</AuthenticatorsContext.Provider>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
position: absolute;
|
||||||
|
bottom: 24px;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
text-align: center;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<PoweredBy />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
BIN
packages/plugins/@samples/plugin-replace-page/src/client/image.png
Executable file
BIN
packages/plugins/@samples/plugin-replace-page/src/client/image.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 3.8 MiB |
13
packages/plugins/@samples/plugin-replace-page/src/client/index.tsx
Executable file
13
packages/plugins/@samples/plugin-replace-page/src/client/index.tsx
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
import { Plugin } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { CustomAuthLayout } from './AuthLayout';
|
||||||
|
|
||||||
|
export class PluginReplacePageClient extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.router.add('auth', {
|
||||||
|
Component: CustomAuthLayout,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginReplacePageClient;
|
2
packages/plugins/@samples/plugin-replace-page/src/index.ts
Executable file
2
packages/plugins/@samples/plugin-replace-page/src/index.ts
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './server';
|
||||||
|
export { default } from './server';
|
1
packages/plugins/@samples/plugin-replace-page/src/server/index.ts
Executable file
1
packages/plugins/@samples/plugin-replace-page/src/server/index.ts
Executable file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './plugin';
|
28
packages/plugins/@samples/plugin-replace-page/src/server/plugin.ts
Executable file
28
packages/plugins/@samples/plugin-replace-page/src/server/plugin.ts
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
import { Plugin } from '@tachybase/server';
|
||||||
|
|
||||||
|
export class PluginReplacePageServer extends Plugin {
|
||||||
|
async afterAdd() {}
|
||||||
|
|
||||||
|
async beforeLoad() {}
|
||||||
|
|
||||||
|
async load() {
|
||||||
|
this.app.db.collection({
|
||||||
|
name: 'posts',
|
||||||
|
// 字段类型参考 packages/core/database/src/fields,常见的有 string、text、integer 等
|
||||||
|
fields: [{ type: 'string', name: 'title' }],
|
||||||
|
});
|
||||||
|
await this.app.db.sync();
|
||||||
|
// 方便做测试,权限设置为公开
|
||||||
|
this.app.acl.allow('posts', '*', 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
async install() {}
|
||||||
|
|
||||||
|
async afterEnable() {}
|
||||||
|
|
||||||
|
async afterDisable() {}
|
||||||
|
|
||||||
|
async remove() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginReplacePageServer;
|
BIN
packages/plugins/@tachybase/plugin-todo-page.rar
Normal file
BIN
packages/plugins/@tachybase/plugin-todo-page.rar
Normal file
Binary file not shown.
@ -20,7 +20,7 @@
|
|||||||
1. **克隆项目**:
|
1. **克隆项目**:
|
||||||
```bash
|
```bash
|
||||||
# git clone 项目
|
# git clone 项目
|
||||||
git clone https://git.daoyoucloud.com:8443/daoyoucloud/tachybase.git
|
git clone https://git.daoyoucloud.com/ruiling/tachybase_todo.git
|
||||||
# 安装依赖(必须使用 pnpm)
|
# 安装依赖(必须使用 pnpm)
|
||||||
cd tachybase
|
cd tachybase
|
||||||
pnpm i
|
pnpm i
|
||||||
@ -77,14 +77,14 @@ pnpm dev
|
|||||||
|
|
||||||
### 文件说明
|
### 文件说明
|
||||||
|
|
||||||
#### 1. `todoList.js`
|
#### 1. `todoList.tsx`
|
||||||
- **作用**:定义了 `todoList` 组件,用于渲染待办事项页面。
|
- **作用**:定义了 `todoList` 组件,用于渲染待办事项页面。
|
||||||
- **功能**:
|
- **功能**:
|
||||||
- 通过 API 接口获取待办事项列表。
|
- 通过 API 接口获取待办事项列表。
|
||||||
- 支持增、删、改、查、标记完成的功能。
|
- 支持增、删、改、查、标记完成的功能。
|
||||||
- 使用 React 状态管理,用户可以在页面上实时操作待办事项。
|
- 使用 React 状态管理,用户可以在页面上实时操作待办事项。
|
||||||
|
|
||||||
#### 2. `PluginTodoPageClient.js`
|
#### 2. `index.tsx`
|
||||||
- **作用**:作为插件的入口文件,负责将 Todo 页面的路由、组件注册到系统的插件管理中。
|
- **作用**:作为插件的入口文件,负责将 Todo 页面的路由、组件注册到系统的插件管理中。
|
||||||
- **功能**:
|
- **功能**:
|
||||||
- 扩展系统的路由和页面展示功能。
|
- 扩展系统的路由和页面展示功能。
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
export function TodoList() {
|
export function TodoLists() {
|
||||||
const [todos, setTodos] = useState([]);
|
const [todos, setTodos] = useState([]);
|
||||||
const [newTodo, setNewTodo] = useState('');
|
const [newTodo, setNewTodo] = useState('');
|
||||||
const [editingId, setEditingId] = useState(null);
|
const [editingId, setEditingId] = useState(null);
|
||||||
|
@ -1,29 +1,24 @@
|
|||||||
/* RESETS */
|
/* RESETS */
|
||||||
*
|
*,
|
||||||
*::before,
|
*::before,
|
||||||
*::after {
|
*::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:focus {
|
*:focus {
|
||||||
outline: 3px dashed #228bec;
|
outline: 3px dashed #228bec;
|
||||||
outline-offset: 0;
|
outline-offset: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font: 62.5% / 1.15 sans-serif;
|
font: 62.5% / 1.15 sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2 {
|
h2 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -38,11 +33,9 @@ button {
|
|||||||
-moz-osx-font-smoothing: inherit;
|
-moz-osx-font-smoothing: inherit;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button::-moz-focus-inner {
|
button::-moz-focus-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
optgroup,
|
optgroup,
|
||||||
@ -53,16 +46,13 @@ textarea {
|
|||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
button,
|
button,
|
||||||
input {
|
input {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"] {
|
input[type="text"] {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 68rem;
|
max-width: 68rem;
|
||||||
@ -73,74 +63,234 @@ body {
|
|||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
color: #4d4d4d;
|
color: #4d4d4d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 620px) {
|
@media screen and (min-width: 620px) {
|
||||||
body {
|
body {
|
||||||
font-size: 1.9rem;
|
font-size: 1.9rem;
|
||||||
line-height: 1.31579;
|
line-height: 1.31579;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*END RESETS*/
|
/*END RESETS*/
|
||||||
/* GLOBAL STYLES */
|
/* GLOBAL STYLES */
|
||||||
.form-group>input[type="text"] {
|
.form-group > input[type="text"] {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding: 0.8rem 1rem 0.7rem;
|
padding: 0.8rem 1rem 0.7rem;
|
||||||
border: 0.2rem solid #4d4d4d;
|
border: 0.2rem solid #4d4d4d;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.toggle-btn {
|
.btn.toggle-btn {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: #d3d3d3;
|
border-color: #d3d3d3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.toggle-btn[aria-pressed="true"] {
|
.btn.toggle-btn[aria-pressed="true"] {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
border-color: #4d4d4d;
|
border-color: #4d4d4d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn__danger {
|
.btn__danger {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #ca3c3c;
|
background-color: #ca3c3c;
|
||||||
border-color: #bd2130;
|
border-color: #bd2130;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn__filter {
|
.btn__filter {
|
||||||
border-color: lightgrey;
|
border-color: lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn__primary {
|
.btn__primary {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
.btn-group > * {
|
||||||
.btn-group>* {
|
|
||||||
flex: 1 1 49%;
|
flex: 1 1 49%;
|
||||||
}
|
}
|
||||||
|
.btn-group > * + * {
|
||||||
.btn-group>*+* {
|
|
||||||
margin-left: 0.8rem;
|
margin-left: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-wrapper {
|
.label-wrapper {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.visually-hidden {
|
.visually-hidden {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
overflow
|
overflow: hidden;
|
||||||
|
clip: rect(1px 1px 1px 1px);
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
[class*="stack"] > * {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.stack-small > * + * {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
}
|
||||||
|
.stack-large > * + * {
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 550px) {
|
||||||
|
.stack-small > * + * {
|
||||||
|
margin-top: 1.4rem;
|
||||||
|
}
|
||||||
|
.stack-large > * + * {
|
||||||
|
margin-top: 2.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.stack-exception {
|
||||||
|
margin-top: 1.2rem;
|
||||||
|
}
|
||||||
|
/* END GLOBAL STYLES */
|
||||||
|
.todoapp {
|
||||||
|
background: #fff;
|
||||||
|
margin: 2rem 0 4rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
position: relative;
|
||||||
|
box-shadow:
|
||||||
|
0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||||
|
0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 550px) {
|
||||||
|
.todoapp {
|
||||||
|
padding: 4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.todoapp > * {
|
||||||
|
max-width: 50rem;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.todoapp > form {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.todoapp > h1 {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.label__lg {
|
||||||
|
line-height: 1.01567;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 0.8rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.input__lg {
|
||||||
|
padding: 2rem;
|
||||||
|
border: 2px solid #000;
|
||||||
|
}
|
||||||
|
.input__lg:focus {
|
||||||
|
border-color: #4d4d4d;
|
||||||
|
box-shadow: inset 0 0 0 2px;
|
||||||
|
}
|
||||||
|
[class*="__lg"] {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.9rem;
|
||||||
|
}
|
||||||
|
[class*="__lg"]:not(:last-child) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 620px) {
|
||||||
|
[class*="__lg"] {
|
||||||
|
font-size: 2.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filters {
|
||||||
|
width: 100%;
|
||||||
|
margin: unset auto;
|
||||||
|
}
|
||||||
|
/* Todo item styles */
|
||||||
|
.todo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.todo > * {
|
||||||
|
flex: 0 0 100%;
|
||||||
|
}
|
||||||
|
.todo-text {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 4.4rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border: 2px solid #565656;
|
||||||
|
}
|
||||||
|
.todo-text:focus {
|
||||||
|
box-shadow: inset 0 0 0 2px;
|
||||||
|
}
|
||||||
|
/* CHECKBOX STYLES */
|
||||||
|
.c-cb {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
min-height: 44px;
|
||||||
|
padding-left: 40px;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
.c-cb > label::before,
|
||||||
|
.c-cb > input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
top: -2px;
|
||||||
|
left: -2px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
.c-cb > input[type="checkbox"] {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.c-cb > label {
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 8px 15px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
.c-cb > label::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
border: 2px solid currentcolor;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.c-cb > input[type="checkbox"]:focus + label::before {
|
||||||
|
border-width: 4px;
|
||||||
|
outline: 3px dashed #228bec;
|
||||||
|
}
|
||||||
|
.c-cb > label::after {
|
||||||
|
box-sizing: content-box;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 11px;
|
||||||
|
left: 9px;
|
||||||
|
width: 18px;
|
||||||
|
height: 7px;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
border: solid;
|
||||||
|
border-width: 0 0 5px 5px;
|
||||||
|
border-top-color: transparent;
|
||||||
|
opacity: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.c-cb > input[type="checkbox"]:checked + label::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
|
|
||||||
import { TodoList } from './TodoList';
|
import { TodoLists } from './TodoList';
|
||||||
|
|
||||||
export class PluginTodoPageClient extends Plugin {
|
export class PluginTodoPageClient extends Plugin {
|
||||||
async afterAdd() {
|
async afterAdd() {
|
||||||
// await this.app.pm.add()
|
// await this.app.pm.add()
|
||||||
}
|
}
|
||||||
|
|
||||||
async beforeLoad() {} // You can get and modify the app instance here
|
async beforeLoad() {}
|
||||||
|
|
||||||
|
// You can get and modify the app instance here
|
||||||
async load() {
|
async load() {
|
||||||
this.router.add('todo', {
|
this.router.add('todo', {
|
||||||
path: '/todo',
|
path: '/todo',
|
||||||
Component: TodoList,
|
Component: TodoLists,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.pluginSettingsManager.add('todo', {
|
this.app.pluginSettingsManager.add('todo', {
|
||||||
title: 'todo',
|
title: 'Todo',
|
||||||
icon: 'ApiOutlined',
|
icon: 'ApiOutlined',
|
||||||
Component: TodoList,
|
Component: TodoLists,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export { default } from './plugin';
|
@ -1,10 +1,10 @@
|
|||||||
import { Plugin } from '@tachybase/server';
|
import { Plugin } from '@tachybase/server';
|
||||||
|
|
||||||
export class PluginTodoServer extends Plugin {
|
export class PluginTodoPageServer extends Plugin {
|
||||||
async load() {
|
async load() {
|
||||||
// 定义一个 todo 数据表,包含 title 和 completed 字段
|
// 定义一个 todo 数据表,包含 title 和 completed 字段
|
||||||
this.app.db.collection({
|
this.app.db.collection({
|
||||||
name: 'todos',
|
name: 'todo',
|
||||||
fields: [
|
fields: [
|
||||||
{ type: 'string', name: 'title' },
|
{ type: 'string', name: 'title' },
|
||||||
{ type: 'boolean', name: 'completed', default: false },
|
{ type: 'boolean', name: 'completed', default: false },
|
||||||
@ -13,8 +13,8 @@ export class PluginTodoServer extends Plugin {
|
|||||||
await this.app.db.sync();
|
await this.app.db.sync();
|
||||||
|
|
||||||
// 设置 todos 数据表的访问权限为公开
|
// 设置 todos 数据表的访问权限为公开
|
||||||
this.app.acl.allow('todos', '*', 'public');
|
this.app.acl.allow('todo', '*', 'public');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PluginTodoServer;
|
export default PluginTodoPageServer;
|
||||||
|
3732
pnpm-lock.yaml
3732
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user