diff --git a/docs/areact/getting-started.mdx b/docs/areact/getting-started.mdx
new file mode 100644
index 0000000..68573ad
--- /dev/null
+++ b/docs/areact/getting-started.mdx
@@ -0,0 +1,219 @@
+---
+title: 快速上手
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# 快速上手
+:::warning
+本文默认你已经掌握 **ArenaPro(或者ArenaLess)** 插件的基本用法,如未了解,请先阅读[ArenaPro](https://www.yuque.com/box3lab/arenapro)插件文档。
+:::
+本篇文章将让您快速入门Areact,从项目创建、配置到开发、部署。
+
+## 环境要求
+1. VSCode(版本尽可能在1.93左右)
+ :::tip
+ 如果无法使用桌面端VSCode配合AP/AL进行开发,那么可以试一试[vscode.dev](https://vscode.dev)+[ArenaLess](/docs/arenaless/)的组合
+ :::
+2. VSCode扩展 [ArenaPro(AP)](https://www.yuque.com/box3lab/arenapro)或者[ArenaLess(AL)](/docs/arenaless/)
+
+## 创建项目并完成JSX配置
+### 1. 创建项目
+在VSCode中按下Ctrl+Shift+P,输入命令并找到创建项目的命令,运行它。
+:::note
+- 在 ArenaPro 中,这个命令叫`ArenaPro: 新建Arena-Ts项目`
+- 在 ArenaLess 中,这个命令叫`ArenaLess: 创建ArenaLess项目`
+
+这两个扩展创建的项目结构几乎是相同的
+:::
+### 2. 修改文件名和入口点
+- 把 `client/src/clientApp.ts` 重命名为-> `client/src/clientApp.tsx`
+- 将 `dao3.config.json` 中的 `client->entry` 改为 `src/clientApp.tsx`(类似下面这样)
+ ```js title="dao3.config.json"
+ {
+ "client": {
+ "base": "./client",
+ // 修改这里
+ "entry": "src/clientApp.tsx",
+ //...省略...
+ }
+ }
+ ```
+### 3. 修改client/tsconfig.json
+需要在`compilerOptions`中加入一些`jsx/tsx+areact`相关的配置
+```js title="client/tsconfig.json"
+ {
+ "compilerOptions": {
+ // ...省略...
+ // 这四行是要添加的内容
+ "noImplicitAny": false,
+ "jsx": "react",
+ "jsxFactory": "Areact.h",
+ "jsxFragmentFactory": "Areact.frag"
+ // ...省略...
+ }
+ }
+```
+:::info
+请记住,如果你下次还要创建一个这样的项目的话依旧要完成以上步骤
+:::
+## 安装 Areact
+对于ArenaPro和ArenaLess有不同的安装步骤。
+
+
+```sh title="在项目根目录打开VSCode的终端,输入以下命令:"
+npm install --save dao3-areact
+```
+
+
+```js title='在importMap.arenaless.jsonc的"imports"中添加:'
+{
+ "imports":{
+ // 在这里加入一条导入
+ "dao3-areact":"npm:dao3-areact"
+ }
+}
+```
+
+
+
+## 你的第一段代码
+好了,所有的配置工作完工了,现在开始写你的第一段代码吧!
+
+ 点击查看完整代码
+```tsx title="client/src/clientApp.tsx"
+import { Areact, hooks } from "dao3-areact";
+import { Text } from "dao3-areact/components";
+let app = new Areact();
+function App() {
+ const [count,setCount]=hooks.useState(0);
+ return (<>
+ {setCount(count+1)}}
+ >
+ >);
+}
+app.mount(, ui);
+```
+
+
+> 接下来是分解教程
+### 1. 导入
+```tsx
+import { Areact, hooks } from "dao3-areact";
+import { Text } from "dao3-areact/components";
+```
+- `Areact`是框架
+- `hooks`是`react(preact)`的`hooks`,详见[Built-in React Hooks(React文档)](https://react.dev/reference/react/hooks)
+- `Text`是一个文本组件,就类似原岛三ui中的UiText,以下是所有的组件:
+ - `Text` 显示文本的组件
+ - `Image` 显示图片的组件
+ - `Input` 显示输入框的组件
+ - `Box` 一个框架组件,没有什么特征
+### 2. 创建 入口点组件
+```tsx
+let app = new Areact();
+function App() {
+ // 待会添加的内容
+ return (<>
+ {/* ... 这里是待会要填充的组件 ...*/}
+ >);
+}
+// 将入口点组件挂载到Areact上运行渲染
+app.mount(,ui)
+```
+最基础的部分已经ok了,但是你现在运行见不到任何效果,那是因为你还没有添加其他组件。
+### 3. 文本组件
+接下来,我们修改`function App(){}`的内容,添加一个文本组件:
+```tsx
+function App() {
+ // 待会添加的内容
+ return (<>
+
+ >);
+}
+```
+
+ 讲解一下以上的各个属性(属性值大多用字符串)
+:::info
+1. `x`,`y`,`width`,`height`这些属性的格式是这样的:`<偏移数值>px+<百分比比例>%`,其中可以把`+`换成`-`,甚至多加几个`+和-`都是允许的。
+
+ 最后会被转换为`offset`和`scale`值。例子`10px`,`10px+20%`,`10px+20%-20px+10%`
+2. `text` 这是适用于`Text`和`Input`的组件的属性,代表文本内容。相当于岛三ui的`textContent`。
+
+ 因为react占用了`textContent`这个属性,所以我们用了`text`代替。
+3. `backgroundColor`,`textColor` 前者是背景颜色,后者是文本颜色。接收css的颜色值,会自动转换为rgb的vec3。
+4. `backgroundOpacity` 背景不透明度,接受百分数
+:::
+
+好,现在左上角出现了一个黑色底,白色字的文本框。
+### 4. 添加事件和state
+一个文本框太过单调了……如果我们想点击它改变显示的文字呢?例如点击显示的数字+1。
+- 使用`hooks.useState()`来创建一个状态变量,当这个变量使用`setXXX`更新时,会重新渲染使用了该变量的组件,
+ 这样我们在点击的时候把`count`变量+1,文本框的文本会随之变化。
+- 使用`onClick`属性来注册点击事件,并且更新状态变量`count`
+
+这是`useState`的一般用法:
+```tsx
+let [name,setName]=hooks.useState("tobylai");// tobylai就是你指定的默认值
+// 前者是用于读取的变量,后者是更新变量时所用的函数
+// 这个命名取决于你,规范的写法是[aaa,setAaa]
+console.log(name); // "tobylai"
+setName("Areact"); // 这里更新了状态变量
+console.log(name); // "Areact"
+```
+让我们修改先前的代码,得到最终成品:
+```tsx
+import { Areact, hooks } from "dao3-areact";
+import { Text } from "dao3-areact/components";
+let app = new Areact();
+function App() {
+ // 这个状态变量count初始值为0,调用setCount可以改变它
+ const [count,setCount]=hooks.useState(0);
+ return (<>
+ {setCount(count+1)}}// onClick事件,把count设置为count+1
+ >
+ >);
+}
+app.mount(, ui);
+```
+现在你就得到了一个点击就能+1的文本框了,像不像个电子木鱼?
+
+## 更远……文本框+输入框
+以下代码可以实现在输入框输入文字的过程中更新文本框的内容
+```tsx
+import { Areact, hooks } from "dao3-areact";
+import { Text,Input,Box,Image } from "dao3-areact/components";
+let app = new Areact();
+
+function App() {
+ const [name,setName]=hooks.useState("");
+ return (<>
+
+ setName(e.target.getAttribute("text"))} // 使用onInput事件监听输入
+ text={name} // 绑定是双向的~
+ >
+ >);
+}
+app.mount(, ui);
+```
\ No newline at end of file
diff --git a/docs/areact/index.md b/docs/areact/index.md
new file mode 100644
index 0000000..0ca39fc
--- /dev/null
+++ b/docs/areact/index.md
@@ -0,0 +1,56 @@
+---
+title: Areact
+---
+
+# Areact
+:::warning 使用前三思
+目前神岛client端编辑器的优化很烂,过大的体积会导致地图无法打开。而目前此库体积`256kb`左右,有几率导致崩溃……
+- 呼叫大板砖支援
+- 呼叫大板砖支援
+- 呼叫大板砖支援
+:::
+Areact是一个基于Preact的UI框架,能够在[神奇代码岛](https://dao3.fun)上利用类似React的方式创建UI界面。
+
+## 快速开始
+:::info[快速上手]
+需要新手入门教程?请点击[这里](./getting-started)
+:::
+
+
+## 速览(简单示例)
+![1726978076891](index/1726978076891.png)
+```tsx title="clientApp.tsx"
+import { Areact, hooks } from "dao3-areact";
+import { Text } from "dao3-areact/components";
+let app = new Areact();
+// 这是UI的根组件
+function App() {
+ const [count,setCount]=hooks.useState(0);
+ return (<>
+ {/* 文字组件,点击+1 */}
+ {setCount(count+1)}}
+ >
+ >);
+}
+// 挂载根组件 开始渲染
+app.mount(, ui);
+```
+
+## 优势
+- 与[ArenaPro](https://www.yuque.com/box3lab/arenapro)或者[ArenaLess](/docs/arenaless/)结合使用,TypeScript助力开发
+- React 的写法,有React的优点,例如状态更新等
+- 支持`React`的`Hooks`,例如`useState`、`useEffect`等
+- 事件写法更为清晰,可以在节点上`onClick`,`onInput`等
+- 组件化的编程方式,十分简单地创建起属于你的组件库,避免了复制粘贴。
+- 近似于`html`的风格,有特色的组件参数绑定
+
+## 缺点
+- 性能开销略高
+- 可能会出现bug
+- 打包体积较大,输出`256kb`左右,可能会导致地图崩溃
+- 有一些神岛自带的组件无法使用,原因是搬砖没有写JavaScriptAPI,只做了编辑器……
\ No newline at end of file
diff --git a/docs/areact/index/1726978076891.png b/docs/areact/index/1726978076891.png
new file mode 100644
index 0000000..3b67e2b
Binary files /dev/null and b/docs/areact/index/1726978076891.png differ
diff --git a/docs/dao3-aui/getting-started.mdx b/docs/dao3-aui/getting-started.mdx
index 0075153..be63549 100644
--- a/docs/dao3-aui/getting-started.mdx
+++ b/docs/dao3-aui/getting-started.mdx
@@ -6,6 +6,10 @@ sidebar_position: 2
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
+:::danger 迁移!
+dao3-aui不再维护,请迁移到Areact
+:::
+
# 快速上手
:::warning
本文默认你已经掌握 **ArenaPro(或者ArenaLess)** 插件的基本用法,如未了解,请先阅读[ArenaPro](https://www.yuque.com/box3lab/arenapro)插件文档。
diff --git a/docs/dao3-aui/index.md b/docs/dao3-aui/index.md
index bf34bda..3082d26 100644
--- a/docs/dao3-aui/index.md
+++ b/docs/dao3-aui/index.md
@@ -1,6 +1,11 @@
---
-title: Dao3-AUI (React on 神岛)
+title: ⚠迁移 Dao3-AUI
---
+
+:::danger 迁移!
+dao3-aui不再维护,请迁移到Areact
+:::
+
# Dao3-AUI
Dao3-AUI是**开源**的,如果你有需求或者bug汇报,请到[本项目repo](https://github.com/Box3TRC/dao3-aui)开issue。
## 什么是Dao3-AUI ⚛️+📦
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 3746d35..14e17ac 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -5,6 +5,7 @@
// See: https://docusaurus.io/docs/api/docusaurus-config
import { themes as prismThemes } from 'prism-react-renderer';
+import tabBlocks from "docusaurus-remark-plugin-tab-blocks";
/** @type {import('@docusaurus/types').Config} */
const config = {
@@ -40,6 +41,7 @@ const config = {
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
+ remarkPlugins: [[tabBlocks,{}]],
sidebarPath: './sidebars.js',
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
@@ -47,6 +49,7 @@ const config = {
'https://github.com/Box3TRC/documentation/blob/main',
},
blog: {
+ remarkPlugins: [tabBlocks],
showReadingTime: true,
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
@@ -141,6 +144,38 @@ const config = {
explicitSearchResultPath: true,
}),
],
+ ],plugins:[
+ // [
+ // 'vercel-analytics',
+ // {
+ // debug: true,
+ // mode: 'auto',
+ // },
+ // ],
+ // [
+ // 'docusaurus-plugin-typedoc',
+ // {
+ // id: 'typedoc-areact',
+ // entryPoints: ['dts/areact/index.d.ts'],
+ // skipErrorChecking: true,
+ // name: "模块: areact",
+ // out: "/docs/areact/api/index",
+ // sidebar: {
+ // "autoConfiguration": false,
+ // "pretty": false
+ // }
+ // },
+ // ],
+ // [
+ // 'docusaurus-plugin-typedoc',
+ // {
+ // id: 'typedoc-areact-components',
+ // entryPoints: ['dts/areact/components.d.ts'],
+ // skipErrorChecking: true,
+ // name: "模块: areact/components",
+ // out: "/docs/areact/api/components"
+ // },
+ // ],
]
};
diff --git a/dts/areact/components.d.ts b/dts/areact/components.d.ts
new file mode 100644
index 0000000..b761ae1
--- /dev/null
+++ b/dts/areact/components.d.ts
@@ -0,0 +1,57 @@
+import type { FunctionalComponent } from "preact";
+export interface AreactHTMLElement extends HTMLElement {
+ uiNode: UiRenderable;
+}
+export interface AreactEvent extends Event {
+ target: AreactHTMLElement;
+}
+interface UiRenderableOpt {
+ id?: string;
+ x?: string;
+ y?: string;
+ width?: string;
+ height?: string;
+ anchor?: string;
+ backgroundColor?: string;
+ backgroundOpacity?: number | string;
+ zIndex?: number | string;
+ autoResize?: 'NONE' | 'X' | 'Y' | 'XY';
+ visible?: boolean | string;
+ pointerEventBehavior?: string;
+ onClick?: (e: AreactEvent) => void;
+}
+interface UiTextOpt extends UiRenderableOpt {
+ text?: string;
+ textFontSize?: number | string;
+ textColor?: string;
+ textXAlignment?: 'Center' | 'Left' | 'Right';
+ textYAlignment?: 'Center' | 'Top' | 'Bottom';
+ autoWordWrap?: boolean | string;
+ textLineHeight?: number | string;
+}
+export declare function Text(opt: UiTextOpt & {
+ children?: any;
+}): FunctionalComponent;
+interface UiBoxOpt extends UiRenderableOpt {
+}
+export declare function Box(opt: UiBoxOpt & {
+ children?: any;
+}): FunctionalComponent;
+interface UiImageOpt extends UiRenderableOpt {
+ image?: string;
+ imageOpacity?: number | string;
+}
+export declare function Image(opt: UiImageOpt & {
+ children?: any;
+}): FunctionalComponent;
+interface UiInputOpt extends UiTextOpt {
+ placeholder?: string;
+ placeholderColor?: string;
+ placeholderOpacity?: number | string;
+ focus?: string | boolean;
+ onInput?: (e: AreactEvent) => void;
+}
+export declare function Input(opt: UiInputOpt & {
+ children?: any;
+}): FunctionalComponent;
+export {};
diff --git a/dts/areact/index.d.ts b/dts/areact/index.d.ts
new file mode 100644
index 0000000..4c0c193
--- /dev/null
+++ b/dts/areact/index.d.ts
@@ -0,0 +1,33 @@
+import { h } from "preact";
+export declare const html: (strings: TemplateStringsArray, ...values: any[]) => import("preact").VNode | import("preact").VNode[];
+export declare const document: any, HTMLElement: any, Event: any;
+export declare class AreactApp {
+ root: HTMLElement;
+ uiNode: UiNode;
+ __interval: any;
+ static h: typeof h;
+ static frag: import("preact").FunctionComponent<{}>;
+ static supportedNodes: string[];
+ uiGenedProps: Record;
+ inputNodes: any[];
+ renderedNodes: any[];
+ constructor();
+ static initUiComponents(): Record;
+ mount(ele: any, uiNode: UiNode): void;
+ render(): void;
+ _bindProps(node: Element | HTMLElement, uiNode: UiRenderable | UiNode, string_props_name: any, special_converters: any): void;
+ static _uiPropsGen(propTypes: Record): {
+ string_props_name: any;
+ special_converters: any;
+ };
+ static getConvertorForType(type: string): (val: string) => any | undefined;
+ static _camelCaseToDash(str: string): string;
+ static _dashToCamelCase(str: string): string;
+ createNodeInUi(node: Element | HTMLElement): UiText | UiBox | UiInput | UiImage | UiRenderable;
+ renderNodes(node: Element, uiNode: UiRenderable | UiNode): void;
+}
+export declare const Areact: typeof AreactApp;
+export * as hooks from "preact/hooks";
diff --git a/package.json b/package.json
index c629bdc..b1b7a6b 100644
--- a/package.json
+++ b/package.json
@@ -15,18 +15,25 @@
},
"dependencies": {
"@docusaurus/core": "^3.5.2",
+ "@docusaurus/plugin-vercel-analytics": "^3.5.2",
"@docusaurus/preset-classic": "^3.5.2",
"@easyops-cn/docusaurus-search-local": "^0.44.5",
"@mdx-js/react": "^3.0.0",
"@node-rs/jieba": "^1.10.3",
"clsx": "^2.0.0",
+ "docusaurus-remark-plugin-tab-blocks": "^3.1.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.5.2",
- "@docusaurus/types": "^3.5.2"
+ "@docusaurus/types": "^3.5.2",
+ "docusaurus-plugin-react-docgen-typescript": "^1.2.1",
+ "docusaurus-plugin-typedoc": "^1.0.5",
+ "react-docgen-typescript": "^2.2.2",
+ "typedoc": "^0.26.7",
+ "typedoc-plugin-markdown": "^4.2.7"
},
"browserslist": {
"production": [
diff --git a/sidebars.js b/sidebars.js
index 3327580..93b3585 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -14,8 +14,9 @@
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
- tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
-
+ tutorialSidebar: [
+ {type: 'autogenerated', dirName: '.'},
+ ],
// But you can create a sidebar manually
/*
tutorialSidebar: [
diff --git a/src/css/custom.css b/src/css/custom.css
index 2bc6a4c..79477ac 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -5,7 +5,7 @@
*/
/* You can override the default Infima variables here. */
-:root {
+/* :root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
@@ -15,10 +15,23 @@
--ifm-color-primary-lightest: #3cad6e;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
+} */
+:root {
+ --ifm-color-primary: #673ab7;
+ --ifm-color-primary-dark: #5d34a5;
+ --ifm-color-primary-darker: #58319c;
+ --ifm-color-primary-darkest: #482980;
+ --ifm-color-primary-light: #7345c4;
+ --ifm-color-primary-lighter: #7a4ec7;
+ --ifm-color-primary-lightest: #341d5b;
+}
+:root{
+ --ifm-code-font-size: 95%;
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
-[data-theme='dark'] {
+/* [data-theme='dark'] {
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: #21af90;
--ifm-color-primary-darker: #1fa588;
@@ -27,4 +40,16 @@
--ifm-color-primary-lighter: #32d8b4;
--ifm-color-primary-lightest: #4fddbf;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
+} */
+[data-theme='dark'] {
+ --ifm-color-primary: #9575cd;
+ --ifm-color-primary-dark: #9373cc;
+ --ifm-color-primary-darker: #7a52c0;
+ --ifm-color-primary-darkest: #623ca5;
+ --ifm-color-primary-light: #a78dd6;
+ --ifm-color-primary-lighter: #b098da;
+ --ifm-color-primary-lightest: #cbbce7;
}
+[data-theme='dark'] {
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
+}
\ No newline at end of file