diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..76d0271
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.{js,ts,jsx,tsx}]
+indent_size = 4
+
+[*.{less,html,ejs}]
+indent_size = 2
+
+[*.json]
+indent_size = 2
+
+[tsconfig.json]
+indent_size = 4
diff --git a/.eslintignore b/.eslintignore
index e401845..c94e368 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,5 @@
types
-node_modules/
-dist/
-assets/
\ No newline at end of file
+node_modules
+dist
+assets
+docs
diff --git a/.eslintrc b/.eslintrc
index 63e374d..3a3ff31 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,8 +1,47 @@
+
{
- "extends": "plugin:@fui/typescript",
+ "env": {
+ "browser": true,
+ "node": true,
+ "es6": true,
+ "jest/globals": true
+ },
+ "plugins": ["jest", "react"],
+ "extends": ["plugin:@fui/typescript", "plugin:@fui/prettier"],
"parserOptions": {
"ecmaFeatures": {
- "legacyDecorators": true
+ "legacyDecorators": true,
+ "jsx": true
}
- }
-}
\ No newline at end of file
+ },
+ "rules": {
+ // 由于prettier和eslint一起使用需要关闭一些规则,但是prettier没有以下规则的配置,统一写在这里
+ // 对象字面量简写语法
+ "object-shorthand": ["error", "always"],
+ // 函数体在必要的时候使用大括号
+ "arrow-body-style": [
+ "error",
+ "as-needed",
+ {
+ "requireReturnForObjectLiteral": true
+ }
+ ],
+ // 回调使用用箭头函数
+ "prefer-arrow-callback": "error",
+ // 如果 if 块中包含了一个 return 语句,else 块就成了多余的了。可以将其内容移至块外
+ "no-else-return": "error",
+ "no-use-before-define": "off",
+
+ "react/jsx-uses-react": "error",
+ "react/jsx-uses-vars": "error"
+ },
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {
+ "no-undef": "off",
+ "no-unused-vars": "off"
+ }
+ }
+ ]
+}
diff --git a/.gitignore b/.gitignore
index 9719d54..ea883ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,6 +47,7 @@ crashlytics.properties
crashlytics-build.properties
/node_modules/
+
+/dist
package-lock.json
-yarn.lock
-/dist
\ No newline at end of file
+yarn.lock
\ No newline at end of file
diff --git a/.npmrc b/.npmrc
index 21e56c3..ee99b80 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1 +1,2 @@
+registry=https://registry.npm.taobao.org
@fui:registry=https://npm.fineres.com/
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..c94e368
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,5 @@
+types
+node_modules
+dist
+assets
+docs
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..7bb8fe5
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "singleQuote": true,
+ "arrowParens": "avoid",
+ "printWidth": 160
+}
diff --git a/.stylelintignore b/.stylelintignore
new file mode 100644
index 0000000..c94e368
--- /dev/null
+++ b/.stylelintignore
@@ -0,0 +1,5 @@
+types
+node_modules
+dist
+assets
+docs
diff --git a/.stylelintrc b/.stylelintrc
new file mode 100644
index 0000000..c671fba
--- /dev/null
+++ b/.stylelintrc
@@ -0,0 +1,7 @@
+{
+ "extends": ["stylelint-config-standard", "stylelint-prettier/recommended"],
+ "rules": {
+ "no-descending-specificity": null,
+ "selector-pseudo-element-colon-notation": "single"
+ }
+}
diff --git a/README.md b/README.md
index dde098a..427ed9f 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,63 @@
-# FineUI-Start
+# README
-## 安装运行
-`git clone --recursive https://git.fanruan.com/dailer/FineUI-Start.git`
+## 准备工作
-## 安装依赖
-`yarn install`
+### 克隆仓库
-## 打开dev模式
-`yarn start`
+```shell
+git clone https://code.fineres.com/scm/fui/fineui-starter.git
+```
-## 打包
-`yarn build`
+### 安装依赖
-## 示例效果
-![](./screenshorts/todolist.gif)
\ No newline at end of file
+```shell
+# 账户:public
+# 密码:fr123456
+# 邮箱:任意
+npm adduser --registry https://npm.fineres.com
+npm install
+```
+
+### 安装扩展
+
+以 VSCode 为例,为保证代码规范和格式统一,请安装`ESLint`、`stylelint`、`Prettier`、`EditorConfig`扩展,以使相关配置文件生效。
+
+## 开发工作
+
+### 项目基础配置
+
+布局配置请见`src/modules/app/layout/layout.constant.ts`。
+
+样式配置请见`src/less/`,譬如`src/less/lib/constant`中的`@color-app-primary`表示项目的主色。
+
+### 项目调试、打包与测试
+
+```shell
+# 调试
+npm run start
+
+# 打包
+npm run build
+
+# 测试
+npm run test
+```
+
+### 项目规范和格式检查
+
+```shell
+# 代码规范
+npm run eslint
+npm run eslint:fix
+
+# 样式规范
+npm run stylelint
+npm run stylelint:fix
+
+# 代码格式
+npm run prettier
+```
+
+## 效果预览
+
+![页面截图](./screenshots/demo.jpeg)
diff --git a/advance.html b/advance.html
deleted file mode 100644
index 2e85732..0000000
--- a/advance.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/images/1x/logo.png b/assets/images/1x/logo.png
new file mode 100644
index 0000000..11baaa1
Binary files /dev/null and b/assets/images/1x/logo.png differ
diff --git a/assets/images/2x/logo.png b/assets/images/2x/logo.png
new file mode 100644
index 0000000..17f645e
Binary files /dev/null and b/assets/images/2x/logo.png differ
diff --git a/babel.config.js b/babel.config.js
index 6cf5fff..12cd09e 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1 +1 @@
-module.exports = require('@fui/babel-preset-fineui').configs.ie8;
+module.exports = require('@fui/babel-preset-fineui').configs.base;
diff --git a/dist/bundle.css b/dist/bundle.css
deleted file mode 100644
index 456246a..0000000
--- a/dist/bundle.css
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
- */
-.my-todolist-header {
- background-color: #3d4d66;
-}
-.my-todolist-header .my-todolist-title {
- font-size: 22px;
- color: #FFF;
-}
-.my-todolist-header .my-todolist-header-editor {
- background-color: #FFF;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius方法等.请选择性使用.不强制要求
- */
-.my-todolist-list .my-todolist-list-text {
- font-size: 16px;
- font-weight: bold;
-}
-.my-todolist-list .my-todolist-list-count-container {
- -webkit-border-radius: 10px;
- -moz-border-radius: 10px;
- border-radius: 10px;
- background-color: #3d4d66;
- color: #ffffff;
-}
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
- */
-.my-todolist-background {
- background-color: #f7f8fa;
-}
diff --git a/dist/bundle.js b/dist/bundle.js
deleted file mode 100644
index c7db7c3..0000000
--- a/dist/bundle.js
+++ /dev/null
@@ -1,286 +0,0 @@
-!(function() {
- /**
- * 顶部组件,提供输入框添加todo项目
- * 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中
- */
- var ToDoListHeader = BI.inherit(BI.Widget, {
-
- props: {
- // 指定组件的className
- baseCls: "my-todolist-header"
- },
-
- render: function() {
- var self = this, o = this.options;
- return {
- type: "bi.horizontal_auto", // 水平居中布局
- items: [
- {
- el: {
- type: "bi.left_right_vertical_adapt", // 左右垂直居中布局
- width: 600,
- height: o.height,
- items: {
- left: [
- {
- el: {
- type: "bi.label",
- cls: "my-todolist-title",
- text: "FineUI ToDoList",
- height: o.height
- }
- }
- ],
- right: [
- {
- el: {
- type: "bi.editor",
- ref: function(_ref) {
- self.editor = _ref;
- },
- allowBlank: true,
- cls: "my-todolist-header-editor",
- watermark: "添加ToDo",
- width: 300,
- height: 24,
- listeners: [
- { // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置空
- eventName: "EVENT_ENTER",
- action: function() {
- // 注意:在这里this指向的是bi.editor的实例.通过bi.editor的getValue()方法获取输入框输入值.
- self.fireEvent(ToDoListHeader.EVENT_ADD, this.getValue());
- self.editor.setValue("");
- }
- }
- ]
- }
- }
- ]
- }
- }
- }
- ]
- };
- }
- });
-
- ToDoListHeader.EVENT_ADD = "EVENT_ADD";
-
- BI.shortcut("my.todolist.header", ToDoListHeader);
-})();!(function() {
- /**
- * todo项列表
- *
- */
- var List = BI.inherit(BI.Widget, {
-
- props: {
- // 指定组件的className
- baseCls: "my-todolist-list",
- text: "正在进行"
- },
-
- render: function() {
- var self = this, o = this.options;
- return {
- type: "bi.vertical",
- items: [
- {
- el: {
- type: "bi.vertical_adapt",
- height: 40,
- items: [
- {
- type: "bi.label",
- cls: "my-todolist-list-text",
- textAlign: "left",
- text: o.text,
- width: 580
- }, {
- type: "bi.center_adapt",
- cls: "my-todolist-list-count-container",
- width: 20,
- height: 20,
- items: [
- {
- el: {
- type: "bi.label",
- ref: function(_ref) {
- self.count = _ref;
- },
- text: "0"
- }
- }
- ]
- }
- ]
- }
- }, { // 用bi.vertical布局作为列表项的容器.
- type: "bi.vertical",
- vgap: 10,
- ref: function(_ref) {
- self.list = _ref;
- },
- items: this._createItems(o.items)
- }
- ]
- };
- },
-
- _createItems: function(items) {
- var self = this;
- return BI.map(items, function(index, item) {
- return BI.extend(item, {
- type: "bi.multi_select_item", // 节点采用复选节点展示
- selected: item.done, // 已完成的todo项置为选中状态
- disabled: item.done, // 已完成的todo项置为灰化状态
- listeners: [
- { // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事件
- eventName: "EVENT_CHANGE",
- action: function(v) {
- self.fireEvent("EVENT_CHANGE", v);
- }
- }
- ]
- });
- });
- },
-
- _setCount: function(count) {
- this.count.setText(count);
- },
-
- populate: function(items) {
- this.list.populate(this._createItems(items));
- this._setCount(items.length);
- }
- });
- BI.shortcut("my.todolist.list", List);
-})();!(function() {
- /**
- * todolist 组件
- */
- var ToDoList = BI.inherit(BI.Widget, {
-
- props: {
- baseCls: "fine-to-do-list"
- },
-
- // 生命周期函数,在组件创建前
- beforeCreate: function() {
- // 初始化存储数据
- this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : [];
- },
-
- render: function() {
- var self = this, o = this.options;
- return {
- type: "bi.vtape", // vtape布局,顶部高度固定,下部分列表占满高度
- items: [
- {
- el: {
- type: "my.todolist.header", // 顶部组件
- listeners: [
- { // 监听组件的EVENT_ADD事件,新建todo项
- eventName: "EVENT_ADD",
- action: function(v) {
- self.addToDo(v);
- }
- }
- ],
- height: 40
- },
- height: 40
- }, {
- type: "bi.horizontal_auto", // 水平居中布局
- cls: "my-todolist-background", // 添加className
- items: [
- {
- el: {
- type: "my.todolist.list", // need todo项列表
- ref: function(_ref) {
- self.todolist = _ref;
- },
- items: this._getNeedTodoList(),
- text: "正在进行",
- listeners: [
- { // 监听EVENT_CHANGE事件,完成某一项todo
- eventName: "EVENT_CHANGE",
- action: function(v) {
- self.finishTodo(v);
- }
- }
- ],
- width: 600
- }
- }, {
- el: {
- type: "my.todolist.list", // 已经完成的todo项列表
- text: "已经完成",
- items: this._getAlreadyDoneList(),
- ref: function(_ref) {
- self.donelist = _ref;
- },
- width: 600
- }
- }
- ]
- }
- ]
- };
- },
-
- _updateLocalStorage: function() {
- localStorage.setItem("fine-todolist", JSON.stringify(this.list));
- },
-
- _getNeedTodoList: function() {
- return BI.filter(this.list, function(index, item) {
- return !item.done;
- });
- },
-
- _getAlreadyDoneList: function() {
- return BI.filter(this.list, function(index, item) {
- return item.done;
- });
- },
-
- /**
- * 添加todo项
- * @param text todo项的内容
- */
- addToDo: function(text) {
- this.list.push({
- value: BI.UUID(),
- text: text,
- done: false
- });
- this.todolist.populate(this._getNeedTodoList());
- this._updateLocalStorage();
- },
-
- /**
- * 完成某一项todo
- * @param v todo项的value
- */
- finishTodo: function(v) {
- BI.some(this.list, function(index, item) {
- if (item.value === v) {
- item.done = true;
- }
- });
- this.todolist.populate(this._getNeedTodoList());
- this.donelist.populate(this._getAlreadyDoneList());
- this._updateLocalStorage();
- }
- });
- BI.shortcut("my.todolist", ToDoList);
-})();
-!(function () {
- // 将todolist组件挂载到#wrapper上.
- BI.createWidget({
- type: "my.todolist",
- element: "#wrapper"
- });
-})();
diff --git a/dist/font/iconfont.eot b/dist/font/iconfont.eot
deleted file mode 100644
index 693b5dc..0000000
Binary files a/dist/font/iconfont.eot and /dev/null differ
diff --git a/dist/font/iconfont.svg b/dist/font/iconfont.svg
deleted file mode 100644
index 973571d..0000000
--- a/dist/font/iconfont.svg
+++ /dev/null
@@ -1,1002 +0,0 @@
-
-
-
-
diff --git a/dist/font/iconfont.ttf b/dist/font/iconfont.ttf
deleted file mode 100644
index e62143d..0000000
Binary files a/dist/font/iconfont.ttf and /dev/null differ
diff --git a/dist/font/iconfont.woff b/dist/font/iconfont.woff
deleted file mode 100644
index 9c9686c..0000000
Binary files a/dist/font/iconfont.woff and /dev/null differ
diff --git a/dist/images/1x/background/auto_color.png b/dist/images/1x/background/auto_color.png
deleted file mode 100644
index 63b3edf..0000000
Binary files a/dist/images/1x/background/auto_color.png and /dev/null differ
diff --git a/dist/images/1x/background/line_conn.gif b/dist/images/1x/background/line_conn.gif
deleted file mode 100644
index d561d36..0000000
Binary files a/dist/images/1x/background/line_conn.gif and /dev/null differ
diff --git a/dist/images/1x/background/marker.png b/dist/images/1x/background/marker.png
deleted file mode 100644
index 3929bbb..0000000
Binary files a/dist/images/1x/background/marker.png and /dev/null differ
diff --git a/dist/images/1x/background/mask.png b/dist/images/1x/background/mask.png
deleted file mode 100644
index b0a4d40..0000000
Binary files a/dist/images/1x/background/mask.png and /dev/null differ
diff --git a/dist/images/1x/background/trans_color.png b/dist/images/1x/background/trans_color.png
deleted file mode 100644
index 8fa4492..0000000
Binary files a/dist/images/1x/background/trans_color.png and /dev/null differ
diff --git a/dist/images/1x/background/wheel.png b/dist/images/1x/background/wheel.png
deleted file mode 100644
index 97b343d..0000000
Binary files a/dist/images/1x/background/wheel.png and /dev/null differ
diff --git a/dist/images/1x/icon/check_box_active.png b/dist/images/1x/icon/check_box_active.png
deleted file mode 100644
index af54808..0000000
Binary files a/dist/images/1x/icon/check_box_active.png and /dev/null differ
diff --git a/dist/images/1x/icon/check_box_disable.png b/dist/images/1x/icon/check_box_disable.png
deleted file mode 100644
index bb7f451..0000000
Binary files a/dist/images/1x/icon/check_box_disable.png and /dev/null differ
diff --git a/dist/images/1x/icon/check_box_disable2.png b/dist/images/1x/icon/check_box_disable2.png
deleted file mode 100644
index fb593ff..0000000
Binary files a/dist/images/1x/icon/check_box_disable2.png and /dev/null differ
diff --git a/dist/images/1x/icon/check_box_normal.png b/dist/images/1x/icon/check_box_normal.png
deleted file mode 100644
index 2974ad7..0000000
Binary files a/dist/images/1x/icon/check_box_normal.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_collapse_1.png b/dist/images/1x/icon/dark/tree_collapse_1.png
deleted file mode 100644
index 583c00f..0000000
Binary files a/dist/images/1x/icon/dark/tree_collapse_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_collapse_2.png b/dist/images/1x/icon/dark/tree_collapse_2.png
deleted file mode 100644
index 083529b..0000000
Binary files a/dist/images/1x/icon/dark/tree_collapse_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_collapse_3.png b/dist/images/1x/icon/dark/tree_collapse_3.png
deleted file mode 100644
index cc3d25c..0000000
Binary files a/dist/images/1x/icon/dark/tree_collapse_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_collapse_4.png b/dist/images/1x/icon/dark/tree_collapse_4.png
deleted file mode 100644
index d599e57..0000000
Binary files a/dist/images/1x/icon/dark/tree_collapse_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_expand_1.png b/dist/images/1x/icon/dark/tree_expand_1.png
deleted file mode 100644
index 76c5863..0000000
Binary files a/dist/images/1x/icon/dark/tree_expand_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_expand_2.png b/dist/images/1x/icon/dark/tree_expand_2.png
deleted file mode 100644
index 53063e7..0000000
Binary files a/dist/images/1x/icon/dark/tree_expand_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_expand_3.png b/dist/images/1x/icon/dark/tree_expand_3.png
deleted file mode 100644
index 0f35d6e..0000000
Binary files a/dist/images/1x/icon/dark/tree_expand_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_expand_4.png b/dist/images/1x/icon/dark/tree_expand_4.png
deleted file mode 100644
index 4752f81..0000000
Binary files a/dist/images/1x/icon/dark/tree_expand_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_vertical_line_1.png b/dist/images/1x/icon/dark/tree_vertical_line_1.png
deleted file mode 100644
index d13fc8d..0000000
Binary files a/dist/images/1x/icon/dark/tree_vertical_line_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_vertical_line_2.png b/dist/images/1x/icon/dark/tree_vertical_line_2.png
deleted file mode 100644
index ebee980..0000000
Binary files a/dist/images/1x/icon/dark/tree_vertical_line_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_vertical_line_3.png b/dist/images/1x/icon/dark/tree_vertical_line_3.png
deleted file mode 100644
index d2f7595..0000000
Binary files a/dist/images/1x/icon/dark/tree_vertical_line_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_vertical_line_4.png b/dist/images/1x/icon/dark/tree_vertical_line_4.png
deleted file mode 100644
index 277d0e5..0000000
Binary files a/dist/images/1x/icon/dark/tree_vertical_line_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/dark/tree_vertical_line_5.png b/dist/images/1x/icon/dark/tree_vertical_line_5.png
deleted file mode 100644
index 85aa1cc..0000000
Binary files a/dist/images/1x/icon/dark/tree_vertical_line_5.png and /dev/null differ
diff --git a/dist/images/1x/icon/dots.png b/dist/images/1x/icon/dots.png
deleted file mode 100644
index 55b461b..0000000
Binary files a/dist/images/1x/icon/dots.png and /dev/null differ
diff --git a/dist/images/1x/icon/half_selected.png b/dist/images/1x/icon/half_selected.png
deleted file mode 100644
index 298dd91..0000000
Binary files a/dist/images/1x/icon/half_selected.png and /dev/null differ
diff --git a/dist/images/1x/icon/icon_down_arrow.png b/dist/images/1x/icon/icon_down_arrow.png
deleted file mode 100644
index b77c330..0000000
Binary files a/dist/images/1x/icon/icon_down_arrow.png and /dev/null differ
diff --git a/dist/images/1x/icon/loading.gif b/dist/images/1x/icon/loading.gif
deleted file mode 100644
index d04fdd2..0000000
Binary files a/dist/images/1x/icon/loading.gif and /dev/null differ
diff --git a/dist/images/1x/icon/push_down.png b/dist/images/1x/icon/push_down.png
deleted file mode 100644
index 7eb88eb..0000000
Binary files a/dist/images/1x/icon/push_down.png and /dev/null differ
diff --git a/dist/images/1x/icon/push_up.png b/dist/images/1x/icon/push_up.png
deleted file mode 100644
index a3042a4..0000000
Binary files a/dist/images/1x/icon/push_up.png and /dev/null differ
diff --git a/dist/images/1x/icon/radio_active.png b/dist/images/1x/icon/radio_active.png
deleted file mode 100644
index 7b2ee27..0000000
Binary files a/dist/images/1x/icon/radio_active.png and /dev/null differ
diff --git a/dist/images/1x/icon/radio_disable.png b/dist/images/1x/icon/radio_disable.png
deleted file mode 100644
index c0389fd..0000000
Binary files a/dist/images/1x/icon/radio_disable.png and /dev/null differ
diff --git a/dist/images/1x/icon/radio_disable2.png b/dist/images/1x/icon/radio_disable2.png
deleted file mode 100644
index f5a71f3..0000000
Binary files a/dist/images/1x/icon/radio_disable2.png and /dev/null differ
diff --git a/dist/images/1x/icon/radio_normal.png b/dist/images/1x/icon/radio_normal.png
deleted file mode 100644
index 2388bb8..0000000
Binary files a/dist/images/1x/icon/radio_normal.png and /dev/null differ
diff --git a/dist/images/1x/icon/slider_active.png b/dist/images/1x/icon/slider_active.png
deleted file mode 100644
index a84164f..0000000
Binary files a/dist/images/1x/icon/slider_active.png and /dev/null differ
diff --git a/dist/images/1x/icon/slider_active_small.png b/dist/images/1x/icon/slider_active_small.png
deleted file mode 100644
index 1c29cec..0000000
Binary files a/dist/images/1x/icon/slider_active_small.png and /dev/null differ
diff --git a/dist/images/1x/icon/slider_normal.png b/dist/images/1x/icon/slider_normal.png
deleted file mode 100644
index 8a611ff..0000000
Binary files a/dist/images/1x/icon/slider_normal.png and /dev/null differ
diff --git a/dist/images/1x/icon/slider_normal_small.png b/dist/images/1x/icon/slider_normal_small.png
deleted file mode 100644
index 7bd6fc7..0000000
Binary files a/dist/images/1x/icon/slider_normal_small.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_collapse_1.png b/dist/images/1x/icon/tree_collapse_1.png
deleted file mode 100644
index dfc427e..0000000
Binary files a/dist/images/1x/icon/tree_collapse_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_collapse_2.png b/dist/images/1x/icon/tree_collapse_2.png
deleted file mode 100644
index 8db0aa7..0000000
Binary files a/dist/images/1x/icon/tree_collapse_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_collapse_3.png b/dist/images/1x/icon/tree_collapse_3.png
deleted file mode 100644
index efbbed9..0000000
Binary files a/dist/images/1x/icon/tree_collapse_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_collapse_4.png b/dist/images/1x/icon/tree_collapse_4.png
deleted file mode 100644
index 743bf8b..0000000
Binary files a/dist/images/1x/icon/tree_collapse_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_expand_1.png b/dist/images/1x/icon/tree_expand_1.png
deleted file mode 100644
index 914e324..0000000
Binary files a/dist/images/1x/icon/tree_expand_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_expand_2.png b/dist/images/1x/icon/tree_expand_2.png
deleted file mode 100644
index 95a8af0..0000000
Binary files a/dist/images/1x/icon/tree_expand_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_expand_3.png b/dist/images/1x/icon/tree_expand_3.png
deleted file mode 100644
index b1c1e94..0000000
Binary files a/dist/images/1x/icon/tree_expand_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_expand_4.png b/dist/images/1x/icon/tree_expand_4.png
deleted file mode 100644
index 6702029..0000000
Binary files a/dist/images/1x/icon/tree_expand_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_vertical_line_1.png b/dist/images/1x/icon/tree_vertical_line_1.png
deleted file mode 100644
index d13fc8d..0000000
Binary files a/dist/images/1x/icon/tree_vertical_line_1.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_vertical_line_2.png b/dist/images/1x/icon/tree_vertical_line_2.png
deleted file mode 100644
index ebee980..0000000
Binary files a/dist/images/1x/icon/tree_vertical_line_2.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_vertical_line_3.png b/dist/images/1x/icon/tree_vertical_line_3.png
deleted file mode 100644
index d2f7595..0000000
Binary files a/dist/images/1x/icon/tree_vertical_line_3.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_vertical_line_4.png b/dist/images/1x/icon/tree_vertical_line_4.png
deleted file mode 100644
index 277d0e5..0000000
Binary files a/dist/images/1x/icon/tree_vertical_line_4.png and /dev/null differ
diff --git a/dist/images/1x/icon/tree_vertical_line_5.png b/dist/images/1x/icon/tree_vertical_line_5.png
deleted file mode 100644
index 85aa1cc..0000000
Binary files a/dist/images/1x/icon/tree_vertical_line_5.png and /dev/null differ
diff --git a/dist/images/2x/background/auto_color.png b/dist/images/2x/background/auto_color.png
deleted file mode 100644
index fc976e4..0000000
Binary files a/dist/images/2x/background/auto_color.png and /dev/null differ
diff --git a/dist/images/2x/background/line_conn.gif b/dist/images/2x/background/line_conn.gif
deleted file mode 100644
index d561d36..0000000
Binary files a/dist/images/2x/background/line_conn.gif and /dev/null differ
diff --git a/dist/images/2x/background/marker.png b/dist/images/2x/background/marker.png
deleted file mode 100644
index 3929bbb..0000000
Binary files a/dist/images/2x/background/marker.png and /dev/null differ
diff --git a/dist/images/2x/background/mask.png b/dist/images/2x/background/mask.png
deleted file mode 100644
index b0a4d40..0000000
Binary files a/dist/images/2x/background/mask.png and /dev/null differ
diff --git a/dist/images/2x/background/trans_color.png b/dist/images/2x/background/trans_color.png
deleted file mode 100644
index 262626f..0000000
Binary files a/dist/images/2x/background/trans_color.png and /dev/null differ
diff --git a/dist/images/2x/background/wheel.png b/dist/images/2x/background/wheel.png
deleted file mode 100644
index 97b343d..0000000
Binary files a/dist/images/2x/background/wheel.png and /dev/null differ
diff --git a/dist/images/2x/icon/check_box_active.png b/dist/images/2x/icon/check_box_active.png
deleted file mode 100644
index f5083b8..0000000
Binary files a/dist/images/2x/icon/check_box_active.png and /dev/null differ
diff --git a/dist/images/2x/icon/check_box_disable.png b/dist/images/2x/icon/check_box_disable.png
deleted file mode 100644
index b6767f3..0000000
Binary files a/dist/images/2x/icon/check_box_disable.png and /dev/null differ
diff --git a/dist/images/2x/icon/check_box_disable2.png b/dist/images/2x/icon/check_box_disable2.png
deleted file mode 100644
index dbc3da4..0000000
Binary files a/dist/images/2x/icon/check_box_disable2.png and /dev/null differ
diff --git a/dist/images/2x/icon/check_box_normal.png b/dist/images/2x/icon/check_box_normal.png
deleted file mode 100644
index cf167a7..0000000
Binary files a/dist/images/2x/icon/check_box_normal.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_collapse_1.png b/dist/images/2x/icon/dark/tree_collapse_1.png
deleted file mode 100644
index 740b50a..0000000
Binary files a/dist/images/2x/icon/dark/tree_collapse_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_collapse_2.png b/dist/images/2x/icon/dark/tree_collapse_2.png
deleted file mode 100644
index 6b7192f..0000000
Binary files a/dist/images/2x/icon/dark/tree_collapse_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_collapse_3.png b/dist/images/2x/icon/dark/tree_collapse_3.png
deleted file mode 100644
index 172b933..0000000
Binary files a/dist/images/2x/icon/dark/tree_collapse_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_collapse_4.png b/dist/images/2x/icon/dark/tree_collapse_4.png
deleted file mode 100644
index 69eb9c3..0000000
Binary files a/dist/images/2x/icon/dark/tree_collapse_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_expand_1.png b/dist/images/2x/icon/dark/tree_expand_1.png
deleted file mode 100644
index ce1480d..0000000
Binary files a/dist/images/2x/icon/dark/tree_expand_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_expand_2.png b/dist/images/2x/icon/dark/tree_expand_2.png
deleted file mode 100644
index 114dc2f..0000000
Binary files a/dist/images/2x/icon/dark/tree_expand_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_expand_3.png b/dist/images/2x/icon/dark/tree_expand_3.png
deleted file mode 100644
index fb15500..0000000
Binary files a/dist/images/2x/icon/dark/tree_expand_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_expand_4.png b/dist/images/2x/icon/dark/tree_expand_4.png
deleted file mode 100644
index 75c9f23..0000000
Binary files a/dist/images/2x/icon/dark/tree_expand_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_vertical_line_1.png b/dist/images/2x/icon/dark/tree_vertical_line_1.png
deleted file mode 100644
index e88f2a6..0000000
Binary files a/dist/images/2x/icon/dark/tree_vertical_line_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_vertical_line_2.png b/dist/images/2x/icon/dark/tree_vertical_line_2.png
deleted file mode 100644
index 554d8b3..0000000
Binary files a/dist/images/2x/icon/dark/tree_vertical_line_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_vertical_line_3.png b/dist/images/2x/icon/dark/tree_vertical_line_3.png
deleted file mode 100644
index 8e7da8a..0000000
Binary files a/dist/images/2x/icon/dark/tree_vertical_line_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_vertical_line_4.png b/dist/images/2x/icon/dark/tree_vertical_line_4.png
deleted file mode 100644
index 4645b52..0000000
Binary files a/dist/images/2x/icon/dark/tree_vertical_line_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/dark/tree_vertical_line_5.png b/dist/images/2x/icon/dark/tree_vertical_line_5.png
deleted file mode 100644
index 3fd2c56..0000000
Binary files a/dist/images/2x/icon/dark/tree_vertical_line_5.png and /dev/null differ
diff --git a/dist/images/2x/icon/dots.png b/dist/images/2x/icon/dots.png
deleted file mode 100644
index beae59d..0000000
Binary files a/dist/images/2x/icon/dots.png and /dev/null differ
diff --git a/dist/images/2x/icon/half_selected.png b/dist/images/2x/icon/half_selected.png
deleted file mode 100644
index 765aabc..0000000
Binary files a/dist/images/2x/icon/half_selected.png and /dev/null differ
diff --git a/dist/images/2x/icon/icon_down_arrow.png b/dist/images/2x/icon/icon_down_arrow.png
deleted file mode 100644
index 5285f73..0000000
Binary files a/dist/images/2x/icon/icon_down_arrow.png and /dev/null differ
diff --git a/dist/images/2x/icon/loading.gif b/dist/images/2x/icon/loading.gif
deleted file mode 100644
index d04fdd2..0000000
Binary files a/dist/images/2x/icon/loading.gif and /dev/null differ
diff --git a/dist/images/2x/icon/push_down.png b/dist/images/2x/icon/push_down.png
deleted file mode 100644
index 88ef8d5..0000000
Binary files a/dist/images/2x/icon/push_down.png and /dev/null differ
diff --git a/dist/images/2x/icon/push_up.png b/dist/images/2x/icon/push_up.png
deleted file mode 100644
index 040d502..0000000
Binary files a/dist/images/2x/icon/push_up.png and /dev/null differ
diff --git a/dist/images/2x/icon/radio_active.png b/dist/images/2x/icon/radio_active.png
deleted file mode 100644
index e465430..0000000
Binary files a/dist/images/2x/icon/radio_active.png and /dev/null differ
diff --git a/dist/images/2x/icon/radio_disable.png b/dist/images/2x/icon/radio_disable.png
deleted file mode 100644
index dfe0413..0000000
Binary files a/dist/images/2x/icon/radio_disable.png and /dev/null differ
diff --git a/dist/images/2x/icon/radio_disable2.png b/dist/images/2x/icon/radio_disable2.png
deleted file mode 100644
index 8476062..0000000
Binary files a/dist/images/2x/icon/radio_disable2.png and /dev/null differ
diff --git a/dist/images/2x/icon/radio_normal.png b/dist/images/2x/icon/radio_normal.png
deleted file mode 100644
index 0bbd274..0000000
Binary files a/dist/images/2x/icon/radio_normal.png and /dev/null differ
diff --git a/dist/images/2x/icon/slider_active.png b/dist/images/2x/icon/slider_active.png
deleted file mode 100644
index cf361f7..0000000
Binary files a/dist/images/2x/icon/slider_active.png and /dev/null differ
diff --git a/dist/images/2x/icon/slider_active_small.png b/dist/images/2x/icon/slider_active_small.png
deleted file mode 100644
index 1c29cec..0000000
Binary files a/dist/images/2x/icon/slider_active_small.png and /dev/null differ
diff --git a/dist/images/2x/icon/slider_normal.png b/dist/images/2x/icon/slider_normal.png
deleted file mode 100644
index a81cf03..0000000
Binary files a/dist/images/2x/icon/slider_normal.png and /dev/null differ
diff --git a/dist/images/2x/icon/slider_normal_small.png b/dist/images/2x/icon/slider_normal_small.png
deleted file mode 100644
index 7bd6fc7..0000000
Binary files a/dist/images/2x/icon/slider_normal_small.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_collapse_1.png b/dist/images/2x/icon/tree_collapse_1.png
deleted file mode 100644
index f2d63e2..0000000
Binary files a/dist/images/2x/icon/tree_collapse_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_collapse_2.png b/dist/images/2x/icon/tree_collapse_2.png
deleted file mode 100644
index 4f87550..0000000
Binary files a/dist/images/2x/icon/tree_collapse_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_collapse_3.png b/dist/images/2x/icon/tree_collapse_3.png
deleted file mode 100644
index 88cfeba..0000000
Binary files a/dist/images/2x/icon/tree_collapse_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_collapse_4.png b/dist/images/2x/icon/tree_collapse_4.png
deleted file mode 100644
index 31c33b9..0000000
Binary files a/dist/images/2x/icon/tree_collapse_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_expand_1.png b/dist/images/2x/icon/tree_expand_1.png
deleted file mode 100644
index 2fb7e3b..0000000
Binary files a/dist/images/2x/icon/tree_expand_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_expand_2.png b/dist/images/2x/icon/tree_expand_2.png
deleted file mode 100644
index 9a26edb..0000000
Binary files a/dist/images/2x/icon/tree_expand_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_expand_3.png b/dist/images/2x/icon/tree_expand_3.png
deleted file mode 100644
index 6f6b5a7..0000000
Binary files a/dist/images/2x/icon/tree_expand_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_expand_4.png b/dist/images/2x/icon/tree_expand_4.png
deleted file mode 100644
index c202c72..0000000
Binary files a/dist/images/2x/icon/tree_expand_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_vertical_line_1.png b/dist/images/2x/icon/tree_vertical_line_1.png
deleted file mode 100644
index e88f2a6..0000000
Binary files a/dist/images/2x/icon/tree_vertical_line_1.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_vertical_line_2.png b/dist/images/2x/icon/tree_vertical_line_2.png
deleted file mode 100644
index 554d8b3..0000000
Binary files a/dist/images/2x/icon/tree_vertical_line_2.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_vertical_line_3.png b/dist/images/2x/icon/tree_vertical_line_3.png
deleted file mode 100644
index 8e7da8a..0000000
Binary files a/dist/images/2x/icon/tree_vertical_line_3.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_vertical_line_4.png b/dist/images/2x/icon/tree_vertical_line_4.png
deleted file mode 100644
index 4645b52..0000000
Binary files a/dist/images/2x/icon/tree_vertical_line_4.png and /dev/null differ
diff --git a/dist/images/2x/icon/tree_vertical_line_5.png b/dist/images/2x/icon/tree_vertical_line_5.png
deleted file mode 100644
index 3fd2c56..0000000
Binary files a/dist/images/2x/icon/tree_vertical_line_5.png and /dev/null differ
diff --git a/dist/resource/ZeroClipboard.swf b/dist/resource/ZeroClipboard.swf
deleted file mode 100644
index 13bf8e3..0000000
Binary files a/dist/resource/ZeroClipboard.swf and /dev/null differ
diff --git a/index.html b/index.html
deleted file mode 100644
index fd39c4e..0000000
--- a/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- FineUI-Start
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/package.json b/package.json
index ae7946f..4888ecd 100644
--- a/package.json
+++ b/package.json
@@ -1,47 +1,77 @@
{
- "name": "fineui-start",
+ "name": "fineui-starter",
"version": "1.0.0",
- "description": "fineui start",
- "main": "index.js",
+ "description": "fineui starter",
+ "scripts": {
+ "start": "webpack-dev-server -p --progress --host 127.0.0.1 --config=webpack/webpack.dev.js --mode development",
+ "build": "webpack -p --progress --config=webpack/webpack.prod.js --mode production",
+ "test": "jest",
+ "eslint": "eslint \"./**/*.{js,ts,jsx,tsx}\"",
+ "eslint:fix": "eslint \"./**/*.{js,ts,tsx}\" --fix",
+ "stylelint": "stylelint \"./**/*.less\" --syntax less",
+ "stylelint:fix": "stylelint \"./**/*.less\" --syntax less --fix",
+ "prettier": "prettier --write \"./**/*.{js,ts,jsx,tsx,less}\""
+ },
"dependencies": {
- "fineui": "^2.0.0"
+ "@fui/core": "^2.0.0"
},
"devDependencies": {
"@fui/babel-preset-fineui": "^1.0.0",
- "@fui/typescript-configs": "^1.0.1",
"@fui/eslint-plugin": "^1.0.7",
- "@types/jest": "24.0.11",
- "typescript": "3.9.2",
- "fork-ts-checker-webpack-plugin": "1.4.3",
+ "@fui/typescript-configs": "^1.0.1",
+ "@types/jest": "^24.0.11",
"autoprefixer": "9.6.1",
"babel-loader": "8.0.6",
+ "babel-plugin-transform-runtime": "6.23.0",
"cross-env": "6.0.0",
"css-loader": "3.0.0",
+ "eslint": "^7.30.0",
+ "eslint-plugin-jest": "^24.3.6",
+ "eslint-plugin-react": "^7.24.0",
+ "fork-ts-checker-webpack-plugin": "1.4.3",
"html-webpack-plugin": "3.2.0",
+ "husky": "^7.0.1",
"jest": "24.7.1",
"jest-css-modules-transform": "2.5.0",
"jest-environment-jsdom": "24.7.1",
"jest-snapshot": "23.6.0",
"less": "^3.11.3",
"less-loader": "5.0.0",
+ "lint-staged": "^11.0.1",
"mini-css-extract-plugin": "0.7.0",
"npm-run-all": "4.1.5",
"optimize-css-assets-webpack-plugin": "5.0.3",
"postcss-loader": "3.0.0",
"postcss-simple-vars": "5.0.2",
+ "prettier": "^2.3.2",
"source-map-loader": "0.2.4",
"style-loader": "0.23.1",
+ "stylelint": "^13.13.1",
+ "stylelint-config-prettier": "^8.0.2",
+ "stylelint-config-standard": "^22.0.0",
+ "stylelint-prettier": "^1.2.0",
+ "typescript": "3.9.2",
"uglifyjs-webpack-plugin": "2.2.0",
"webpack": "4.35.2",
"webpack-cli": "3.3.5",
"webpack-dev-server": "3.7.2",
"webpack-merge": "4.2.1"
},
- "scripts": {
- "start": "webpack-dev-server -p --progress --host 127.0.0.1 --config=webpack/webpack.dev.js --mode development",
- "build": "webpack -p --progress --config=webpack/webpack.prod.js --mode production",
- "test": "jest"
- },
"author": "",
- "license": "MIT"
+ "license": "MIT",
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "*.{js,ts}": [
+ "eslint --fix",
+ "git add"
+ ],
+ "*.less": [
+ "stylelint --fix",
+ "git add"
+ ]
+ }
}
diff --git a/screenshorts/todolist.gif b/screenshorts/todolist.gif
deleted file mode 100644
index 15a465e..0000000
Binary files a/screenshorts/todolist.gif and /dev/null differ
diff --git a/screenshots/demo.jpeg b/screenshots/demo.jpeg
new file mode 100644
index 0000000..94decdb
Binary files /dev/null and b/screenshots/demo.jpeg differ
diff --git a/src/common/app.less b/src/common/app.less
deleted file mode 100644
index 491bdf4..0000000
--- a/src/common/app.less
+++ /dev/null
@@ -1,14 +0,0 @@
-@import "../../fineui/src/less/resource/app";
-
-//定义自己的全局样式配置
-#body {
-}
-
-#wrapper {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- .overflow-hidden();
-}
\ No newline at end of file
diff --git a/src/common/background.less b/src/common/background.less
deleted file mode 100644
index f2dfaa9..0000000
--- a/src/common/background.less
+++ /dev/null
@@ -1,3 +0,0 @@
-@import "../../fineui/src/less/resource/background";
-
-//定义自己的背景
\ No newline at end of file
diff --git a/src/common/font.less b/src/common/font.less
deleted file mode 100644
index 9459171..0000000
--- a/src/common/font.less
+++ /dev/null
@@ -1,3 +0,0 @@
-@import "../../fineui/src/less/resource/font";
-
-//定义自己的字体
diff --git a/src/common/icon.less b/src/common/icon.less
deleted file mode 100644
index 610fc21..0000000
--- a/src/common/icon.less
+++ /dev/null
@@ -1,3 +0,0 @@
-@import "../../fineui/src/less/resource/icon";
-
-//定义自己的icon
\ No newline at end of file
diff --git a/src/core/javascript/decorator.js b/src/core/javascript/decorator.js
deleted file mode 100644
index e5f32dd..0000000
--- a/src/core/javascript/decorator.js
+++ /dev/null
@@ -1 +0,0 @@
-export const { shortcut, Model, model, store } = BI.Decorators;
diff --git a/src/core/typescript/decorator.ts b/src/core/typescript/decorator.ts
deleted file mode 100644
index ee94eb1..0000000
--- a/src/core/typescript/decorator.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const { shortcut, Model, model, store } = BI.Decorators;
-
-export type Constructor = new(...args: any[]) => T;
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 3a8714d..0000000
--- a/src/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ToDoList } from "./modules/main";
-
-// 将todolist组件挂载到#wrapper上.
-BI.createWidget({
- type: ToDoList.xtype,
- element: "#wrapper"
-});
diff --git a/src/index.less b/src/index.less
index 09f8de8..0ec9d28 100644
--- a/src/index.less
+++ b/src/index.less
@@ -1,5 +1,9 @@
-@import "../node_modules/fineui/src/less/index";
+@import './less/index.less';
-@fontUrl: 'font/'; //字体存放路径
-@imageUrl: 'images/1x/'; //图片的基本地址
-@image2xUrl: 'images/2x/'; //2x图片的基本地址
\ No newline at end of file
+#wrapper {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..267debf
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,7 @@
+import Layout from '@app/layout/layout';
+import './index.less';
+
+BI.createWidget({
+ type: Layout.xtype,
+ element: '#wrapper',
+});
diff --git a/src/less/index.less b/src/less/index.less
new file mode 100644
index 0000000..4dff600
--- /dev/null
+++ b/src/less/index.less
@@ -0,0 +1,7 @@
+@import '~@fui/core/src/less/index.less';
+@import '~@fui/core/src/less/image.less';
+@import './var.less';
+@import './resource/app.less';
+@import './resource/background.less';
+@import './resource/font.less';
+@import './resource/custom.less';
diff --git a/src/less/lib/background.less b/src/less/lib/background.less
new file mode 100644
index 0000000..09e9a54
--- /dev/null
+++ b/src/less/lib/background.less
@@ -0,0 +1,3 @@
+// 背景图片
+
+@background-logo: 'logo.png';
diff --git a/src/less/lib/constant.less b/src/less/lib/constant.less
new file mode 100644
index 0000000..d034086
--- /dev/null
+++ b/src/less/lib/constant.less
@@ -0,0 +1,3 @@
+// 常量
+
+@color-app-primary: yellowgreen;
diff --git a/src/less/lib/font.less b/src/less/lib/font.less
new file mode 100644
index 0000000..6e91cb0
--- /dev/null
+++ b/src/less/lib/font.less
@@ -0,0 +1,4 @@
+// 字体图标,请参考:http://fanruan.design/#/docs/spec/icon
+
+@font-directory: 'e748';
+@font-management: 'e777';
diff --git a/src/less/resource/app.less b/src/less/resource/app.less
new file mode 100644
index 0000000..b344a50
--- /dev/null
+++ b/src/less/resource/app.less
@@ -0,0 +1,47 @@
+@import '../lib/constant.less';
+
+// 左边框式列表选项
+.app-list-item-border-left {
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ color: @color-bi-text-gray;
+ &:hover,
+ &.hover {
+ color: @color-bi-text-white;
+ }
+ &.active,
+ &:active {
+ border-left: 4px solid white;
+ color: @color-bi-text-white;
+ }
+ &.disabled {
+ &,
+ &:hover,
+ &:active {
+ color: @color-bi-text-disabled !important;
+ }
+ }
+}
+
+// 下划线式列表选项
+.app-list-item-underline {
+ .box-sizing(border-box);
+ &:hover,
+ &.hover {
+ font-weight: bold;
+ }
+ &.active,
+ &:active {
+ border-bottom: 2px solid @color-app-primary;
+ font-weight: bold;
+ color: @color-app-primary;
+ background-color: @color-bi-background-default;
+ }
+ &.disabled {
+ &,
+ &:hover,
+ &:active {
+ color: @color-bi-text-disabled !important;
+ }
+ }
+}
diff --git a/src/less/resource/background.less b/src/less/resource/background.less
new file mode 100644
index 0000000..af3c91d
--- /dev/null
+++ b/src/less/resource/background.less
@@ -0,0 +1,3 @@
+@import '../lib/background.less';
+
+.background(logo-background, @background-logo);
diff --git a/src/less/resource/custom.less b/src/less/resource/custom.less
new file mode 100644
index 0000000..9a3823d
--- /dev/null
+++ b/src/less/resource/custom.less
@@ -0,0 +1,40 @@
+@import '../lib/constant.less';
+
+.bi-high-light {
+ color: @color-app-primary;
+}
+
+.bi-high-light-background {
+ background-color: @color-app-primary;
+}
+
+.bi-list-item-select {
+ &:hover,
+ &.hover {
+ .background-color(@color-app-primary, 10%);
+ }
+ &:active,
+ &.active {
+ color: white;
+ background-color: @color-app-primary;
+ }
+}
+
+.bi-list-item {
+ &:hover,
+ &.hover {
+ .background-color(@color-app-primary, 10%);
+ }
+}
+
+.bi-list-item-active2 {
+ &:hover,
+ &.hover {
+ .background-color(@color-app-primary, 10%);
+ }
+ &:active,
+ &.active {
+ color: white;
+ background-color: @color-app-primary;
+ }
+}
diff --git a/src/less/resource/font.less b/src/less/resource/font.less
new file mode 100644
index 0000000..0b557c6
--- /dev/null
+++ b/src/less/resource/font.less
@@ -0,0 +1,4 @@
+@import '../lib/font.less';
+
+.font(directory-font, @font-directory);
+.font(management-font, @font-management);
diff --git a/src/less/var.less b/src/less/var.less
new file mode 100644
index 0000000..cfd1607
--- /dev/null
+++ b/src/less/var.less
@@ -0,0 +1,3 @@
+@fontUrl: 'assets/font/'; // 字体的存放路径
+@imageUrl: 'assets/images/1x/'; // 1x图片的基本路径
+@image2xUrl: 'assets/images/2x/'; // 2x图片的基本路径
diff --git a/src/modules/app/layout/content/content.less b/src/modules/app/layout/content/content.less
new file mode 100644
index 0000000..e4e25e3
--- /dev/null
+++ b/src/modules/app/layout/content/content.less
@@ -0,0 +1,5 @@
+@import '~@/index.less';
+
+.app-layout-content {
+ background-color: @background-color-default;
+}
diff --git a/src/modules/app/layout/content/content.model.ts b/src/modules/app/layout/content/content.model.ts
new file mode 100644
index 0000000..5908489
--- /dev/null
+++ b/src/modules/app/layout/content/content.model.ts
@@ -0,0 +1,41 @@
+import { model, Model } from '@core/decorator';
+import LayoutModel from '../layout.model';
+
+@model()
+export default class LayoutContentModel extends Model<{
+ types: {
+ openedCards: LayoutModel['TYPE']['openedCards'];
+ activeCard: LayoutModel['TYPE']['activeCard'];
+ };
+ context: LayoutContentModel['context'];
+}> {
+ static xtype = 'app.model.layout_content';
+
+ public context = ['openedCards', 'activeCard'];
+
+ public actions = {
+ /**
+ * 切换card
+ * @param value 要切换的card的key
+ */
+ changeCard: (value: string) => {
+ this.model.activeCard = value;
+ },
+ /**
+ * 关闭card
+ * @param value 要关闭的card的key
+ */
+ closeCard: (value: string) => {
+ // 获取要关闭card在已打开cards中的下标
+ const index = BI.indexOf(this.model.openedCards, value);
+ // 如果要关闭card就是当前card,则自动切换至其它card
+ if (value === this.model.activeCard) {
+ const [prevIndex, nextIndex] = [index - 1, index + 1];
+ const [prevCard, nextCard] = [this.model.openedCards[prevIndex], this.model.openedCards[nextIndex]];
+ this.model.activeCard = nextCard || prevCard;
+ }
+ // 然后从已打开cards中移除目标card
+ BI.removeAt(this.model.openedCards, index);
+ },
+ };
+}
diff --git a/src/modules/app/layout/content/content.tsx b/src/modules/app/layout/content/content.tsx
new file mode 100644
index 0000000..9ce508e
--- /dev/null
+++ b/src/modules/app/layout/content/content.tsx
@@ -0,0 +1,156 @@
+import { Tab } from '@fui/core';
+import { shortcut, store } from '@core/decorator';
+import { Nav, NavItemInfo, NavItemStyle } from '@base/nav/nav';
+import { RouteType, RouteInfo, ROUTE_INFOS } from '@/routes';
+import LayoutContentModel from './content.model';
+import LayoutConstant from '../layout.constant';
+import './content.less';
+
+// 路由信息value与页面内容的映射关系,可以理解成一个经过faltten的路由信息集合
+export interface ContentsMap {
+ [key: string]: NavItemInfo & Required> & Partial>;
+}
+
+// 路由类别与导航选项风格的映射关系
+export const ROUTE_TYPE_NAV_ITEM_STYLE_MAP = {
+ [RouteType.Single]: NavItemStyle.Block,
+ [RouteType.Multiple]: NavItemStyle.Underline,
+};
+
+/**
+ * 应用布局的内容区域,包括导航栏和实际内容区域
+ */
+@shortcut()
+@store(LayoutContentModel)
+export class LayoutContent extends BI.Widget {
+ static xtype = 'app.layout_content';
+
+ public props = {
+ baseCls: 'app-layout-content',
+ };
+
+ public watch = {
+ openedCards: (values: string[]) => {
+ this.udpateNavItemInfos(values);
+ this.updateNavValue();
+ },
+ activeCard: (value: string) => {
+ this.updateNavItemStyle(value);
+ this.updateNavValue();
+ this.tabRef.setSelect(value);
+ },
+ };
+
+ private model: LayoutContentModel['model'];
+ private store: LayoutContentModel['store'];
+ private navRef: Nav;
+ private tabRef: Tab;
+ private contentsMap: ContentsMap;
+
+ /**
+ * 初始化ContentsMap
+ * @param routeInfos 路由信息集合
+ * @param closable 当前路由信息对应的导航选项是否可关闭
+ */
+ private initContentsMap(routeInfos: RouteInfo[], closable: boolean) {
+ if (!this.contentsMap) {
+ this.contentsMap = {};
+ }
+ for (const routeInfo of routeInfos) {
+ const { type, value, text, card: Card, cards, children } = routeInfo;
+ const isHome = type !== undefined;
+ const newClosable = type === RouteType.Single ? true : closable;
+ this.contentsMap[value] = {
+ type,
+ value,
+ text: isHome ? '首页' : text,
+ closable: isHome ? false : newClosable,
+ card: Card ? : ,
+ };
+ if (children) {
+ this.initContentsMap(children, newClosable);
+ }
+ if (cards) {
+ this.initContentsMap(cards, newClosable);
+ }
+ }
+ }
+
+ /**
+ * 更新导航组件的itemInfos
+ * @param values 当前打卡的卡片们的values
+ */
+ private udpateNavItemInfos(values: string[]) {
+ const itemInfos = BI.map(values, (_index, value) => this.contentsMap[value]);
+ this.navRef.setItemInfos(itemInfos);
+ }
+
+ /**
+ * 更新导航组件的itemStyle
+ * @param value 当前激活卡片的value
+ */
+ private updateNavItemStyle(value: string) {
+ const { type } = this.contentsMap[value];
+ if (type !== undefined) {
+ const itemStyle = ROUTE_TYPE_NAV_ITEM_STYLE_MAP[type];
+ this.navRef.setItemStyle(itemStyle);
+ }
+ }
+
+ /**
+ * 根据当前激活卡片的value更新导航组件的值
+ */
+ private updateNavValue() {
+ this.navRef.setValue(this.model.activeCard);
+ }
+
+ public init() {
+ this.initContentsMap([{ value: '', text: 'blank', icon: '' }, ...ROUTE_INFOS], false);
+ }
+
+ public render() {
+ const { NAV_HEIGHT } = LayoutConstant;
+ const navValue = ROUTE_INFOS[0].value;
+ const navItemInfo = this.contentsMap[navValue];
+ const navItemType = navItemInfo.type as RouteType;
+ const navItemStyle = ROUTE_TYPE_NAV_ITEM_STYLE_MAP[navItemType];
+
+ return (
+
+
+ );
+ }
+}
diff --git a/src/modules/app/layout/header/header.less b/src/modules/app/layout/header/header.less
new file mode 100644
index 0000000..a84fa3e
--- /dev/null
+++ b/src/modules/app/layout/header/header.less
@@ -0,0 +1,17 @@
+@import '~@/index.less';
+
+.app-layout-header {
+ .box-shadow(0 0 10px, rgba(@background-color-black, 10%));
+ .logo {
+ }
+ .title {
+ font-size: @font-size-16;
+ }
+ .user {
+ .avatar {
+ border-radius: 100%;
+ }
+ .name {
+ }
+ }
+}
diff --git a/src/modules/app/layout/header/header.tsx b/src/modules/app/layout/header/header.tsx
new file mode 100644
index 0000000..b684c2e
--- /dev/null
+++ b/src/modules/app/layout/header/header.tsx
@@ -0,0 +1,59 @@
+import { shortcut } from '@core/decorator';
+import LayoutConstant from '../layout.constant';
+import './header.less';
+
+// 测试用的用户信息
+const userInfo = {
+ name: 'Finer',
+ avatarSrc: 'https://code.fanruan.com/img/gitea-sm.png',
+};
+
+/**
+ * 应用布局的顶栏,包括应用logo、标题和用户信息
+ */
+@shortcut()
+export class LayoutHeader extends BI.Widget {
+ static xtype = 'app.layout_header';
+
+ public props = {
+ baseCls: 'app-layout-header',
+ };
+
+ public render() {
+ const { APP_TITLE_TEXT, MAIN_MENU_WIDTH, HEADER_HEIGHT } = LayoutConstant;
+
+ return (
+
+
+ ,
+ ,
+ ],
+ right: [
+ {
+ BI.Msg.toast(`您点击了第一个图标`);
+ }}
+ />,
+ {
+ BI.Msg.toast(`您点击了第二个图标`);
+ }}
+ />,
+
+
+
+ ,
+ ],
+ }}
+ />
+ );
+ }
+}
diff --git a/src/modules/app/layout/layout.constant.ts b/src/modules/app/layout/layout.constant.ts
new file mode 100644
index 0000000..506067d
--- /dev/null
+++ b/src/modules/app/layout/layout.constant.ts
@@ -0,0 +1,7 @@
+export default {
+ APP_TITLE_TEXT: 'FineBI 商业智能', // 应用标题文字
+ MAIN_MENU_WIDTH: 72, // 一级菜单宽度
+ SUB_MENU_WIDTH: 208, // 二级菜单宽度
+ HEADER_HEIGHT: 40, // 顶栏高度
+ NAV_HEIGHT: 36, // 导航栏高度
+};
diff --git a/src/modules/app/layout/layout.less b/src/modules/app/layout/layout.less
new file mode 100644
index 0000000..9f30789
--- /dev/null
+++ b/src/modules/app/layout/layout.less
@@ -0,0 +1,16 @@
+@import '~@/index.less';
+
+.app-layout {
+ .app-layout-header {
+ .z-index-layer(2);
+ }
+ .app-layout-body {
+ .z-index-layer(1);
+ .app-layout-sider {
+ .z-index-layer(2);
+ }
+ .app-layout-content {
+ .z-index-layer(1);
+ }
+ }
+}
diff --git a/src/modules/app/layout/layout.model.ts b/src/modules/app/layout/layout.model.ts
new file mode 100644
index 0000000..03f357b
--- /dev/null
+++ b/src/modules/app/layout/layout.model.ts
@@ -0,0 +1,21 @@
+import { model, Model } from '@core/decorator';
+import { ROUTE_INFOS } from '@/routes';
+
+@model()
+export default class LayoutModel extends Model {
+ static xtype = 'app.model.layout';
+
+ public childContext = ['openedCards', 'activeCard'];
+
+ public state(): LayoutModelState {
+ return {
+ openedCards: [ROUTE_INFOS[0].value],
+ activeCard: ROUTE_INFOS[0].value,
+ };
+ }
+}
+
+interface LayoutModelState {
+ openedCards: string[]; // 打开卡片的key的集合
+ activeCard: string; // 当前卡片的key
+}
diff --git a/src/modules/app/layout/layout.tsx b/src/modules/app/layout/layout.tsx
new file mode 100644
index 0000000..81a1ad0
--- /dev/null
+++ b/src/modules/app/layout/layout.tsx
@@ -0,0 +1,34 @@
+import { shortcut, store } from '@core/decorator';
+import { LayoutHeader } from './header/header';
+import { LayoutSider } from './sider/sider';
+import { LayoutContent } from './content/content';
+import LayoutConstant from './layout.constant';
+import LayoutModel from './layout.model';
+import './layout.less';
+
+/**
+ * 应用布局
+ */
+@shortcut()
+@store(LayoutModel)
+export default class Layout extends BI.Widget {
+ static xtype = 'app.layout';
+
+ public props = {
+ baseCls: 'app-layout',
+ };
+
+ public render() {
+ const { HEADER_HEIGHT, MAIN_MENU_WIDTH, SUB_MENU_WIDTH } = LayoutConstant;
+
+ return (
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/modules/app/layout/sider/sider.less b/src/modules/app/layout/sider/sider.less
new file mode 100644
index 0000000..713d0df
--- /dev/null
+++ b/src/modules/app/layout/sider/sider.less
@@ -0,0 +1,10 @@
+@import '~@/index.less';
+
+.app-layout-sider {
+ .app-layout-sider-main-menu {
+ // background-color: @background-color-black;
+ background-color: darken(@color-app-primary, 25%);
+ }
+ .app-layout-sider-sub-menu {
+ }
+}
diff --git a/src/modules/app/layout/sider/sider.model.ts b/src/modules/app/layout/sider/sider.model.ts
new file mode 100644
index 0000000..21c7019
--- /dev/null
+++ b/src/modules/app/layout/sider/sider.model.ts
@@ -0,0 +1,43 @@
+import { model, Model } from '@core/decorator';
+import LayoutModel from '../layout.model';
+
+@model()
+export default class LayoutSiderModel extends Model<{
+ types: {
+ openedCards: LayoutModel['TYPE']['openedCards'];
+ activeCard: LayoutModel['TYPE']['activeCard'];
+ };
+ context: LayoutSiderModel['context'];
+}> {
+ static xtype = 'app.model.layout_sider';
+
+ public context = ['openedCards', 'activeCard'];
+
+ public actions = {
+ /**
+ * 用于RouteType为Single时打开单个card
+ * @param value 要打开的card
+ */
+ openSingleCard: (value: string) => {
+ if (BI.indexOf(this.model.openedCards, value) === -1) {
+ this.model.openedCards.push(value);
+ }
+ this.model.activeCard = value;
+ },
+ /**
+ * 用于RouteType为Multiple时打开多个card
+ * @param values 要打开的card们
+ */
+ openMultipleCards: (values: string[]) => {
+ this.model.openedCards = values;
+ this.model.activeCard = values[0];
+ },
+ /**
+ * 用于切换一级菜单时关闭所有cards
+ */
+ closeAllCards: () => {
+ this.model.openedCards = [];
+ this.model.activeCard = '';
+ },
+ };
+}
diff --git a/src/modules/app/layout/sider/sider.tsx b/src/modules/app/layout/sider/sider.tsx
new file mode 100644
index 0000000..3cb92cf
--- /dev/null
+++ b/src/modules/app/layout/sider/sider.tsx
@@ -0,0 +1,119 @@
+import { shortcut, store } from '@core/decorator';
+import { Menu, MenuItemInfo, MenuItemStyle } from '@base/menu/menu';
+import { RouteType, RouteInfo, ROUTE_INFOS } from '@/routes';
+import LayoutSiderModel from './sider.model';
+import LayoutConstant from '../layout.constant';
+import './sider.less';
+
+/**
+ * 应用布局的侧栏,包括一级菜单和二级菜单
+ */
+@shortcut()
+@store(LayoutSiderModel)
+export class LayoutSider extends BI.Widget {
+ static xtype = 'app.layout_sider';
+
+ public props = {
+ baseCls: 'app-layout-sider',
+ };
+
+ public watch = {
+ openedCards: (values: string[]) => {
+ this.updateSubMenuValueByOpenedCardChange(values);
+ },
+ activeCard: (value: string) => {
+ this.updateSubMenuValueByActiveCardChange(value);
+ },
+ };
+
+ private model: LayoutSiderModel['model'];
+ private store: LayoutSiderModel['store'];
+ private subMenuRef: Menu;
+
+ /**
+ * 更新二级菜单的itemInfos
+ * @param value 当前选中的一级菜单选项的value值
+ */
+ private updateSubMenuItemInfos(value: string) {
+ const mainMenuItemInfo = BI.find(ROUTE_INFOS, { value }) as RouteInfo;
+ const subMenuItemInfos = mainMenuItemInfo.children as MenuItemInfo[];
+ this.subMenuRef.setItemInfos(subMenuItemInfos);
+ }
+
+ /**
+ * 更新二级菜单的value
+ */
+ private updateSubMenuValueByOpenedCardChange(values: string[]) {
+ // console.log('openedcard change', values);
+ const mainRouteInfo = BI.find(ROUTE_INFOS, { value: values[0] });
+ if (mainRouteInfo && mainRouteInfo.type === RouteType.Single && values.length === 1) {
+ this.subMenuRef.setValue('');
+ }
+ }
+
+ /**
+ * 更新二级菜单的value
+ */
+ private updateSubMenuValueByActiveCardChange(value: string) {
+ // console.log('activecard change', value);
+ const mainRouteInfo = BI.find(ROUTE_INFOS, { value: this.model.openedCards[0] });
+ if (mainRouteInfo && mainRouteInfo.type === RouteType.Single) {
+ this.subMenuRef.setValue(value);
+ }
+ }
+
+ public render() {
+ const { MAIN_MENU_WIDTH, SUB_MENU_WIDTH } = LayoutConstant;
+ const mainMenuItemInfos = BI.map(ROUTE_INFOS, (_index, routeInfo) => {
+ const { value, text, icon } = routeInfo;
+
+ return {
+ value,
+ text,
+ icon,
+ };
+ });
+ const subMenuItemInfos = ROUTE_INFOS[0].children;
+
+ return (
+
+ {/* 一级菜单 */}
+
+ );
+ }
+}
diff --git a/src/modules/base/menu/item/item.less b/src/modules/base/menu/item/item.less
new file mode 100644
index 0000000..13aa247
--- /dev/null
+++ b/src/modules/base/menu/item/item.less
@@ -0,0 +1,16 @@
+@import '~@/index.less';
+
+.app-base-menu-item {
+ &.app-base-menu-item-main {
+ .icon {
+ }
+ .text {
+ }
+ }
+ &.app-base-menu-item-sub {
+ .icon {
+ }
+ .text {
+ }
+ }
+}
diff --git a/src/modules/base/menu/item/item.tsx b/src/modules/base/menu/item/item.tsx
new file mode 100644
index 0000000..4fe95b5
--- /dev/null
+++ b/src/modules/base/menu/item/item.tsx
@@ -0,0 +1,71 @@
+import { Widget, BasicButton } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { MenuItemStyle } from '../menu';
+import './item.less';
+
+/**
+ * 菜单选项
+ */
+@shortcut()
+export class MenuItem extends BI.BasicButton {
+ static xtype = 'app.base.menu_item';
+
+ public props: MenuItemProps & BasicButton['props'] = {
+ baseCls: 'app-base-menu-item',
+ value: '',
+ text: '',
+ icon: '',
+ level: 0,
+ style: MenuItemStyle.Main,
+ };
+
+ /**
+ * 创建Main风格的菜单选项组件
+ * @returns 创建的菜单选项组件
+ */
+ private createMainMenuItem(): Widget {
+ const { text, icon } = this.options;
+
+ return (
+
+
+
+
+ );
+ }
+
+ /**
+ * 创建Sub风格的菜单选项组件
+ * @returns 创建的菜单选项组件
+ */
+ private createSubMenuItem() {
+ const { text, icon, level } = this.options;
+
+ return (
+
+
+
+
+ );
+ }
+
+ public render() {
+ const { style } = this.options;
+ // 菜单选项与组件创建函数的映射关系
+ const menuItemStyleCreatorsMap = {
+ [MenuItemStyle.Main]: this.createMainMenuItem.bind(this),
+ [MenuItemStyle.Sub]: this.createSubMenuItem.bind(this),
+ };
+
+ return menuItemStyleCreatorsMap[style]();
+ }
+}
+
+interface MenuItemProps {
+ baseCls: string;
+ value: string;
+ text: string;
+ icon: string;
+ level: number;
+ style: MenuItemStyle;
+}
diff --git a/src/modules/base/menu/menu.less b/src/modules/base/menu/menu.less
new file mode 100644
index 0000000..db66d7f
--- /dev/null
+++ b/src/modules/base/menu/menu.less
@@ -0,0 +1,4 @@
+@import '~@/index.less';
+
+.app-base-menu {
+}
diff --git a/src/modules/base/menu/menu.tsx b/src/modules/base/menu/menu.tsx
new file mode 100644
index 0000000..58d34a4
--- /dev/null
+++ b/src/modules/base/menu/menu.tsx
@@ -0,0 +1,125 @@
+import { Widget, CustomTree } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { MenuNode } from './node/node';
+import { MenuItem } from './item/item';
+import './menu.less';
+
+// 菜单选项信息
+export interface MenuItemInfo {
+ value: string;
+ text: string;
+ icon: string;
+ card?: typeof Widget;
+ cards?: MenuItemInfo[];
+ children?: MenuItemInfo[];
+}
+
+// 菜单选项风格
+export enum MenuItemStyle {
+ Main,
+ Sub,
+}
+
+/**
+ * 菜单,有一级菜单和二级菜单两种风格
+ */
+@shortcut()
+export class Menu extends BI.Widget {
+ static xtype = 'app.base.menu';
+
+ static EVENT = {
+ CHANGE: 'EVENT_CHANGE',
+ };
+
+ public props: MenuProps = {
+ baseCls: 'app-base-menu',
+ value: '',
+ itemInfos: [],
+ itemStyle: MenuItemStyle.Main,
+ };
+
+ private menuRef: CustomTree;
+
+ /**
+ * 创建菜单选项组件
+ * @param itemInfos 菜单选项信息
+ * @param itemStyle 菜单选项风格
+ * @param level 菜单选项层次
+ * @returns 菜单选项组件
+ */
+ private createMenuItems(itemInfos: MenuItemInfo[], itemStyle: MenuItemStyle, level: number): (MenuNode | MenuItem)[] {
+ return BI.map(itemInfos, (_index, itemInfo) => {
+ const { value, text, icon, cards, children } = itemInfo;
+ const valueOrValues = cards ? BI.map(cards, (_index, card) => card.value).join(',') : value;
+
+ return children ? (
+
+ ) : (
+
+ );
+ });
+ }
+
+ /**
+ * 获取菜单选项组件
+ * @returns 菜单选项组件
+ */
+ private getMenuItems(): (MenuNode | MenuItem)[] {
+ const { itemInfos, itemStyle } = this.options;
+
+ return this.createMenuItems(itemInfos, itemStyle, 0);
+ }
+
+ /**
+ * 设置itemInfos,会根据其值更新menuRef
+ * @param itemInfos 要设置的itemInfos值
+ */
+ public setItemInfos(itemInfos: MenuItemInfo[]) {
+ this.options.itemInfos = itemInfos;
+ const menuItems = this.getMenuItems();
+ this.menuRef.populate(menuItems);
+ }
+
+ /**
+ * 设置value
+ * @param value 要设置的value值
+ */
+ public setValue(value: string) {
+ this.options.value = value;
+ this.menuRef.setValue(value);
+ }
+
+ public render() {
+ const { itemStyle, value } = this.options;
+ const menuItems = this.getMenuItems();
+ const vgap = itemStyle === MenuItemStyle.Main ? 24 : 0;
+
+ return (
+ {
+ this.menuRef = ref;
+ }}
+ expander={} />}
+ el={]} chooseType={BI.Selection.Single} />}
+ items={menuItems}
+ value={value}
+ listeners={[
+ {
+ eventName: BI.CustomTree.EVENT_CHANGE,
+ action: (value: string) => {
+ const valueOrValues = value.includes(',') ? value.split(',') : value;
+ this.fireEvent(Menu.EVENT.CHANGE, valueOrValues);
+ },
+ },
+ ]}
+ />
+ );
+ }
+}
+
+interface MenuProps {
+ baseCls: string;
+ value: string;
+ itemInfos: MenuItemInfo[];
+ itemStyle: MenuItemStyle;
+}
diff --git a/src/modules/base/menu/node/node.less b/src/modules/base/menu/node/node.less
new file mode 100644
index 0000000..766c45d
--- /dev/null
+++ b/src/modules/base/menu/node/node.less
@@ -0,0 +1,10 @@
+@import '~@/index.less';
+
+.app-base-menu-node {
+ .icon {
+ }
+ .text {
+ }
+ .arrow {
+ }
+}
diff --git a/src/modules/base/menu/node/node.tsx b/src/modules/base/menu/node/node.tsx
new file mode 100644
index 0000000..c746eb8
--- /dev/null
+++ b/src/modules/base/menu/node/node.tsx
@@ -0,0 +1,73 @@
+import { NodeButton, IconChangeButton } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { MenuItem } from '../item/item';
+import './node.less';
+
+// 节点展开和折叠状态分别对应的类名
+export const ARROW_CLASSES_MAP = {
+ collapse: 'column-next-page-h-font',
+ expand: 'column-pre-page-h-font',
+};
+
+/**
+ * 菜单选项中的展开/折叠节点
+ */
+@shortcut()
+export class MenuNode extends BI.NodeButton {
+ static xtype = 'app.base.menu_node';
+
+ public props: MenuNodeProps & NodeButton['props'] = {
+ baseCls: 'app-base-menu-node bi-list-item',
+ height: 36,
+ open: false,
+ value: '',
+ text: '',
+ icon: '',
+ level: 0,
+ children: [],
+ };
+
+ private arrowRef: IconChangeButton;
+
+ /**
+ * 设置菜单节点的展开情况
+ * @param opened 要设置的展开情况,ture表示展开,false表示折叠
+ */
+ public setOpened(opened: boolean) {
+ Object.getPrototypeOf(MenuNode).prototype.setOpened.call(this, opened);
+ const arrowCls = ARROW_CLASSES_MAP[opened ? 'expand' : 'collapse'];
+ this.arrowRef.setIcon(arrowCls);
+ }
+
+ public render() {
+ const { text, icon, level } = this.options;
+
+ return (
+ , ],
+ right: [
+ {
+ this.arrowRef = ref;
+ }}
+ iconCls="arrow"
+ />,
+ ],
+ }}
+ />
+ );
+ }
+}
+
+interface MenuNodeProps {
+ baseCls: string;
+ height: number;
+ value: string;
+ text: string;
+ icon: string;
+ level: number;
+ children: (MenuNode | MenuItem)[];
+}
diff --git a/src/modules/base/nav/item/item.less b/src/modules/base/nav/item/item.less
new file mode 100644
index 0000000..1fb684c
--- /dev/null
+++ b/src/modules/base/nav/item/item.less
@@ -0,0 +1,13 @@
+@import '~@/index.less';
+
+.app-base-nav-item {
+ .text {
+ }
+ .close {
+ border-radius: 100%;
+ &:hover {
+ color: @font-color-white;
+ background-color: @background-color-negative;
+ }
+ }
+}
diff --git a/src/modules/base/nav/item/item.tsx b/src/modules/base/nav/item/item.tsx
new file mode 100644
index 0000000..cee8eec
--- /dev/null
+++ b/src/modules/base/nav/item/item.tsx
@@ -0,0 +1,50 @@
+import { BasicButton } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { NavItemStyle, NAV_ITEM_STYLE_CLASSES_MAP } from '../nav';
+import './item.less';
+
+@shortcut()
+export class NavItem extends BI.BasicButton {
+ static xtype = 'app.base.nav_item';
+
+ static EVENT = {
+ CLOSE: 'EVENT_CLOSE',
+ };
+
+ public props: NavItemProps & BasicButton['props'] = {
+ baseCls: 'app-base-nav-item bi-split-left bi-split-right',
+ value: '',
+ text: '',
+ closable: false,
+ style: NavItemStyle.Block,
+ };
+
+ public render() {
+ const { value, text, closable, style } = this.options;
+ const cls = NAV_ITEM_STYLE_CLASSES_MAP[style];
+
+ return (
+
+
+ {
+ this.fireEvent(NavItem.EVENT.CLOSE, value);
+ }}
+ />
+
+ );
+ }
+}
+
+interface NavItemProps {
+ baseCls: string;
+ value: string;
+ text: string;
+ closable: boolean;
+ style: NavItemStyle;
+}
diff --git a/src/modules/base/nav/nav.less b/src/modules/base/nav/nav.less
new file mode 100644
index 0000000..2948e45
--- /dev/null
+++ b/src/modules/base/nav/nav.less
@@ -0,0 +1,4 @@
+@import '~@/index.less';
+
+.app-base-nav {
+}
diff --git a/src/modules/base/nav/nav.tsx b/src/modules/base/nav/nav.tsx
new file mode 100644
index 0000000..f3483c7
--- /dev/null
+++ b/src/modules/base/nav/nav.tsx
@@ -0,0 +1,134 @@
+import { ButtonGroup } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { NavItem } from './item/item';
+import './nav.less';
+
+// 导航选项信息
+export interface NavItemInfo {
+ value: string;
+ text: string;
+ closable: boolean;
+}
+
+// 导航选项风格
+export enum NavItemStyle {
+ Block,
+ Underline,
+}
+
+// 导航选项风格与class的映射关系
+export const NAV_ITEM_STYLE_CLASSES_MAP = {
+ [NavItemStyle.Block]: 'bi-list-item-select',
+ [NavItemStyle.Underline]: 'app-list-item-underline',
+};
+
+@shortcut()
+export class Nav extends BI.Widget {
+ static xtype = 'app.base.nav';
+
+ static EVENT = {
+ CHANGE: 'EVENT_CHANGE',
+ CLOSE: 'EVENT_CLOSE',
+ };
+
+ public props: NavProps = {
+ baseCls: 'app-base-nav',
+ height: 36,
+ value: '',
+ itemInfos: [],
+ itemStyle: NavItemStyle.Block,
+ };
+
+ private navRef: ButtonGroup;
+
+ /**
+ * 获取导航菜单选项组件集合
+ * @returns 导航菜单选项组件集合
+ */
+ private getNavItems(): NavItem[] {
+ const { height, itemInfos, itemStyle } = this.options;
+
+ return BI.map(itemInfos, (_index, itemInfo) => {
+ const { value, text, closable } = itemInfo;
+
+ return (
+ {
+ this.fireEvent(Nav.EVENT.CLOSE, value);
+ },
+ },
+ ]}
+ />
+ );
+ });
+ }
+
+ /**
+ * 设置itemInfos,并根据其值更新navRef
+ * @param itemInfos 要设置的itemInfos
+ */
+ public setItemInfos(itemInfos: NavItemInfo[]) {
+ this.options.itemInfos = itemInfos;
+ const navItems = this.getNavItems();
+ this.navRef.populate(navItems);
+ }
+
+ /**
+ * 设置itemStyle,并根据其值更新navRef
+ * @param itemStyle 要设置的itemStyle
+ */
+ public setItemStyle(itemStyle: NavItemStyle) {
+ this.options.itemStyle = itemStyle;
+ const navItems = this.getNavItems();
+ this.navRef.populate(navItems);
+ }
+
+ /**
+ * 设置value
+ * @param value 要设置的value值
+ */
+ public setValue(value: string) {
+ this.options.value = value;
+ this.navRef.setValue(value);
+ }
+
+ public render() {
+ const { value } = this.options;
+ const navItems = this.getNavItems();
+
+ return (
+ {
+ this.navRef = ref;
+ }}
+ layouts={[]}
+ listeners={[
+ {
+ eventName: BI.ButtonGroup.EVENT_CHANGE,
+ action: value => {
+ this.fireEvent(Nav.EVENT.CHANGE, value);
+ },
+ },
+ ]}
+ items={navItems}
+ value={value}
+ />
+ );
+ }
+}
+
+interface NavProps {
+ baseCls: string;
+ height: number;
+ value: string;
+ itemInfos: NavItemInfo[];
+ itemStyle: NavItemStyle;
+}
diff --git a/src/modules/card/demo/demo.less b/src/modules/card/demo/demo.less
new file mode 100644
index 0000000..2b0a10f
--- /dev/null
+++ b/src/modules/card/demo/demo.less
@@ -0,0 +1,5 @@
+@import '~@/index.less';
+
+.app-demo {
+ font-size: @font-size-24;
+}
diff --git a/src/modules/card/demo/demo.model.ts b/src/modules/card/demo/demo.model.ts
new file mode 100644
index 0000000..aac8e0c
--- /dev/null
+++ b/src/modules/card/demo/demo.model.ts
@@ -0,0 +1,15 @@
+import { model, Model } from '@core/decorator';
+import LayoutModel from '@app/layout/layout.model';
+
+@model()
+export default class DemoModel extends Model<{
+ types: {
+ openedCards: LayoutModel['TYPE']['openedCards'];
+ activeCard: LayoutModel['TYPE']['activeCard'];
+ };
+ context: DemoModel['context'];
+}> {
+ static xtype = 'app.model.demo';
+
+ public context = ['openedCards', 'activeCard'];
+}
diff --git a/src/modules/card/demo/demo.tsx b/src/modules/card/demo/demo.tsx
new file mode 100644
index 0000000..522931b
--- /dev/null
+++ b/src/modules/card/demo/demo.tsx
@@ -0,0 +1,73 @@
+import { Label } from '@fui/core';
+import { shortcut, store } from '@core/decorator';
+import DemoModel from './demo.model';
+import './demo.less';
+
+/**
+ * 用于进行基本演示的测试组件
+ */
+@shortcut()
+@store(DemoModel)
+export class Demo extends BI.Widget {
+ static xtype = 'app.demo';
+
+ public props: DeomProps = {
+ baseCls: 'app-demo',
+ cardName: '',
+ };
+
+ public watch = {
+ openedCards: () => {
+ this.updateLabelRef();
+ },
+ activeCard: () => {
+ this.updateLabelRef();
+ },
+ };
+
+ private model: DemoModel['model'];
+ private labelRef: Label;
+
+ /**
+ * 基于cardName和model获取标签的文本内容
+ * @returns 标签的文本内容
+ */
+ private getLabelText(): string {
+ const { cardName } = this.options;
+ const { openedCards, activeCard } = this.model;
+ const text = `
+ 组件名称为 ${cardName},
+ openedCards 为 [ ${openedCards} ],
+ openedCards 的长度为 ${openedCards.length},
+ activeCard 为 ${activeCard}
+ `;
+
+ return text;
+ }
+
+ /**
+ * 更新标签的文本内容
+ */
+ private updateLabelRef() {
+ const labelText = this.getLabelText();
+ this.labelRef.setText(labelText);
+ }
+
+ public render() {
+ const labelText = this.getLabelText();
+
+ return (
+ {
+ this.labelRef = ref;
+ }}
+ text={labelText}
+ />
+ );
+ }
+}
+
+interface DeomProps {
+ baseCls: string;
+ cardName: string;
+}
diff --git a/src/modules/card/home/home.less b/src/modules/card/home/home.less
new file mode 100644
index 0000000..b830f63
--- /dev/null
+++ b/src/modules/card/home/home.less
@@ -0,0 +1,5 @@
+@import '~@/index.less';
+
+.app-home {
+ font-size: @font-size-24;
+}
diff --git a/src/modules/card/home/home.tsx b/src/modules/card/home/home.tsx
new file mode 100644
index 0000000..8ba9b39
--- /dev/null
+++ b/src/modules/card/home/home.tsx
@@ -0,0 +1,27 @@
+import { shortcut } from '@core/decorator';
+import './home.less';
+
+/**
+ * 用于充当各一级菜单首页的测试组件
+ */
+@shortcut()
+export class Home extends BI.Widget {
+ static xtype = 'app.home';
+
+ public props: HomeProps = {
+ baseCls: 'app-home',
+ cardName: '',
+ };
+
+ public render() {
+ const { cardName } = this.options;
+ const labelText = `我是一级菜单 ${cardName} 的首页`;
+
+ return ;
+ }
+}
+
+interface HomeProps {
+ baseCls: string;
+ cardName: string;
+}
diff --git a/src/modules/card/todolist/header/header.less b/src/modules/card/todolist/header/header.less
new file mode 100644
index 0000000..dcb020d
--- /dev/null
+++ b/src/modules/card/todolist/header/header.less
@@ -0,0 +1,15 @@
+@import '~@/index.less';
+
+.app-todolist-header {
+ background-color: @color-bi-background-light-black;
+ .title {
+ font-size: @font-size-24;
+ color: @color-bi-text-white;
+ }
+ .editor {
+ background-color: @color-bi-background-default;
+ .border-radius(@radius-2);
+ }
+ .button {
+ }
+}
diff --git a/src/modules/card/todolist/header/header.tsx b/src/modules/card/todolist/header/header.tsx
new file mode 100644
index 0000000..d15c858
--- /dev/null
+++ b/src/modules/card/todolist/header/header.tsx
@@ -0,0 +1,76 @@
+import { TextEditor, Button } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import './header.less';
+
+/**
+ * ToDoList中的Header组件,包括标题,以及用于添加待办事项的编辑框和按钮
+ */
+@shortcut()
+export class TodolistHeader extends BI.Widget {
+ static xtype = 'app.todolist_header';
+
+ static EVENT = {
+ ADD: 'EVENT_ADD',
+ };
+
+ public props = {
+ baseCls: 'app-todolist-header',
+ };
+
+ private editorRef: TextEditor;
+ private buttonRef: Button;
+
+ public render() {
+ return (
+
+ ],
+ right: [
+ {
+ this.editorRef = ref;
+ }}
+ cls="editor"
+ width={256}
+ height={32}
+ allowBlank
+ watermark="请填写待办事项"
+ listeners={[
+ {
+ eventName: BI.Editor.EVENT_CHANGE,
+ action: () => {
+ const editorValue = this.editorRef.getValue();
+ const buttonEnabled = editorValue.length > 0;
+ this.buttonRef.setEnable(buttonEnabled);
+ },
+ },
+ ]}
+ />,
+ {
+ this.buttonRef = ref;
+ }}
+ cls="button"
+ height={32}
+ text="添加"
+ iconCls="plus-font"
+ disabled
+ handler={() => {
+ const editorValue = this.editorRef.getValue();
+ this.fireEvent(TodolistHeader.EVENT.ADD, editorValue);
+ this.editorRef.setValue('');
+ this.buttonRef.setEnable(false);
+ }}
+ />,
+ ],
+ }}
+ />
+
+ );
+ }
+}
diff --git a/src/modules/card/todolist/list/list.less b/src/modules/card/todolist/list/list.less
new file mode 100644
index 0000000..9650ec8
--- /dev/null
+++ b/src/modules/card/todolist/list/list.less
@@ -0,0 +1,30 @@
+@import '~@/index.less';
+
+.app-todolist-list {
+ .header {
+ .title {
+ font-size: @font-size-16;
+ font-weight: bold;
+ }
+ .count {
+ border-radius: 100%;
+ color: @font-color-white;
+ background-color: @color-bi-background-light-black;
+ }
+ }
+ .items {
+ .item {
+ .check {
+ }
+ .text {
+ }
+ .close {
+ &:hover,
+ &.hover {
+ font-weight: bold;
+ color: @color-bi-text-redmark;
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/card/todolist/list/list.tsx b/src/modules/card/todolist/list/list.tsx
new file mode 100644
index 0000000..576260b
--- /dev/null
+++ b/src/modules/card/todolist/list/list.tsx
@@ -0,0 +1,117 @@
+import { Widget, Label, VirtualGroup } from '@fui/core';
+import { shortcut } from '@core/decorator';
+import { TodolistItemInfo } from '../todolist';
+import './list.less';
+
+/**
+ * ToDoList中的List组件,表示待办事项清单
+ */
+@shortcut()
+export class TodolistList extends BI.Widget {
+ static xtype = 'app.todolist_list';
+
+ static EVENT = {
+ FINISH: 'EVENT_FINISH',
+ REMOVE: 'EVENT_REMOVE',
+ };
+
+ public props: TodolistListProps = {
+ baseCls: 'app-todolist-list',
+ title: '',
+ itemInfos: [],
+ };
+
+ private countRef: Label;
+ private itemsRef: VirtualGroup;
+
+ /**
+ * 根据itemInfos获取待办事项列表的items
+ * @returns 用于传给itemsRef的items
+ */
+ private getItems(): Widget[] {
+ const { itemInfos } = this.options;
+
+ return BI.map(itemInfos, (_index, itemInfo) => {
+ const { text, done } = itemInfo;
+
+ return (
+
+ {
+ this.fireEvent(TodolistList.EVENT.FINISH, itemInfo);
+ }}
+ />
+
+ {
+ this.fireEvent(TodolistList.EVENT.REMOVE, itemInfo);
+ }}
+ />
+
+ );
+ });
+ }
+
+ /**
+ * 设置itemInfos,并更新itemsRef
+ * @param itemInfos 待办事项信息集合
+ */
+ public setItemInfos(itemInfos: TodolistItemInfo[]) {
+ this.options.itemInfos = itemInfos;
+ const items = this.getItems();
+ this.itemsRef.populate(items);
+ this.countRef.setText(`${items.length}`);
+ }
+
+ public render() {
+ const { title } = this.options;
+ const items = this.getItems();
+ const count = `${items.length}`;
+
+ return (
+
+ ],
+ right: [
+ {
+ this.countRef = ref;
+ }}
+ cls="count"
+ width={24}
+ height={24}
+ text={count}
+ />,
+ ],
+ }}
+ />
+ {
+ this.itemsRef = ref;
+ }}
+ cls="items"
+ layouts={[]}
+ items={items}
+ />
+
+ );
+ }
+}
+
+interface TodolistListProps {
+ baseCls: string;
+ title: string;
+ itemInfos: TodolistItemInfo[];
+}
diff --git a/src/modules/card/todolist/todolist.less b/src/modules/card/todolist/todolist.less
new file mode 100644
index 0000000..d7912f1
--- /dev/null
+++ b/src/modules/card/todolist/todolist.less
@@ -0,0 +1,4 @@
+@import '~@/index.less';
+
+.app-todolist {
+}
diff --git a/src/modules/card/todolist/todolist.tsx b/src/modules/card/todolist/todolist.tsx
new file mode 100644
index 0000000..a6a8775
--- /dev/null
+++ b/src/modules/card/todolist/todolist.tsx
@@ -0,0 +1,174 @@
+import { shortcut } from '@core/decorator';
+import { TodolistHeader } from './header/header';
+import { TodolistList } from './list/list';
+import './todolist.less';
+
+// 待办事项信息
+export interface TodolistItemInfo {
+ id: string;
+ text: string;
+ done: boolean;
+}
+
+/**
+ * ToDoList组件,由header和list两个组件组成
+ */
+@shortcut()
+export class Todolist extends BI.Widget {
+ static xtype = 'app.todolist';
+
+ public props: TodolistProps = {
+ baseCls: 'app-todolist',
+ storageKey: 'app.todolist',
+ };
+
+ private undoneListRef: TodolistList;
+ private doneListRef: TodolistList;
+
+ /**
+ * 从window.localStorage中获取待办事项信息集合,并将其转换为对象格式
+ * @returns 对象格式的待办事项信息集合
+ */
+ private getItemInfos(): TodolistItemInfo[] {
+ const { storageKey } = this.options;
+ const itemsInfosStr = localStorage.getItem(storageKey) || JSON.stringify([]);
+
+ return JSON.parse(itemsInfosStr);
+ }
+
+ /**
+ * 更新localStorage中存储的待办事项信息集合,并更新undoneListRef和doneListRef
+ * @param itemInfos 待办事项信息集合
+ */
+ private setItemInfos(itemInfos: TodolistItemInfo[]) {
+ const { storageKey } = this.options;
+ const itemsInfosStr = JSON.stringify(itemInfos);
+ localStorage.setItem(storageKey, itemsInfosStr);
+ this.updateListRefs();
+ }
+
+ /**
+ * 添加待办事项
+ * @param itemInfo 要添加的待办事项信息
+ */
+ private addItemInfo(itemInfo: TodolistItemInfo) {
+ const itemInfos = this.getItemInfos();
+ itemInfos.push(itemInfo);
+ this.setItemInfos(itemInfos);
+ }
+
+ /**
+ * 完成待办事项
+ * @param itemInfo 要完成的待办事项信息
+ */
+ private finishItemInfo(itemInfo: TodolistItemInfo) {
+ const itemInfos = this.getItemInfos();
+ (BI.find(itemInfos, { id: itemInfo.id }) as TodolistItemInfo).done = true;
+ this.setItemInfos(itemInfos);
+ }
+
+ /**
+ * 删除待办事项
+ * @param itemInfo 要删除的待办事项信息
+ */
+ private removeItemInfo(itemInfo: TodolistItemInfo) {
+ const itemInfos = this.getItemInfos();
+ BI.remove(itemInfos, (_index: number, curItemInfo: TodolistItemInfo) => curItemInfo.id === itemInfo.id);
+ this.setItemInfos(itemInfos);
+ }
+
+ /**
+ * 获取未完成的待办事项信息集合
+ * @returns 未完成的待办事项信息集合
+ */
+ private getUndoneItemInfos(): TodolistItemInfo[] {
+ const itemInfos = this.getItemInfos();
+
+ return BI.filter(itemInfos, (_index, itemInfo) => itemInfo.done === false);
+ }
+
+ /**
+ * 获取已完成的待办事项信息集合
+ * @returns 已完成的待办事项信息集合
+ */
+ private getDoneItemInfos(): TodolistItemInfo[] {
+ const itemInfos = this.getItemInfos();
+
+ return BI.filter(itemInfos, (_index, itemInfo) => itemInfo.done === true);
+ }
+
+ /**
+ * 更新undoneListRef和doneListRef
+ */
+ private updateListRefs() {
+ const undoneItemInfos = this.getUndoneItemInfos();
+ const doneItemInfos = this.getDoneItemInfos();
+ this.undoneListRef.setItemInfos(undoneItemInfos);
+ this.doneListRef.setItemInfos(doneItemInfos);
+ }
+
+ public render() {
+ const undoneItemInfos = this.getUndoneItemInfos();
+ const doneItemInfos = this.getDoneItemInfos();
+
+ return (
+
+ {
+ this.addItemInfo({
+ id: BI.UUID(),
+ text,
+ done: false,
+ });
+ },
+ },
+ ]}
+ />
+ {
+ this.undoneListRef = ref;
+ }}
+ title="待办"
+ itemInfos={undoneItemInfos}
+ listeners={[
+ {
+ eventName: TodolistList.EVENT.FINISH,
+ action: itemInfo => {
+ this.finishItemInfo(itemInfo);
+ },
+ },
+ {
+ eventName: TodolistList.EVENT.REMOVE,
+ action: itemInfo => {
+ this.removeItemInfo(itemInfo);
+ },
+ },
+ ]}
+ />
+ {
+ this.doneListRef = ref;
+ }}
+ title="已办"
+ itemInfos={doneItemInfos}
+ listeners={[
+ {
+ eventName: TodolistList.EVENT.REMOVE,
+ action: itemInfo => {
+ this.removeItemInfo(itemInfo);
+ },
+ },
+ ]}
+ />
+
+ );
+ }
+}
+
+interface TodolistProps {
+ baseCls: string;
+ storageKey: string;
+}
diff --git a/src/modules/core/decorator.ts b/src/modules/core/decorator.ts
new file mode 100644
index 0000000..aaf0b8c
--- /dev/null
+++ b/src/modules/core/decorator.ts
@@ -0,0 +1,3 @@
+export const { shortcut, model, store, Model } = BI.Decorators;
+
+export type Constructor = new (...args: any[]) => T;
diff --git a/src/modules/header/header.js b/src/modules/header/header.js
deleted file mode 100644
index 6f490ff..0000000
--- a/src/modules/header/header.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { shortcut } from "../../core/javascript/decorator";
-import "./header.less";
-
-/**
- * 顶部组件,提供输入框添加todo项目
- * 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中
- */
-@shortcut()
-export class ToDoListHeader extends BI.Widget {
- static xtype = "my.todolist.header";
-
- static EVENT_ADD = "EVENT_ADD";
-
- props = {
- // 指定组件的className
- baseCls: "my-todolist-header",
- }
-
- render() {
- const { height } = this.options;
-
- return {
- // 水平居中布局
- type: BI.HorizontalAutoLayout.xtype,
- items: [{
- el: {
- // 左右垂直居中布局
- type: BI.LeftRightVerticalAdaptLayout.xtype,
- width: 600,
- height: 40,
- items: {
- left: [
- {
- el: {
- type: BI.Label.xtype,
- cls: "my-todolist-title",
- text: "FineUI ToDoList",
- height,
- },
- },
- ],
- right: [
- {
- el: {
- type: BI.Editor.xtype,
- ref: _ref => {
- this.editor = _ref;
- },
- allowBlank: true,
- cls: "my-todolist-header-editor",
- watermark: "添加ToDo",
- width: 300,
- height: 24,
- listeners: [
- { // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置
- eventName: "EVENT_ENTER",
- action: () => {
- this.fireEvent(ToDoListHeader.EVENT_ADD, this.editor.getValue());
- this.editor.setValue("");
- },
- },
- ],
- },
- },
- ],
- },
- },
- }],
- };
- }
-}
diff --git a/src/modules/header/header.less b/src/modules/header/header.less
deleted file mode 100644
index 32fcaac..0000000
--- a/src/modules/header/header.less
+++ /dev/null
@@ -1,18 +0,0 @@
-@import "../../index.less";
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
- */
-.my-todolist-header {
- background-color: #3d4d66;
-
- .my-todolist-title {
- font-size: @font-size-22;
- color: #FFF;
- }
-
- .my-todolist-header-editor {
- background-color: #FFF;
- .border-radius(5px);
- .box-shadow(0 1px 0 rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset)
- }
-}
\ No newline at end of file
diff --git a/src/modules/list/list.less b/src/modules/list/list.less
deleted file mode 100644
index 7b1d751..0000000
--- a/src/modules/list/list.less
+++ /dev/null
@@ -1,16 +0,0 @@
-@import "../../index.less";
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius方法等.请选择性使用.不强制要求
- */
-.my-todolist-list {
- .my-todolist-list-text {
- font-size: @font-size-16;
- font-weight: bold;
- }
-
- .my-todolist-list-count-container {
- .border-radius(10px);
- background-color: #3d4d66;
- color: @font-color-white;
- }
-}
\ No newline at end of file
diff --git a/src/modules/list/list.ts b/src/modules/list/list.ts
deleted file mode 100644
index 7a9b1f2..0000000
--- a/src/modules/list/list.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { Label, VerticalLayout } from 'fineui';
-import { shortcut } from "../../core/typescript/decorator";
-import "./list.less";
-
-/**
- * todo项列表
- */
-@shortcut()
-export class List extends BI.Widget {
- public static xtype = "my.todolist.list";
-
- private count: Label;
- private list: VerticalLayout;
-
- public props = {
- // 指定组件的className
- baseCls: "my-todolist-list",
- text: "正在进行",
- items: [],
- }
-
- public render() {
- const { text, items } = this.options;
-
- return {
- type: BI.VerticalLayout.xtype,
- items: [
- {
- el: {
- type: BI.VerticalAdaptLayout.xtype,
- height: 40,
- items: [
- {
- type: BI.Label.xtype,
- cls: "my-todolist-list-text",
- textAlign: "left",
- text,
- width: 580,
- }, {
- type: BI.CenterAdaptLayout.xtype,
- cls: "my-todolist-list-count-container",
- width: 20,
- height: 20,
- items: [
- {
- el: {
- type: BI.Label.xtype,
- ref: (_ref: Label) => {
- this.count = _ref;
- },
- text: 0,
- },
- },
- ],
- },
- ],
- },
- }, {
- // 用bi.vertical布局作为列表项的容器.
- type: BI.VerticalLayout.xtype,
- vgap: 10,
- ref: (_ref: VerticalLayout) => {
- this.list = _ref;
- },
- items: this.createItems(items),
- },
- ],
- };
- }
-
- private createItems(items: Item[]) {
- return items.map(item => {
- return BI.extend(item, {
- type: BI.MultiSelectItem.xtype, // 节点采用复选节点展示
- selected: item.done, // 已完成的todo项置为选中状态
- disabled: item.done, // 已完成的todo项置为灰化状态
- listeners: [
- { // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事
- eventName: "EVENT_CHANGE",
- action: (v: any) => {
- this.fireEvent("EVENT_CHANGE", v);
- },
- },
- ],
- });
- })
- }
-
- private setCount(count: number) {
- this.count.setText(`${count}`);
- }
-
- public populate(items: []) {
- this.list.populate(this.createItems(items));
- this.setCount(items.length);
- }
-}
-
-interface Item {
- done: boolean,
-}
diff --git a/src/modules/main.js b/src/modules/main.js
deleted file mode 100644
index e624d9a..0000000
--- a/src/modules/main.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { shortcut } from "../core/javascript/decorator";
-import { ToDoListHeader } from "./header/header";
-import { List } from "./list/list";
-import "./main.less";
-
-/**
- * todolist 组件
- */
-@shortcut()
-export class ToDoList extends BI.Widget {
- static xtype = "my.todolist";
-
- props = {
- baseCls: "fine-to-do-list",
- }
-
- // 生命周期函数,在组件创建前
- beforeCreate() {
- // 初始化存储数据
- this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : [];
- }
-
- render() {
- return {
- type: BI.VTapeLayout.xtype, // vtape布局,顶部高度固定,下部分列表占满高度
- items: [
- {
- el: {
- type: ToDoListHeader.xtype, // 顶部组件
- listeners: [
- { // 监听组件的EVENT_ADD事件,新建todo项
- eventName: "EVENT_ADD",
- action: v => {
- this.addToDo(v);
- },
- },
- ],
- height: 40,
- },
- height: 40,
- }, {
- type: BI.HorizontalAutoLayout.xtype, // 水平居中布局
- cls: "my-todolist-background", // 添加className
- items: [
- {
- el: {
- type: List.xtype, // need todo项列表
- ref: _ref => {
- this.todolist = _ref;
- },
- items: this._getNeedTodoList(),
- text: "正在进行",
- listeners: [
- { // 监听EVENT_CHANGE事件,完成某一项todo
- eventName: "EVENT_CHANGE",
- action: v => {
- this.finishTodo(v);
- },
- },
- ],
- width: 600,
- },
- }, {
- el: {
- type: List.xtype, // 已经完成的todo项列表
- text: "已经完成",
- items: this._getAlreadyDoneList(),
- ref: _ref => {
- this.donelist = _ref;
- },
- width: 600,
- },
- },
- ],
- }],
- };
- }
-
- _updateLocalStorage() {
- localStorage.setItem("fine-todolist", JSON.stringify(this.list));
- }
-
- _getNeedTodoList() {
- return BI.filter(this.list, (index, item) => !item.done);
- }
-
- _getAlreadyDoneList() {
- return BI.filter(this.list, (index, item) => item.done);
- }
-
- /**
- * 添加todo项
- * @param text todo项的内容
- */
- addToDo(text) {
- this.list.push({
- value: BI.UUID(),
- text,
- done: false,
- });
- this.todolist.populate(this._getNeedTodoList());
- this._updateLocalStorage();
- }
-
- /**
- * 完成某一项todo
- * @param v todo项的value
- */
- finishTodo(v) {
- BI.some(this.list, (index, item) => {
- if (item.value === v) {
- item.done = true;
- }
- });
- this.todolist.populate(this._getNeedTodoList());
- this.donelist.populate(this._getAlreadyDoneList());
- this._updateLocalStorage();
- }
-}
diff --git a/src/modules/main.less b/src/modules/main.less
deleted file mode 100644
index 14cef72..0000000
--- a/src/modules/main.less
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
- */
-.my-todolist-background {
- background-color: #f7f8fa;
-}
\ No newline at end of file
diff --git a/src/routes.ts b/src/routes.ts
new file mode 100644
index 0000000..e8c237d
--- /dev/null
+++ b/src/routes.ts
@@ -0,0 +1,186 @@
+import { Widget } from '@fui/core';
+import { Home } from '@card/home/home';
+import { Demo } from '@card/demo/demo';
+import { Todolist } from '@card/todolist/todolist';
+
+// 路由类型
+export enum RouteType {
+ Single,
+ Multiple,
+}
+
+// 路由信息
+export interface RouteInfo {
+ type?: RouteType;
+ value: string;
+ text: string;
+ icon: string;
+ card?: typeof Widget;
+ cards?: RouteInfo[];
+ children?: RouteInfo[];
+}
+
+/*
+ * 路由映射信息,配置说明:
+ * 1.顶层路由将作为一级菜单,第二层及更深层路由将作为二级菜单
+ * 2.为顶层路由配置type属性
+ * 2.1 RouteType.Single: 每个二级菜单选项对应一个card,导航标签可关闭,其形式类似BI的目录页面
+ * 2.2 RouteType.Multiple: 每个二级菜单选项对应多个card,导航标签不可关闭,其形式类似BI的管理系统页面
+ * 3.路由公共配置如下:
+ * 3.1 value: 路由的唯一索引
+ * 3.2 text: 路由对应的菜单项名称和导航标签名称
+ * 3.3 icon: 路由对应的菜单项图标
+ * 3.4 children: 路由的子路由
+ * 3.5 card|cards:
+ * 3.5.1 card: 顶层路由的type为RouteType.Single时可用,表示该路由对应的单个card
+ * 3.5.2 cards: 顶层路由的type为RouteType.Multiple时可用,表示该路由对应的多个card
+ * 3.5.3 顶层路由的card表示一级菜单对应的默认card
+ */
+export const ROUTE_INFOS: RouteInfo[] = [
+ {
+ type: RouteType.Single,
+ value: 'directory',
+ text: '模板目录',
+ icon: 'directory-font',
+ card: Home,
+ children: [
+ {
+ value: 'todolist',
+ text: 'Todolist',
+ icon: 'date-font',
+ card: Todolist,
+ },
+ {
+ value: 'menu-level-1',
+ text: '一级菜单',
+ icon: 'text-align-center-font',
+ children: [
+ {
+ value: 'menu-level-1-todolist',
+ text: '一级 Todolist',
+ icon: 'date-font',
+ card: Todolist,
+ },
+ {
+ value: 'menu-level-2',
+ text: '二级菜单',
+ icon: 'text-align-center-font',
+ children: createDemoRouteInfos(4, '二级'),
+ },
+ {
+ value: 'menu-level-2-another',
+ text: '另一个二级菜单',
+ icon: 'text-align-center-font',
+ children: createDemoRouteInfos(4, '另一个二级'),
+ },
+ ...createDemoRouteInfos(4, '一级'),
+ ],
+ },
+ ...createDemoRouteInfos(8),
+ ],
+ },
+ {
+ type: RouteType.Multiple,
+ value: 'management',
+ text: '系统管理',
+ icon: 'management-font',
+ card: Home,
+ children: [
+ {
+ value: 'series-1',
+ text: '系列一',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(4, '系列一的'),
+ },
+ {
+ value: 'series-2',
+ text: '系列二',
+ icon: 'copy-font',
+ cards: [...createDemoRouteInfos(4, '系列二的'), ...createDemoRouteInfos(4, '另一个')],
+ },
+ {
+ value: 'series-level-1',
+ text: '一级菜单',
+ icon: 'text-align-center-font',
+ children: [
+ {
+ value: 'series-level-1-1',
+ text: '一级系列一',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(8, '一级系列一的'),
+ },
+ {
+ value: 'series-level-1-2',
+ text: '一级系列二',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(8, '一级系列二的'),
+ },
+ {
+ value: 'series-level-2',
+ text: '二级菜单',
+ icon: 'text-align-center-font',
+ children: [
+ {
+ value: 'series-level-2-1',
+ text: '二级系列一',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(5, '二级系列一的'),
+ },
+ {
+ value: 'series-level-2-2',
+ text: '二级系列二',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(6, '二级系列二的'),
+ },
+ {
+ value: 'series-level-2-3',
+ text: '二级系列三',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(7, '二级系列三的'),
+ },
+ {
+ value: 'series-level-2-4',
+ text: '二级系列四',
+ icon: 'copy-font',
+ cards: createDemoRouteInfos(8, '二级系列四的'),
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+];
+
+// ================ 以下为测试用的工具函数 ================
+
+/**
+ * 生成用于测试的路由信息集合
+ * @param number 要生成路由信息的数量
+ * @param textPrefix 要生成路由信息的名称前缀
+ * @returns 所生成的路由信息集合
+ */
+function createDemoRouteInfos(number: number, textPrefix = ''): RouteInfo[] {
+ const iconList = [
+ 'search-font',
+ 'date-font',
+ 'time-font',
+ 'date-change-h-font',
+ 'copy-font',
+ 'primary-key-font',
+ 'text-bold-font',
+ 'text-italic-font',
+ 'text-underline-font',
+ 'text-color-font',
+ 'text-background-font',
+ ];
+
+ return BI.map(BI.range(0, number, 1), index => {
+ return {
+ value: BI.UUID(),
+ text: `${textPrefix} Demo ${index + 1}`,
+ icon: iconList[index % iconList.length],
+ card: Demo,
+ };
+ });
+}
diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts
deleted file mode 100644
index 6a28a08..0000000
--- a/src/types/globals.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-interface Obj {
- [key: string]: any;
-}
-
-declare let BI: Obj & import('fineui').BI;
-declare const Fix: Obj;
-
-declare interface String {
- replaceAll(regx: string | RegExp, callback: (str: string) => void): string;
-}
diff --git a/template/favicon.ico b/template/favicon.ico
new file mode 100644
index 0000000..8b87a0f
Binary files /dev/null and b/template/favicon.ico differ
diff --git a/template/index.html b/template/index.html
new file mode 100644
index 0000000..8af506a
--- /dev/null
+++ b/template/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ FineUI Starter
+
+
+
+
+
+
+
+
diff --git a/test/sum.test.ts b/test/sum.test.ts
new file mode 100644
index 0000000..854e5ff
--- /dev/null
+++ b/test/sum.test.ts
@@ -0,0 +1,5 @@
+import { sum } from './sum';
+
+test('adds 1 + 2 to equal 3', () => {
+ expect(sum(1, 2)).toBe(3);
+});
diff --git a/test/sum.ts b/test/sum.ts
new file mode 100644
index 0000000..a8c4991
--- /dev/null
+++ b/test/sum.ts
@@ -0,0 +1,3 @@
+export function sum(a: number, b: number): number {
+ return a + b;
+}
diff --git a/tsconfig.json b/tsconfig.json
index 9459ffe..c480d0d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,22 @@
{
"extends": "@fui/typescript-configs/application.json",
+ "include": ["src/*.ts", "src/*.tsx", "src/**/*.ts", "src/**/*.tsx", "test", "typings"],
"compilerOptions": {
+ /* 基本选项 */
+ "jsx": "react",
+ /* 严格的类型检查选项 */
"strict": false,
- "allowJs": true,
- },
+ /* 模块解析选项 */
+ "baseUrl": "./",
+ "rootDir": ".",
+ "paths": {
+ "@/*": ["src/*"],
+ "@app/*": ["src/modules/app/*"],
+ "@base/*": ["src/modules/base/*"],
+ "@card/*": ["src/modules/card/*"],
+ "@core/*": ["src/modules/core/*"],
+ "@service/*": ["src/modules/service/*"],
+ "@types/*": ["src/modules/types/*"]
+ }
+ }
}
diff --git a/typings/globals.d.ts b/typings/globals.d.ts
new file mode 100644
index 0000000..eea1690
--- /dev/null
+++ b/typings/globals.d.ts
@@ -0,0 +1,14 @@
+// eslint-disable-next-line spaced-comment
+///
+
+interface Obj {
+ [key: string]: any;
+}
+
+declare let BI: Obj & import('@fui/core').BI;
+declare const Fix: Obj;
+declare const $: ((el: any) => any) & Obj;
+
+declare interface String {
+ replaceAll(regx: string | RegExp, callback: (str: string) => void): string;
+}
diff --git a/webpack/dirs.js b/webpack/dirs.js
index 09fc4e7..36f3d53 100644
--- a/webpack/dirs.js
+++ b/webpack/dirs.js
@@ -1,9 +1,18 @@
-const path = require("path");
+const { pathResolve, pathJoin } = require('./utils');
+
module.exports = {
- DEST: path.resolve(__dirname, "../dist"),
- NODE_MODULES: path.resolve(__dirname, "../node_modules"),
- PRIVATE: path.resolve(__dirname, "../private"),
- BABEL_CONFIG: path.resolve(__dirname, "../babel.config.js"),
- IE8_BABEL_CONFIG: path.resolve(__dirname, "../babel.config.ie8.js"),
- SRC: path.resolve(__dirname, "../src"),
+ NODE_MODULES: pathResolve('../node_modules'),
+ DEST: pathResolve('../dist'),
+ SRC: pathResolve('../src'),
+ SRC_MODULES_APP: pathResolve('../src/modules/app'),
+ SRC_MODULES_BASE: pathResolve('../src/modules/base'),
+ SRC_MODULES_CARD: pathResolve('../src/modules/card'),
+ SRC_MODULES_CORE: pathResolve('../src/modules/core'),
+ SRC_MODULES_SERVICE: pathResolve('../src/modules/service'),
+ SRC_MODULES_TYPES: pathResolve('../src/modules/types'),
+ SRC_CORE: pathResolve('../src/core'),
+ PRIVATE: pathResolve('../private'),
+ INDEX: pathResolve('../template/index.html'),
+ BABEL_CONFIG: pathResolve('../babel.config.js'),
+ CONTENT_BASE: pathJoin('..'),
};
diff --git a/webpack/utils.js b/webpack/utils.js
new file mode 100644
index 0000000..3739bb3
--- /dev/null
+++ b/webpack/utils.js
@@ -0,0 +1,6 @@
+const path = require('path');
+
+module.exports = {
+ pathResolve: dirpath => path.resolve(__dirname, dirpath),
+ pathJoin: dirpath => path.join(__dirname, dirpath),
+};
diff --git a/webpack/webpack.common.js b/webpack/webpack.common.js
index fa765f5..9cf3484 100644
--- a/webpack/webpack.common.js
+++ b/webpack/webpack.common.js
@@ -1,17 +1,24 @@
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const autoprefixer = require("autoprefixer");
-
-const dirs = require("./dirs");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const AutoPrefixer = require('autoprefixer');
+const dirs = require('./dirs');
module.exports = {
entry: {
- bundle: [
- "./src/index.js",
- ],
+ bundle: ['./src/index.ts'],
},
resolve: {
- mainFields: ["module", "main"],
- extensions: [".js", ".ts"],
+ mainFields: ['module', 'main'],
+ mainFiles: ['index'],
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ alias: {
+ '@': dirs.SRC,
+ '@app': dirs.SRC_MODULES_APP,
+ '@base': dirs.SRC_MODULES_BASE,
+ '@card': dirs.SRC_MODULES_CARD,
+ '@core': dirs.SRC_MODULES_CORE,
+ '@service': dirs.SRC_MODULES_SERVICE,
+ '@types': dirs.SRC_MODULES_TYPES,
+ },
},
stats: {
children: false,
@@ -20,38 +27,41 @@ module.exports = {
module: {
rules: [
{
- test: /\.(js|ts)$/,
+ test: /\.(jsx?|tsx?)$/,
include: [dirs.NODE_MODULES, dirs.SRC],
- use: [{
- loader: "babel-loader",
- options: {
- configFile: dirs.BABEL_CONFIG,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ configFile: dirs.BABEL_CONFIG,
+ },
},
- }, {
- loader: "source-map-loader",
- options: {
- enforce: "pre",
+ {
+ loader: 'source-map-loader',
+ options: {
+ enforce: 'pre',
+ },
},
- }],
+ ],
},
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
{
- loader: "css-loader",
+ loader: 'css-loader',
options: {
url: false,
},
},
{
- loader: "postcss-loader",
+ loader: 'postcss-loader',
options: {
- plugins: [autoprefixer],
+ plugins: [AutoPrefixer],
},
},
{
- loader: "less-loader",
+ loader: 'less-loader',
options: {
relativeUrls: false,
},
diff --git a/webpack/webpack.dev.js b/webpack/webpack.dev.js
index 190be31..bff83a8 100644
--- a/webpack/webpack.dev.js
+++ b/webpack/webpack.dev.js
@@ -1,51 +1,49 @@
-const merge = require("webpack-merge");
-const path = require("path");
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const HtmlWebpackPlugin = require("html-webpack-plugin");
-const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
-const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
-
-const dirs = require("./dirs");
-
-const common = require("./webpack.common.js");
+const merge = require('webpack-merge');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
+const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
+const dirs = require('./dirs');
+const common = require('./webpack.common.js');
module.exports = merge(common, {
- devtool: "eval-source-map",
- entry: {
- },
+ devtool: 'eval-source-map',
+ entry: {},
output: {
path: dirs.DEST,
- filename: "[name].[contenthash].js",
+ filename: '[name].[contenthash].js',
},
devServer: {
open: true,
- contentBase: path.join(__dirname, ".."),
- port: 9002,
+ contentBase: dirs.CONTENT_BASE,
+ port: 8080,
liveReload: true,
},
plugins: [
- new ForkTsCheckerWebpackPlugin({
- }),
+ new ForkTsCheckerWebpackPlugin({}),
new MiniCssExtractPlugin({
path: dirs.DEST,
- filename: "[contenthash].css",
+ filename: '[contenthash].css',
}),
new HtmlWebpackPlugin({
- template: path.resolve(__dirname, "../index.html"),
- chunks: ["bundle"],
- chunksSortMode: "manual",
- nodeModules: path.resolve(__dirname, "../node_modules"),
+ template: dirs.INDEX,
+ chunks: ['bundle'],
+ chunksSortMode: 'manual',
+ nodeModules: dirs.NODE_MODULES,
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
- cssProcessor: require("cssnano"),
+ cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
- preset: ["default", {
- discardComments: {
- removeAll: true,
+ preset: [
+ 'default',
+ {
+ discardComments: {
+ removeAll: true,
+ },
+ normalizeUnicode: false,
},
- normalizeUnicode: false,
- }],
+ ],
},
canPrint: true,
}),
diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js
index 29b363d..7dde1de 100644
--- a/webpack/webpack.prod.js
+++ b/webpack/webpack.prod.js
@@ -1,16 +1,14 @@
-const webpack = require("webpack");
-const merge = require("webpack-merge");
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
-const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
-const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
-
-const dirs = require("./dirs");
-
-const common = require("./webpack.common.js");
+const webpack = require('webpack');
+const merge = require('webpack-merge');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
+const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
+const dirs = require('./dirs');
+const common = require('./webpack.common.js');
module.exports = merge.smart(common, {
- mode: "production",
+ mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
@@ -25,34 +23,33 @@ module.exports = merge.smart(common, {
}),
],
},
-
- devtool: "hidden-source-map",
-
+ devtool: 'hidden-source-map',
output: {
path: dirs.DEST,
- filename: "bundle.js",
+ filename: 'bundle.js',
},
-
plugins: [
- new ForkTsCheckerWebpackPlugin({
- }),
+ new ForkTsCheckerWebpackPlugin({}),
new MiniCssExtractPlugin({
path: dirs.DEST,
- filename: "bundle.css",
+ filename: 'bundle.css',
}),
new webpack.BannerPlugin({
banner: `time: ${new Date().toLocaleString()}`,
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
- cssProcessor: require("cssnano"),
+ cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
- preset: ["default", {
- discardComments: {
- removeAll: true,
+ preset: [
+ 'default',
+ {
+ discardComments: {
+ removeAll: true,
+ },
+ normalizeUnicode: false,
},
- normalizeUnicode: false,
- }],
+ ],
},
canPrint: true,
}),