feat: init project US2022111700422
Signed-off-by: <zenglingka@> Match-id-9ac6cf2948c4663b3ce91406b4ddbc6045cbd57e
|
@ -0,0 +1,23 @@
|
|||
version: 0.1.0
|
||||
name: tiny-opentiny-vue
|
||||
language: nodejs
|
||||
|
||||
# 构建工具
|
||||
dependencies:
|
||||
base:
|
||||
nodejs: best
|
||||
|
||||
# 构建机器
|
||||
machine:
|
||||
standard:
|
||||
euler:
|
||||
- default
|
||||
|
||||
# 构建脚本
|
||||
scripts:
|
||||
- sh build.sh
|
||||
|
||||
# 构建产物
|
||||
artifacts:
|
||||
npm_deploy:
|
||||
- config_path: ./dist/vue/package.json
|
|
@ -0,0 +1,9 @@
|
|||
version: 2.0
|
||||
|
||||
steps:
|
||||
pre_codecheck:
|
||||
- checkout
|
||||
|
||||
tool_params:
|
||||
secsolar:
|
||||
source_dir: ./
|
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
runtime
|
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"jest": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:vue/vue3-essential"],
|
||||
"parserOptions": {
|
||||
"parser": ["vue-eslint-parser", "@babel/eslint-parser"],
|
||||
"requireConfigFile": false,
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": "latest",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"no-debugger": "off",
|
||||
"no-var": "error",
|
||||
"no-tabs": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-undef": "error",
|
||||
"no-extra-semi": "error",
|
||||
"no-empty": "error",
|
||||
"no-console": "off",
|
||||
"semi": [2, "never"],
|
||||
"max-len": [
|
||||
"warn",
|
||||
{
|
||||
"code": 160
|
||||
}
|
||||
],
|
||||
"function-paren-newline": ["off"],
|
||||
"object-property-newline": [
|
||||
"warn",
|
||||
{
|
||||
"allowAllPropertiesOnSameLine": true
|
||||
}
|
||||
],
|
||||
"newline-per-chained-call": [
|
||||
"warn",
|
||||
{
|
||||
"ignoreChainWithDepth": 4
|
||||
}
|
||||
],
|
||||
"comma-dangle": "off",
|
||||
"semi-style": ["warn", "last"],
|
||||
"max-lines": ["error", 2400],
|
||||
"max-lines-per-function": ["error", 200],
|
||||
"complexity": ["error", 26],
|
||||
"max-depth": ["warn", 4],
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
"no-multi-assign": "off",
|
||||
"no-undef-init": "warn",
|
||||
"no-shadow": "off",
|
||||
"max-params": ["warn", 5],
|
||||
"no-param-reassign": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"prefer-arrow-callback": "error",
|
||||
"arrow-body-style": ["warn", "as-needed"],
|
||||
"no-this-before-super": "error",
|
||||
"quotes": ["warn", "single"],
|
||||
"prefer-template": "off",
|
||||
"no-multi-str": "warn",
|
||||
"object-shorthand": "warn",
|
||||
"dot-notation": "error",
|
||||
"accessor-pairs": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"guard-for-in": "error",
|
||||
"eqeqeq": "off",
|
||||
"no-fallthrough": "error",
|
||||
"no-case-declarations": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-eval": "error",
|
||||
"no-with": "error",
|
||||
"no-implicit-coercion": [
|
||||
"error",
|
||||
{
|
||||
"allow": ["!!", "~"]
|
||||
}
|
||||
],
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/valid-v-slot": "off",
|
||||
"vue/no-deprecated-v-on-native-modifier": "off",
|
||||
"vue/no-reserved-component-names": "off",
|
||||
"vue/no-deprecated-dollar-listeners-api": "off",
|
||||
"vue/no-deprecated-slot-attribute": "off",
|
||||
"vue/no-use-computed-property-like-method": "off",
|
||||
"vue/no-mutating-props": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
name: '🐛 Bug report'
|
||||
description: Create a report to help us improve Tiny Vue
|
||||
title: '🐛 [Bug]: '
|
||||
labels: ['🐛 bug']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please fill out the following carefully in order to better fix the problem.
|
||||
- type: input
|
||||
id: tiny-vue-version
|
||||
attributes:
|
||||
label: Version
|
||||
description: |
|
||||
### **Check if the issue is reproducible with the latest stable version.**
|
||||
You can use the command `npm ls @opentiny/vue` to view it
|
||||
placeholder: latest
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: vue-version
|
||||
attributes:
|
||||
label: Vue Version
|
||||
placeholder: latest
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: minimal-repo
|
||||
attributes:
|
||||
label: Link to minimal reproduction
|
||||
description: |
|
||||
**Provide a streamlined CodePen / CodeSandbox or GitHub repository link as much as possible. Please don't fill in a link randomly, it will only close your issue directly.**
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Step to reproduce
|
||||
description: |
|
||||
**After the replay is turned on, what actions do we need to perform to make the bug appear? Simple and clear steps can help us locate the problem more quickly. Please clearly describe the steps of reproducing the issue. Issues without clear reproducing steps will not be repaired. If the issue marked with 'need reproduction' does not provide relevant steps within 7 days, it will be closed directly.**
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What is expected
|
||||
placeholder: Please Input
|
||||
- type: textarea
|
||||
id: actually
|
||||
attributes:
|
||||
label: What is actually happening
|
||||
placeholder: Please Input
|
||||
- type: textarea
|
||||
id: additional-comments
|
||||
attributes:
|
||||
label: Any additional comments (optional)
|
||||
description: |
|
||||
**Some background / context of how you ran into this bug.**
|
||||
placeholder: Please Input
|
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Questions or need help
|
||||
url: https://github.com/opentiny/ui-vue/discussions
|
||||
about: Add this WeChat(opentiny), we will invite you to the WeChat discussion group later.
|
|
@ -0,0 +1,23 @@
|
|||
name: ✨ Feature Request
|
||||
description: Propose new features to @opentiny/vue to improve it.
|
||||
title: '✨ [Feature]: '
|
||||
labels: ['✨ feature']
|
||||
body:
|
||||
- type: textarea
|
||||
id: feature-solve
|
||||
attributes:
|
||||
label: What problem does this feature solve
|
||||
description: |
|
||||
Explain your use case, context, and rationale behind this feature request. More importantly, what is the end user experience you are trying to build that led to the need for this feature?
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature-api
|
||||
attributes:
|
||||
label: What does the proposed API look like
|
||||
description: |
|
||||
Describe how you propose to solve the problem and provide code samples of how the API would work once implemented. Note that you can use Markdown to format your code blocks.
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
|
@ -0,0 +1,41 @@
|
|||
# PR
|
||||
|
||||
## PR Checklist
|
||||
|
||||
Please check if your PR fulfills the following requirements:
|
||||
|
||||
- [ ] The commit message follows our [Commit Message Guidelines](https://github.com/opentiny/ui-vue/blob/main/CONTRIBUTING.md)
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
|
||||
## PR Type
|
||||
|
||||
What kind of change does this PR introduce?
|
||||
|
||||
<!-- Please check the one that applies to this PR using "x". -->
|
||||
|
||||
- [ ] Bugfix
|
||||
- [ ] Feature
|
||||
- [ ] Code style update (formatting, local variables)
|
||||
- [ ] Refactoring (no functional changes, no api changes)
|
||||
- [ ] Build related changes
|
||||
- [ ] CI related changes
|
||||
- [ ] Documentation content changes
|
||||
- [ ] Other... Please describe:
|
||||
|
||||
## What is the current behavior?
|
||||
|
||||
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
|
||||
|
||||
Issue Number: N/A
|
||||
|
||||
## What is the new behavior?
|
||||
|
||||
## Does this PR introduce a breaking change?
|
||||
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
|
||||
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
|
||||
|
||||
## Other information
|
|
@ -0,0 +1,41 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
dist/
|
||||
allDist/
|
||||
packages/**/runtime/
|
||||
coverage/
|
||||
|
||||
/packages/base.js
|
||||
/packages/chart.js
|
||||
/packages/core.js
|
||||
/packages/index.js
|
||||
/packages/pc.js
|
||||
/packages/mobile.js
|
||||
|
||||
# local env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.history
|
||||
.vscode
|
||||
.cloudbuild
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.log
|
||||
*.stackdump
|
||||
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
||||
tgzs
|
||||
*.tgz
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn commitlint --edit $1
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
|
@ -0,0 +1,3 @@
|
|||
# Except myapp folder:
|
||||
dist/
|
||||
public/
|
|
@ -0,0 +1,4 @@
|
|||
semi: false
|
||||
singleQuote: true
|
||||
printWidth: 160
|
||||
trailingComma: none
|
|
@ -0,0 +1,20 @@
|
|||
# 更新日志
|
||||
|
||||
## v2.0.0/v3.0.0
|
||||
|
||||
`2022/09/15`
|
||||
|
||||
### 📢破坏性变更
|
||||
|
||||
无
|
||||
|
||||
### ✨新特性
|
||||
|
||||
- Search 组件:增加 input 事件
|
||||
- Select 组件:增加 scroll 事件
|
||||
|
||||
### 🐞缺陷修复
|
||||
|
||||
- Tabs 组件:修复 tab 组件套 tab 组件,内部的 tab 项会显示在外部 tab 上的bug
|
||||
- PopEditor 组件:解决弹出框里的查询条件不能输入的问题
|
||||
- Cascader 组件:解决点击已选中选项无法关闭选择器的问题
|
|
@ -0,0 +1,81 @@
|
|||
# 贡献指南
|
||||
|
||||
很高兴你有意愿参与 TinyVue 开源项目的贡献,参与贡献的形式有很多种,你可以根据自己的特长和兴趣选择其中的一个或多个:
|
||||
|
||||
- 报告[新缺陷](https://github.com/opentiny/tiny-vue/issues/new?template=bug-report.yml)
|
||||
- 为[已有缺陷](https://github.com/opentiny/tiny-vue/labels/bug)提供更详细的信息,比如补充截图、提供更详细的复现步骤、提供最小可复现demo链接等
|
||||
- 提交 Pull requests 修复文档中的错别字或让文档更清晰和完善
|
||||
- 添加官方小助手微信 opentiny,加入技术交流群参与讨论
|
||||
|
||||
当你亲自使用 TinyVue 组件库,并参与多次以上形式的贡献,对 TinyVue 逐渐熟悉之后,可以尝试做一些更有挑战的事情,比如:
|
||||
|
||||
- 修复缺陷,可以先从 [Good-first issue](https://github.com/opentiny/tiny-vue/labels/good%20first%20issue) 开始
|
||||
- 实现新特性
|
||||
- 完善单元测试
|
||||
- 翻译文档
|
||||
- 参与代码检视
|
||||
|
||||
## 提交 Issue
|
||||
|
||||
如果你在使用 TinyVue 组件过程中遇到问题,欢迎给我们提交 Issue,提交 Issue 之前,请先仔细阅读相关的[官方文档](https://opentiny.design),确认这是一个缺陷还是尚未实现的功能。
|
||||
|
||||
如果是一个缺陷,创建新 Issue 时选择 [Bug report](https://github.com/opentiny/tiny-vue/issues/new?template=bug-report.yml) 模板,标题遵循 `[componentName]缺陷简述` 的格式,比如:`[select]选择框内容太长展示不下时,希望能支持配置tips提示`。
|
||||
|
||||
报告缺陷的 Issue 主要需要填写以下信息:
|
||||
- tiny-vue 和 vue 的版本号
|
||||
- 缺陷的表现,可截图辅助说明,如果有报错可贴上报错信息
|
||||
- 缺陷的复现步骤,最好能提供一个最小可复现 demo 链接
|
||||
|
||||
如果是一个新特性,则选择 [Feature request](https://github.com/opentiny/tiny-vue/issues/new?template=feature-request.yml) 模板,标题遵循 `[componentName]新特性简述` 的格式,比如:`[select]过滤功能中,选中的选项退格删除后,无法再次选中该选项`。
|
||||
|
||||
新特性的 Issue 主要需要填写以下信息:
|
||||
- 该特性主要解决用户的什么问题
|
||||
- 该特性的 api 是什么样的
|
||||
|
||||
## 提交 PR
|
||||
|
||||
提交 PR 之前,请先确保你提交的内容是符合 TinyVue 整体规划的,一般已经标记为 [bug](https://github.com/opentiny/tiny-vue/labels/bug) 的 Issue 是鼓励提交 PR 的,如果你不是很确定,可以创建一个 [Discussion](https://github.com/opentiny/tiny-vue/discussions) 进行讨论。
|
||||
|
||||
本地启动步骤:
|
||||
|
||||
- 点击 [TinyVue](https://github.com/opentiny/tiny-vue) 代码仓库右上角的 Fork 按钮,将上游仓库 Fork 到个人仓库
|
||||
- Clone 个人仓库到本地
|
||||
- 在 Tiny Vue 根目录下运行 npm i, 安装 node 依赖
|
||||
- 运行 npm run dev:vue3,启动组件库网站
|
||||
- 打开浏览器访问:[http://127.0.0.1:5173/](http://127.0.0.1:5173/)
|
||||
|
||||
```shell
|
||||
# username 为用户名,执行前请替换
|
||||
git clone git@github.com:username/tiny-vue.git
|
||||
cd tiny-vue
|
||||
git remote add upstream git@github.com:opentiny/tiny-vue.git
|
||||
npm i
|
||||
|
||||
# 启动 Vue3 项目
|
||||
npm run dev:vue3
|
||||
|
||||
# 启动 Vue2 项目
|
||||
npm run dev:vue2
|
||||
```
|
||||
|
||||
提交 PR 的步骤:
|
||||
|
||||
- 请确保你已经完成本地启动中的步骤,并能正常访问:[http://127.0.0.1:5173/](http://127.0.0.1:5173/)
|
||||
- 创建新分支 `git checkout -b username/feature1`,分支名字建议为 `username/feat-xxx` / `username/fix-xxx`
|
||||
- 本地编码
|
||||
- 遵循 Commit Message Format 规范进行提交,不符合提交规范的 PR 将不会被合并
|
||||
- 提交到远程仓库:git push origin branchName
|
||||
- (可选)同步上游仓库 dev 分支最新代码:git pull upstream dev
|
||||
- 打开 TinyVue 代码仓库的 [Pull requests](https://github.com/opentiny/tiny-vue/pulls) 链接,点击 New pull request 按钮提交 PR
|
||||
- 项目 Committer 进行 Code Review,并提出意见
|
||||
- PR 作者根据意见调整代码,请注意一个分支发起了 PR 后,后续的 commit 会自动同步,无需重新提交 PR
|
||||
- 项目管理员合并 PR
|
||||
|
||||
贡献流程结束,感谢你的贡献!
|
||||
|
||||
## 加入开源社区
|
||||
|
||||
如果你对我们的开源项目感兴趣,欢迎通过以下方式加入我们的开源社区。
|
||||
|
||||
- 添加官方小助手微信:opentiny,加入我们的技术交流群
|
||||
- 加入邮件列表:opentiny@googlegroups.com
|
|
@ -0,0 +1,22 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 - present TinyVue Authors.
|
||||
Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
75
README.md
|
@ -1,2 +1,75 @@
|
|||
# tiny-vue
|
||||
<p align="center">
|
||||
<a href="https://tinyuidesign.cloudbu.huawei.com/" target="_blank" rel="noopener noreferrer">
|
||||
<img alt="TinyVue Logo" src="logo.svg" height="100" style="max-width:100%;">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">Tiny Vue 是一个基于 Vue 的 UI 组件库,可以同时支持 Vue 2.0 和 Vue 3.0。</p>
|
||||
|
||||
特性:
|
||||
|
||||
- 包含 69 个简洁、易用、功能强大的组件
|
||||
- 同时支持 Vue2 和 Vue3
|
||||
- 支持国际化
|
||||
- 支持主题定制
|
||||
- 组件内部支持配置式开发,特别适合低代码平台可视化组件配置
|
||||
- 采用模板、样式、逻辑分离的跨端跨框架架构,保障灵活性和可移植性
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 1. 安装
|
||||
|
||||
执行以下命令,安装 Vue 3.0 版本的 Tiny Vue 组件库:
|
||||
|
||||
```shell
|
||||
npm i @opentiny/vue
|
||||
```
|
||||
|
||||
执行以下命令,安装 Vue 2.0 版本的 Tiny Vue 组件库 :
|
||||
|
||||
```shell
|
||||
npm i @opentiny/vue@2
|
||||
```
|
||||
|
||||
### 2. 引入和使用
|
||||
|
||||
在`App.vue`文件中使用 Tiny Vue 组件。
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { Button as TinyButton } from '@opentiny/vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tiny-button>Tiny Vue</tiny-button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 本地开发
|
||||
|
||||
```shell
|
||||
git clone git@github.com:opentiny/tiny-vue.git
|
||||
cd tiny-vue
|
||||
npm i
|
||||
|
||||
# 启动 Vue3 项目
|
||||
npm run dev:vue3
|
||||
|
||||
# 启动 Vue2 项目
|
||||
npm run dev:vue2
|
||||
```
|
||||
|
||||
打开浏览器访问:[http://127.0.0.1:5173/](http://127.0.0.1:5173/)
|
||||
|
||||
## 参与贡献
|
||||
|
||||
如果你对我们的开源项目感兴趣,欢迎加入我们!
|
||||
|
||||
参与贡献之前请先阅读[贡献指南](CONTRIBUTING.md)。
|
||||
|
||||
- 添加官方小助手微信 opentiny,加入技术交流群
|
||||
- 加入邮件列表 opentiny@googlegroups.com
|
||||
|
||||
## 开源协议
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ ! $version ];
|
||||
then npm version 0.1.0-`date "+%Y%m%d%H%M%S"`;
|
||||
else npm version ${version};
|
||||
fi
|
||||
|
||||
npm run bootstrap
|
||||
npm run build:vue3
|
||||
npm run release3
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "[ERROR] build falid!"
|
||||
exit 1
|
||||
fi
|
||||
echo '[INFO] build completed'
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"rules": {
|
||||
"no-empty": "off",
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 生成全量运行时入口文件
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const endOfLine = require('os').EOL
|
||||
const utils = require('./utils')
|
||||
const runtimeUtils = require('./runtime-utils')
|
||||
|
||||
const version = utils.getTinyVersion()
|
||||
const outputDir = 'packages'
|
||||
const IMPORT_TEMPLATE = 'import {{name}} from "@opentiny/vue-{{package}}"'
|
||||
const MAIN_TEMPLATE = `{{include}}
|
||||
|
||||
const version = '${version}'
|
||||
|
||||
export {
|
||||
version,
|
||||
{{components}}
|
||||
}
|
||||
`
|
||||
|
||||
const buildFullRuntime = (buildType) => {
|
||||
const outputPath = utils.pathJoin('..', outputDir, buildType + '.js')
|
||||
const includeTemplate = []
|
||||
const componentsTemplate = []
|
||||
const render = utils.renderTemplate()
|
||||
let coreLibs = []
|
||||
|
||||
coreLibs = runtimeUtils.getFullRuntime(buildType === 'base' ? ['base', 'business'] : buildType)
|
||||
|
||||
coreLibs.forEach((name) => {
|
||||
includeTemplate.push(
|
||||
render(IMPORT_TEMPLATE, {
|
||||
name,
|
||||
package: utils.kebabCase({ str: name })
|
||||
})
|
||||
)
|
||||
componentsTemplate.push(name)
|
||||
})
|
||||
|
||||
const template = render(MAIN_TEMPLATE, {
|
||||
include: includeTemplate.join(endOfLine),
|
||||
components: componentsTemplate.join(',' + endOfLine)
|
||||
})
|
||||
|
||||
const output = utils.prettierFormat({
|
||||
str: template
|
||||
})
|
||||
|
||||
fs.writeFileSync(outputPath, output)
|
||||
|
||||
utils.logGreen(`npm run build:entry done. [${outputDir}/${buildType}.js]`)
|
||||
}
|
||||
|
||||
;['core', 'base', 'chart'].forEach(buildFullRuntime)
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* 生成入口文件,包括 pc.js / mobile.js / index.js
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const endOfLine = require('os').EOL
|
||||
const utils = require('./utils')
|
||||
const moduleUtils = require('./module-utils')
|
||||
|
||||
const version = utils.getTinyVersion()
|
||||
const outputDir = 'packages'
|
||||
|
||||
const fileNames = {
|
||||
all: 'index.js',
|
||||
pc: 'pc.js',
|
||||
mobile: 'mobile.js'
|
||||
}
|
||||
|
||||
const getMainTemplate = (mode) => {
|
||||
const template = `{{include}}
|
||||
import { $prefix } from '@opentiny/vue-common'
|
||||
const components = [{{components}}]
|
||||
|
||||
export const install = (app, opts = {}) => {
|
||||
const regex = new RegExp('^' + $prefix)
|
||||
${
|
||||
mode === 'all'
|
||||
? ''
|
||||
: `
|
||||
if (typeof app.unmount === 'function') {
|
||||
app.config.globalProperties.tiny_mode = { value: '${mode}' }
|
||||
} else {
|
||||
app.prototype.tiny_mode = { value: '${mode}' }
|
||||
}
|
||||
`
|
||||
}
|
||||
components.filter(component=> component.name !== 'TinyPicker').forEach((component) => {
|
||||
let name = component.name
|
||||
let alias = opts.alias || opts.prefix
|
||||
if (typeof component.install !== 'function') { return }
|
||||
if (name && alias) {
|
||||
app.component(name.replace(regex, alias), component)
|
||||
} else {
|
||||
component.install(app)
|
||||
}
|
||||
})
|
||||
}
|
||||
const version = '${version}'
|
||||
export {
|
||||
version,
|
||||
{{components}}
|
||||
}
|
||||
|
||||
export default {
|
||||
version,
|
||||
{{components}},
|
||||
install
|
||||
}
|
||||
`
|
||||
return template
|
||||
}
|
||||
|
||||
const forEachCompoents = ({ components, componentsTemplate, render, INSTALL_COMPONENT_TEMPLATE, includeTemplate, IMPORT_TEMPLATE }) => {
|
||||
components.forEach((item) => {
|
||||
let exportsComponents = ''
|
||||
const childrenComponents = []
|
||||
|
||||
// 增加组件内部抛出子组件,针对父子组件不能拆分的情况
|
||||
if (Array.isArray(item.exports) && item.exports.length > 0) {
|
||||
item.exports.indexOf(item.name) === -1 && item.exports.push(item.name)
|
||||
} else {
|
||||
item.exports = [item.name]
|
||||
}
|
||||
|
||||
item.exports.forEach((component) => {
|
||||
if (component !== item.name) {
|
||||
component = utils.capitalizeKebabCase(component)
|
||||
|
||||
childrenComponents.push(component)
|
||||
}
|
||||
|
||||
componentsTemplate.push(
|
||||
render(INSTALL_COMPONENT_TEMPLATE, {
|
||||
name: component
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
if (childrenComponents.length) {
|
||||
exportsComponents = `,{${childrenComponents.join(',')}}`
|
||||
}
|
||||
|
||||
includeTemplate.push(
|
||||
render(IMPORT_TEMPLATE, {
|
||||
name: item.name,
|
||||
exports: exportsComponents,
|
||||
package: item.importName
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const createEntry = (mode) => {
|
||||
const OUTPUT_PATH = utils.pathJoin('..', outputDir, fileNames[mode])
|
||||
const IMPORT_TEMPLATE = 'import {{name}} {{exports}} from "{{package}}"'
|
||||
const INSTALL_COMPONENT_TEMPLATE = ' {{name}}'
|
||||
|
||||
const MAIN_TEMPLATE = getMainTemplate(mode)
|
||||
|
||||
const includeTemplate = []
|
||||
const componentsTemplate = []
|
||||
const render = utils.renderTemplate()
|
||||
let components
|
||||
|
||||
if (mode === 'pc') {
|
||||
components = moduleUtils.getPcComponents()
|
||||
} else if (mode === 'mobile') {
|
||||
components = moduleUtils.getMobileComponents()
|
||||
} else {
|
||||
components = moduleUtils.getComponents()
|
||||
}
|
||||
|
||||
forEachCompoents({
|
||||
components,
|
||||
componentsTemplate,
|
||||
render,
|
||||
INSTALL_COMPONENT_TEMPLATE,
|
||||
includeTemplate,
|
||||
IMPORT_TEMPLATE
|
||||
})
|
||||
|
||||
const template = render(MAIN_TEMPLATE, {
|
||||
include: includeTemplate.join(endOfLine),
|
||||
components: componentsTemplate.join(`,${endOfLine}`)
|
||||
})
|
||||
|
||||
const output = utils.prettierFormat({
|
||||
str: template
|
||||
})
|
||||
|
||||
fs.writeFileSync(OUTPUT_PATH, output)
|
||||
}
|
||||
;['all', 'pc', 'mobile'].forEach(createEntry)
|
||||
|
||||
utils.logGreen(`npm run build:entry done. [${outputDir}/index.js,${outputDir}/pc.js,${outputDir}/mobile.js]`)
|
|
@ -0,0 +1,92 @@
|
|||
const vue = require('rollup-plugin-vue')
|
||||
const { babel } = require('@rollup/plugin-babel')
|
||||
const commonjs = require('@rollup/plugin-commonjs')
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve')
|
||||
const { pathJoin, logGreen, logRed } = require('./utils')
|
||||
const rollup = require('rollup')
|
||||
const svg = require('rollup-plugin-vue-inline-svg')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
|
||||
const inputOptions = {
|
||||
plugins: [
|
||||
vue({
|
||||
css: true
|
||||
}),
|
||||
svg({
|
||||
svgoConfig: {
|
||||
plugins: [{ removeDoctype: true }, { removeComments: true }, { removeViewBox: false }],
|
||||
removeViewBox: false
|
||||
}
|
||||
}),
|
||||
nodeResolve(),
|
||||
babel({
|
||||
exclude: /node_modules/,
|
||||
configFile: false, // 必须为 false 不然会取根文件的 babel.config.js 配置,产生一堆 runtime 代码
|
||||
babelrc: false,
|
||||
babelHelpers: 'bundled',
|
||||
plugins: ['@babel/plugin-proposal-export-default-from', '@babel/plugin-proposal-export-namespace-from'],
|
||||
presets: ['@babel/preset-env'],
|
||||
extensions: ['.js', '.vue']
|
||||
}),
|
||||
// 如果打包文件中包含 jsx 语法, commonjs 必须放置在 babel 配置下面,否则会报错 PLUGIN_ERROR
|
||||
commonjs()
|
||||
],
|
||||
external: (deps) => /^@opentiny[\\/]-vue-common/.test(deps)
|
||||
}
|
||||
|
||||
const outputOptions = {
|
||||
format: 'es',
|
||||
exports: 'named'
|
||||
}
|
||||
|
||||
const build = (components) => {
|
||||
components.forEach((component) => {
|
||||
const inputs = { ...inputOptions }
|
||||
|
||||
inputs.input = pathJoin('..', 'packages', 'icon', component.path)
|
||||
|
||||
if (component.path === 'index.js') {
|
||||
inputs.external = (deps) => !deps.includes('index.js')
|
||||
} else {
|
||||
inputs.external = (deps) => /^@opentiny[\\/]vue-common/.test(deps)
|
||||
}
|
||||
|
||||
rollup
|
||||
.rollup(inputs)
|
||||
.then((bundle) => {
|
||||
const outs = { ...outputOptions }
|
||||
outs.file = pathJoin('..', 'packages', 'icon', component.libPath)
|
||||
bundle.write(outs)
|
||||
logGreen(`${component.path} compile icon done`)
|
||||
})
|
||||
.catch((e) => {
|
||||
logRed(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function createComponentMap(dir) {
|
||||
const components = []
|
||||
fs.readdirSync(dir).forEach((file) => {
|
||||
if (['dist', 'runtime'].includes(file)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (fs.statSync(path.join(dir, file)).isDirectory()) {
|
||||
components.push({
|
||||
path: `${file}/index.js`,
|
||||
libPath: `dist/lib/${file}.js`
|
||||
})
|
||||
} else {
|
||||
file.endsWith('.js') &&
|
||||
components.push({
|
||||
path: `${file}`,
|
||||
libPath: `dist/lib/${file}`
|
||||
})
|
||||
}
|
||||
})
|
||||
return components
|
||||
}
|
||||
|
||||
build(createComponentMap(pathJoin('..', 'packages', 'icon')))
|
|
@ -0,0 +1,115 @@
|
|||
const rollup = require('rollup')
|
||||
const utils = require('./utils')
|
||||
const replace = require('@rollup/plugin-replace')
|
||||
const moduleUtils = require('./module-utils')
|
||||
const fs = require('fs-extra')
|
||||
const isSingle = process.env.BUILD_TARGET === 'single'
|
||||
const config = require('./config')
|
||||
|
||||
const outputOptions = {
|
||||
format: 'es',
|
||||
globals: config.globals,
|
||||
exports: 'named'
|
||||
}
|
||||
|
||||
const inputOptions = {
|
||||
plugins: config.plugins,
|
||||
external: config.external
|
||||
}
|
||||
|
||||
const replaceConstant = {
|
||||
'process.env.BUILD_TARGET': JSON.stringify(process.env.BUILD_TARGET),
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
|
||||
}
|
||||
|
||||
if (process.env.tiny_mode === 'pc') {
|
||||
outputOptions.format = 'umd'
|
||||
replaceConstant['process.env.TINY_MODE'] = JSON.stringify(process.env.tiny_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译单个组件
|
||||
* @param {Object} component 组件 module 信息 (modules.json)
|
||||
* @param {Function} 回调函数
|
||||
*/
|
||||
const build = ({ component, callback }) => {
|
||||
inputOptions.input = utils.pathJoin('..', component.path)
|
||||
|
||||
inputOptions.plugins.push(replace(replaceConstant))
|
||||
rollup
|
||||
.rollup(inputOptions)
|
||||
.then((bundle) => {
|
||||
outputOptions.file = utils.pathJoin('..', component.libPath)
|
||||
if (outputOptions.format === 'umd') {
|
||||
outputOptions.name = component.global
|
||||
}
|
||||
bundle.write(outputOptions).finally(() => {
|
||||
const filePath = utils.pathJoin('..', component.libPath)
|
||||
if (filePath.endsWith('index.js')) {
|
||||
const indexStr = fs.readFileSync(filePath).toString('UTF-8')
|
||||
const resStr = indexStr.replace('./src/pc', './pc').replace('./src/mobile', './mobile')
|
||||
fs.writeFileSync(filePath, resStr)
|
||||
}
|
||||
callback()
|
||||
})
|
||||
})
|
||||
.catch((e) => {
|
||||
utils.logRed(e)
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
let components = []
|
||||
|
||||
/**
|
||||
* 递归执行 Rollup 编译
|
||||
* @param {Number} count 起始索引
|
||||
*/
|
||||
const buildAll = (count = 0) => {
|
||||
let component = components[count++]
|
||||
if (component) {
|
||||
if (!isSingle) {
|
||||
component.libPath = 'dist/' + component.libName.replace('@opentiny/vue/', '')
|
||||
component.libPath += (component.type === 'component' ? '/index' : '') + '.js'
|
||||
}
|
||||
build({
|
||||
component,
|
||||
callback() {
|
||||
buildAll(count)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
utils.logGreen(`npm run build:ui${isSingle ? '-single' : ''} done.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (isSingle) {
|
||||
const inputName = utils.getInputCmd()
|
||||
if (inputName.length > 0) {
|
||||
inputName.forEach((input) => {
|
||||
const activeComponentName = utils.kebabCase({ str: input })
|
||||
|
||||
if (activeComponentName) {
|
||||
components.push(
|
||||
...moduleUtils.getByName({
|
||||
name: activeComponentName,
|
||||
isSort: false
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const activeComponentName = utils.getComponentName()
|
||||
components = moduleUtils.getByName({
|
||||
name: activeComponentName,
|
||||
isSort: false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
components = moduleUtils.getAllModules(false)
|
||||
}
|
||||
if (components.length > 0) {
|
||||
buildAll()
|
||||
} else {
|
||||
utils.logYellow('please enter the component name after command.')
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* 批量更新组件版本号,一般用于大版本发布
|
||||
* npm run build:version ${targetVersion} ${tag} ${single-components}|null[build all pkg]
|
||||
* example:
|
||||
* 发布 @opentiny/vue-alert@next 和 @opentiny/vue-button@next 命令:
|
||||
* npm run build:version '0.1.0' 'next' 'alert button'
|
||||
* 发布全量包@next:
|
||||
* npm run build:version '0.1.0' 'next'
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const ROOT_PATH = path.join(__dirname, '..')
|
||||
const TYPE = process.env.TYPE
|
||||
const isFullVersionUpdate = true
|
||||
const TAG = process.argv[3] === 'false' ? '' : process.argv[3]
|
||||
const packages = path.join(ROOT_PATH, 'packages')
|
||||
const pkgJsonFileName = 'package.json'
|
||||
const { logGreen } = require('./utils')
|
||||
const tinyVueReg = /@opentiny\//
|
||||
|
||||
const targetVersion = process.argv[2] || JSON.parse(fs.readFileSync(path.join(ROOT_PATH, pkgJsonFileName)).toString()).version
|
||||
|
||||
const isUpdateDependenciesVersion = true // process.argv[3] === 'true'
|
||||
const single = process.argv[4]
|
||||
const targetVersionArr = targetVersion.split('.')
|
||||
const oldVersion = `${targetVersionArr[0]}.${targetVersionArr[1] - 1}.0`
|
||||
const targetVersionDependencies = `${targetVersionArr[0]}.${targetVersionArr[1]}.0`
|
||||
|
||||
const isTinyVuePkg = (str) => tinyVueReg.test(str || '')
|
||||
|
||||
const replaceDependenciesForTag = (obj) => {
|
||||
for (let key in obj) {
|
||||
if (isTinyVuePkg(key)) {
|
||||
obj[key] = TAG
|
||||
}
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
const replaceDependencies = (obj) => {
|
||||
for (let key in obj) {
|
||||
if (isTinyVuePkg(key) && /~/.test(obj[key])) {
|
||||
obj[key] = obj[key].replace(isUpdateDependenciesVersion ? /[0-9]+\.[0-9]+\.[0-9]+/ : oldVersion, targetVersionDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
const buidPackages = (dirs) => {
|
||||
let uiArr
|
||||
|
||||
if (single) {
|
||||
uiArr = single.trim().split(' ')
|
||||
}
|
||||
|
||||
fs.readdirSync(dirs).forEach((name) => {
|
||||
if (uiArr && !uiArr.includes(name)) {
|
||||
return
|
||||
}
|
||||
|
||||
const component = path.join(dirs, name)
|
||||
|
||||
if (name === 'src' || !fs.statSync(component).isDirectory()) {
|
||||
return
|
||||
}
|
||||
|
||||
let pkgJsonFile, pkgJson
|
||||
|
||||
try {
|
||||
pkgJsonFile = path.join(component, pkgJsonFileName)
|
||||
pkgJson = JSON.parse(fs.readFileSync(pkgJsonFile).toString())
|
||||
} catch (error) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isTinyVuePkg(pkgJson.name)) {
|
||||
const arr = ['dependencies', 'devDependencies']
|
||||
|
||||
pkgJson.version = single || isFullVersionUpdate ? targetVersion : targetVersionDependencies
|
||||
|
||||
arr.forEach((key) => {
|
||||
if (pkgJson[key]) {
|
||||
pkgJson[key] = TAG ? replaceDependenciesForTag(pkgJson[key]) : replaceDependencies(pkgJson[key])
|
||||
}
|
||||
})
|
||||
|
||||
fs.writeFileSync(pkgJsonFile, JSON.stringify(pkgJson, null, 2))
|
||||
}
|
||||
|
||||
if (name === 'chart') {
|
||||
buidPackages(component)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!targetVersion) {
|
||||
throw new Error('targetVersion is null, cmd example:\n npm run build:version 3.10.0 true "alert grid"')
|
||||
}
|
||||
|
||||
const buildCommon = () => {
|
||||
const pkgJsonFile = path.join(ROOT_PATH, pkgJsonFileName)
|
||||
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonFile).toString())
|
||||
|
||||
pkgJson.version = targetVersion
|
||||
pkgJson.uiVersion = isFullVersionUpdate ? targetVersion : targetVersionDependencies
|
||||
pkgJson.srcVersion = isFullVersionUpdate ? targetVersion : targetVersionDependencies
|
||||
|
||||
fs.writeFileSync(pkgJsonFile, JSON.stringify(pkgJson, null, 2))
|
||||
logGreen('update src version done')
|
||||
}
|
||||
|
||||
const build = () => {
|
||||
buildCommon()
|
||||
|
||||
if (TYPE === 'ui') {
|
||||
buidPackages(packages)
|
||||
logGreen('update all component version done')
|
||||
}
|
||||
}
|
||||
|
||||
build()
|
|
@ -0,0 +1,82 @@
|
|||
const fs = require('fs-extra')
|
||||
const vue = require('rollup-plugin-vue')
|
||||
const { babel } = require('@rollup/plugin-babel')
|
||||
const alias = require('@rollup/plugin-alias')
|
||||
const commonjs = require('@rollup/plugin-commonjs')
|
||||
const postcss = require('rollup-plugin-postcss')
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve')
|
||||
const { pathJoin } = require('./utils')
|
||||
const { getAllModules } = require('./module-utils')
|
||||
|
||||
const external = ['vue', './pc', './mobile', '@vue/composition-api', '@opentiny/vue-common', '@opentiny/vue-locale', '@opentiny/vue-renderless']
|
||||
|
||||
const globals = {
|
||||
vue: 'Vue',
|
||||
'@vue/composition-api': 'vueCompositionApi',
|
||||
'@opentiny/vue-common': 'TinyVueCommon',
|
||||
'@opentiny/vue-locale': 'TinyVueLocale',
|
||||
'@opentiny/vue-renderless': 'TinyRenderLess'
|
||||
}
|
||||
|
||||
const aliasList = {}
|
||||
const components = getAllModules(false)
|
||||
|
||||
components.forEach((item) => {
|
||||
aliasList[item.libName] = pathJoin('../' + item.path)
|
||||
|
||||
if (item.private) {
|
||||
return
|
||||
}
|
||||
|
||||
const isComponent = item.type === 'component'
|
||||
|
||||
external.push(item.importName) // @opentiny/vue-todo
|
||||
external.push(item.libName) // @opentiny/vue/todo
|
||||
globals[item.libName] = item.global // TinyTodo
|
||||
|
||||
if (isComponent) {
|
||||
if (fs.existsSync(pathJoin('../../vue-theme3'))) {
|
||||
aliasList[`@opentiny/vue-theme/${item.LowerName}/index.css`] = pathJoin(`../../vue-theme3/style/${item.LowerName}/index.css`)
|
||||
aliasList[`@opentiny/vue-theme/${item.LowerName}/index.js`] = pathJoin(`../../vue-theme3/style/${item.LowerName}/index.js`)
|
||||
}
|
||||
external.push(item.libName + '/index.js')
|
||||
} else {
|
||||
external.push(item.libName + '.js')
|
||||
}
|
||||
})
|
||||
|
||||
exports.aliasList = aliasList
|
||||
|
||||
exports.external = (deps) => external.includes(deps) || /^@opentiny[\\/](vue-renderless|vue-theme|vue-common|vue-icon)|cropperjs/.test(deps)
|
||||
|
||||
exports.globals = globals
|
||||
|
||||
exports.plugins = [
|
||||
alias({
|
||||
resolve: ['.js', '.vue', '.css'],
|
||||
'@opentiny/vue-locale': pathJoin('../packages/locale/index'),
|
||||
'@opentiny/vue-common': pathJoin('../packages/common/index'),
|
||||
...aliasList
|
||||
}),
|
||||
postcss({
|
||||
extract: false
|
||||
}),
|
||||
vue({
|
||||
css: true
|
||||
}),
|
||||
nodeResolve({
|
||||
extensions: ['.js', '.jsx', '.vue', '.css']
|
||||
}),
|
||||
babel({
|
||||
exclude: /node_modules/,
|
||||
babelrc: false,
|
||||
configFile: false, // 必须为 false 不然会取根文件的 babel.config.js 配置,产生一堆 runtime 代码
|
||||
babelHelpers: 'bundled',
|
||||
comments: false,
|
||||
extensions: ['.js', '.vue', '.jsx'],
|
||||
presets: ['@babel/preset-env', '@vue/babel-preset-jsx'],
|
||||
plugins: ['@babel/plugin-syntax-dynamic-import']
|
||||
}),
|
||||
// 如果打包文件中包含 jsx 语法, commonjs 必须放置在 babel 配置下面,否则会报错 PLUGIN_ERROR
|
||||
commonjs()
|
||||
]
|
|
@ -0,0 +1,68 @@
|
|||
const { sep } = require('path')
|
||||
const utils = require('./utils')
|
||||
const { addModule, writeModuleMap, quickSort, readModuleMap } = require('./module-utils')
|
||||
|
||||
const isDeepFn = (file, dirs, subPath) =>
|
||||
// 如果底层文件夹内没有找到 vue 文件,找到 src//index.js 文件也被认可为组件
|
||||
(file.endsWith('.vue') && (dirs.includes('index.js') || dirs.includes('index.vue'))) || ~subPath.indexOf(['src', 'index.js'].join(sep))
|
||||
|
||||
const getTemplateName = (currentPaths) => currentPaths.slice(2).map(utils.capitalize).join('/').split('.')[0].replace('/', '')
|
||||
|
||||
/**
|
||||
* 扫描指定目录下面的组件目录,查找非 index.vue 文件(模板)生成 modules.json 中的对象
|
||||
*/
|
||||
const makeModules = () => {
|
||||
const templates = {}
|
||||
const oldModules = readModuleMap()
|
||||
const packagesStr = 'packages'
|
||||
utils.walkFileTree({
|
||||
isDeep: true,
|
||||
dirPath: utils.pathJoin('..', packagesStr),
|
||||
fileFilter({ file }) {
|
||||
return !/node_modules|helper|common|assets/.test(file)
|
||||
},
|
||||
callback({ file, subPath, dirs }) {
|
||||
const isDeep = isDeepFn(file, dirs, subPath)
|
||||
// NEXT: 针对 option 的模板做特殊处理
|
||||
if (isDeep && ['template.vue'].indexOf(file) === -1) {
|
||||
const isEntry = file.startsWith('index')
|
||||
const subPaths = subPath.split(sep)
|
||||
const currentPaths = subPaths.slice(subPaths.indexOf(packagesStr) + 1)
|
||||
const templateName = getTemplateName(currentPaths)
|
||||
const templatePath = currentPaths[currentPaths.length - 1].split('.')[0]
|
||||
const componentName = []
|
||||
currentPaths.every((dirName) => {
|
||||
if (dirName === 'src') {
|
||||
return false
|
||||
}
|
||||
componentName.push(dirName)
|
||||
return true
|
||||
})
|
||||
const globalName = componentName[componentName.length - 1].split('-').map(utils.capitalize).join('')
|
||||
const moduleName = globalName + (isEntry ? '' : templateName)
|
||||
const oldModuleItem = oldModules[moduleName] || {}
|
||||
const oldKeys = Object.keys(oldModuleItem)
|
||||
const newModuleItem = addModule({
|
||||
componentName: componentName.join('/'),
|
||||
templateName: templatePath
|
||||
})
|
||||
oldKeys.forEach((key) => {
|
||||
if (typeof newModuleItem[key] === 'undefined' || key === 'onlyMode') {
|
||||
newModuleItem[key] = oldModuleItem[key]
|
||||
}
|
||||
})
|
||||
newModuleItem.exclude = oldModuleItem.exclude || false
|
||||
templates[moduleName] = newModuleItem
|
||||
}
|
||||
}
|
||||
})
|
||||
writeModuleMap(quickSort({ sortData: templates, returnType: 'object' }))
|
||||
}
|
||||
|
||||
try {
|
||||
makeModules()
|
||||
|
||||
utils.logGreen('npm run create:mapping done.')
|
||||
} catch (e) {
|
||||
utils.logRed('npm run create:mapping failed.', e)
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/**
|
||||
* yarn create:ui 新建组件,支持格式如下:
|
||||
* yarn create:ui img-preview
|
||||
* yarn create:ui img-preview -single 输出纯净模板(没有 pc 等模板/单层组件)
|
||||
* yarn create:ui img-preview -mobile 创建纯移动组件
|
||||
*/
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const semver = require('semver')
|
||||
const utils = require('./utils')
|
||||
const { createModuleMapping } = require('./module-utils')
|
||||
|
||||
const args = utils.getInputCmd()
|
||||
|
||||
const getTemplate = (upperComponentName) => `<template>
|
||||
<div>
|
||||
<tiny-[[NAME]] _mode="mobile"></tiny-[[NAME]]>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { [[UNAME]] } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
name: '[[UNAME]]',
|
||||
components: {
|
||||
Tiny${upperComponentName}:${upperComponentName}
|
||||
}
|
||||
}
|
||||
</script>`
|
||||
|
||||
const getDcoTemplate = () => `<div class="demo-header">
|
||||
<p class="overviewicon">
|
||||
<span class="wapi-ui-[[NAME]]"/>
|
||||
</p>
|
||||
|
||||
## [[UNAME]]
|
||||
|
||||
<mobile-uxlink widget-name="[[UNAME]]"></mobile-uxlink>
|
||||
|
||||
</div>
|
||||
|
||||
### [[UNAME]]
|
||||
|
||||
<mobile-view link="[[NAME]]/base"></mobile-view>`
|
||||
|
||||
const getTemp = (componentName) => `const router = [
|
||||
{
|
||||
path: '${componentName}',
|
||||
meta: {
|
||||
title: 'test',
|
||||
lang: 'zh-CN',
|
||||
sign: 'component'
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: 'v3-${componentName}' */ './docs/mobile/${componentName}/base.md'
|
||||
)
|
||||
},`
|
||||
|
||||
const doWorkTreeFn = ({ templateDir, componentPath, componetDir, componentName, isSingle, render, version, isMobile }) => {
|
||||
utils.walkFileTree({
|
||||
isDeep: true,
|
||||
dirPath: templateDir,
|
||||
callback({ file, subPath }) {
|
||||
let fileName = file
|
||||
const isSingleTemplate = file === 'single.vue'
|
||||
const isSrcDir = path.basename(path.dirname(subPath)) === 'src'
|
||||
|
||||
componentPath = path.join(componetDir, componentName)
|
||||
|
||||
// 单层组件处理逻辑
|
||||
if (isSrcDir) {
|
||||
componentPath = path.join(componentPath, 'src')
|
||||
|
||||
if (isSingle) {
|
||||
if (!isSingleTemplate) {
|
||||
return
|
||||
}
|
||||
|
||||
fileName = 'index.vue'
|
||||
} else {
|
||||
if (isSingleTemplate) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(componentPath)) {
|
||||
fs.mkdirSync(componentPath)
|
||||
}
|
||||
|
||||
componentPath = path.join(componentPath, fileName)
|
||||
|
||||
let fileContent = fs.readFileSync(subPath, { encoding: 'utf8' })
|
||||
const upperComponentName = utils.capitalizeKebabCase(componentName)
|
||||
|
||||
// 编译模板
|
||||
fileContent = render(fileContent, {
|
||||
NAME: componentName,
|
||||
UNAME: upperComponentName,
|
||||
MINOR: semver.minor(version),
|
||||
SUFFIX: isSingle ? '.vue' : '',
|
||||
THEME: isMobile ? 'theme-mobile' : 'theme'
|
||||
})
|
||||
|
||||
fs.writeFileSync(componentPath, fileContent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const createRouter = (json, componentName, navPath, router) => {
|
||||
const Navs = JSON.parse(json)
|
||||
Navs.component.push({
|
||||
name: 'New Component',
|
||||
children: [
|
||||
{
|
||||
path: `/${componentName}`,
|
||||
name: `${componentName}`
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
fs.writeFileSync(path.join(navPath, 'nav.config.comp.mobile.json'), JSON.stringify(Navs, null, 2), { encoding: 'utf-8' })
|
||||
|
||||
fs.writeFileSync(path.join(navPath, 'route.config.comp.mobile.js'), router, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
const commands = []
|
||||
const components = []
|
||||
const render = utils.renderTemplate({ leftChar: '[[', rightChar: ']]' })
|
||||
const templateDir = utils.pathJoin('..', 'template', 'component')
|
||||
const componetDir = utils.pathJoin('..', 'packages')
|
||||
const demoDir = utils.pathJoin('..', 'example', 'src', 'demo', 'mobile')
|
||||
const docDir = utils.pathJoin('..', 'example', 'src', 'docs', 'mobile')
|
||||
const { version } = fs.readJSONSync(utils.pathJoin('..', 'package.json'))
|
||||
const navPath = utils.pathJoin('..', 'example', 'src')
|
||||
|
||||
args.forEach((item) => {
|
||||
if (item.indexOf('-') === 0) {
|
||||
commands.push(item.replace(/-/g, '').toLowerCase())
|
||||
} else {
|
||||
components.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
const isSingle = commands.includes('single')
|
||||
const isMobile = commands.includes('mobile')
|
||||
|
||||
const createDemo = (filePath, componentName, fileName, template) => {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
fs.mkdirSync(filePath)
|
||||
}
|
||||
|
||||
const upperComponentName = utils.capitalizeKebabCase(componentName)
|
||||
|
||||
// 生成测试demo
|
||||
filePath = path.join(filePath, fileName)
|
||||
|
||||
const outString = render(template, {
|
||||
NAME: componentName,
|
||||
UNAME: upperComponentName
|
||||
})
|
||||
|
||||
const outputDemo = require('prettier').format(outString, {
|
||||
printWidth: 160,
|
||||
jsxBracketSameLine: false,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
singleQuote: true,
|
||||
semi: false,
|
||||
trailingComma: 'none',
|
||||
bracketSpacing: true,
|
||||
parser: 'vue'
|
||||
})
|
||||
|
||||
fs.writeFileSync(filePath, outputDemo)
|
||||
}
|
||||
|
||||
components.forEach((componentName) => {
|
||||
let componentPath = path.join(componetDir, componentName)
|
||||
let demoPath = path.join(demoDir, componentName)
|
||||
let docPath = path.join(docDir, componentName)
|
||||
const upperComponentName = utils.capitalizeKebabCase(componentName)
|
||||
|
||||
if (fs.existsSync(componentPath)) {
|
||||
utils.logYellow(`The component name : ${componentName} is exist , please enter other name.`)
|
||||
return
|
||||
}
|
||||
|
||||
const json = fs.readFileSync(path.join(navPath, 'nav.config.comp.mobile.json'), { encoding: 'utf8' })
|
||||
|
||||
let router = fs.readFileSync(path.join(navPath, 'route.config.comp.mobile.js'), { encoding: 'utf8' })
|
||||
|
||||
const templ = getTemp(componentName)
|
||||
router = router.replace('const router = [', templ)
|
||||
|
||||
createRouter(json, componentName, navPath, router)
|
||||
|
||||
doWorkTreeFn({
|
||||
templateDir,
|
||||
componentPath,
|
||||
componetDir,
|
||||
componentName,
|
||||
isSingle,
|
||||
render,
|
||||
version,
|
||||
isMobile
|
||||
})
|
||||
|
||||
// 生成测试demo
|
||||
const template = getTemplate(upperComponentName)
|
||||
createDemo(demoPath, componentName, 'base.vue', template)
|
||||
|
||||
// 生成doc
|
||||
const dcoTemplate = getDcoTemplate()
|
||||
|
||||
createDemo(docPath, componentName, 'base.md', dcoTemplate)
|
||||
|
||||
componentName && createModuleMapping(componentName, componentPath, isMobile)
|
||||
})
|
||||
|
||||
utils.logYellow('npm run create:ui done.')
|
||||
} else {
|
||||
utils.logYellow('please enter the component name after command.')
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
/**
|
||||
* 专门用于 modules.json 配置的通用方法
|
||||
* modules.json 作为单组件的清单列表,记录组件类型、路径、是否排除引用、仅支持某种[pc/mobile]模式等
|
||||
*/
|
||||
const { writeFileSync } = require('fs')
|
||||
const moduleMap = require('../modules.json')
|
||||
const { kebabCase, pathJoin, capitalize, prettierFormat, logGreen, capitalizeKebabCase } = require('./utils')
|
||||
|
||||
const realNameMap = {
|
||||
realValue: '__real_value'
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的组件模板
|
||||
*/
|
||||
const defaultMode = ['index', 'pc']
|
||||
|
||||
/**
|
||||
* 组件组包名前缀:@opentiny/vue-tag | @opentiny/vue/tag
|
||||
*/
|
||||
const importName = '@opentiny/vue'
|
||||
|
||||
const exampleBase = 'basic-usage.vue'
|
||||
|
||||
/**
|
||||
* 查询没有模板的组件(单层组件)
|
||||
*/
|
||||
const getNoTemplateComponents = () => {
|
||||
const components = []
|
||||
const templates = ['Pc', 'Mobile']
|
||||
|
||||
Object.keys(moduleMap).forEach((key) => {
|
||||
if (!key.endsWith(templates[0]) && !key.endsWith(templates[1]) && !key.startsWith('Chart')) {
|
||||
if (!moduleMap[key + templates[0]] && !moduleMap[key + templates[1]]) {
|
||||
components.push(moduleMap[key])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 PC 组件
|
||||
*/
|
||||
const isPcComponent = (name) => {
|
||||
const componentName = capitalizeKebabCase(name)
|
||||
const moduleInfo = moduleMap[componentName]
|
||||
|
||||
return moduleInfo && moduleInfo.onlyMode !== 'mobile'
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 Mobile 组件
|
||||
*/
|
||||
const isMobileComponent = (name) => {
|
||||
const componentName = capitalizeKebabCase(name)
|
||||
const moduleInfo = moduleMap[componentName]
|
||||
|
||||
return moduleInfo && moduleInfo.onlyMode === 'mobile'
|
||||
}
|
||||
|
||||
const setIndex = (obj, key, maxNumberLength, indexArr) => {
|
||||
// 一个字母用3位数代替,没有达到3位用0填充到前面,为了减少差值,在前面设置1
|
||||
const priority =
|
||||
'1' +
|
||||
obj[key]
|
||||
.split('')
|
||||
.map((chart) => String(chart.charCodeAt()).padStart(3, '0'))
|
||||
.join('')
|
||||
.padEnd(maxNumberLength, '0')
|
||||
.substr(0, maxNumberLength)
|
||||
|
||||
// 分段比较 (javascript 超过15位比较失效)
|
||||
obj.priority1 = Number(priority.substr(0, 15))
|
||||
obj.priority2 = Number(priority.substr(15, 30))
|
||||
obj.priority3 = Number(priority.substr(30, 45))
|
||||
obj.priority4 = Number(priority.substr(45, maxNumberLength))
|
||||
|
||||
obj.priority = priority
|
||||
|
||||
indexArr.push(obj)
|
||||
}
|
||||
|
||||
const arrayToObject = (arr, key) => {
|
||||
const sortObj = {}
|
||||
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
if (arr[i][realNameMap.realValue]) {
|
||||
sortObj[arr[i][key]] = arr[i][realNameMap.realValue]
|
||||
} else {
|
||||
delete arr[i].priority
|
||||
delete arr[i].priority1
|
||||
delete arr[i].priority2
|
||||
delete arr[i].priority3
|
||||
delete arr[i].priority4
|
||||
|
||||
sortObj[arr[i][key]] = arr[i]
|
||||
|
||||
delete sortObj[arr[i][key]][key]
|
||||
}
|
||||
}
|
||||
|
||||
return sortObj
|
||||
}
|
||||
|
||||
const sortArray = (arr) => {
|
||||
if (Array.isArray(arr) && arr.length > 1) {
|
||||
const middleIndex = Math.floor(arr.length / 2)
|
||||
const middleValue = arr.splice(middleIndex, 1)[0]
|
||||
const leftArr = []
|
||||
const rightArr = []
|
||||
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
const left = arr[i].priority1 - middleValue.priority1
|
||||
const right = arr[i].priority2 - middleValue.priority2
|
||||
const right2 = arr[i].priority3 - middleValue.priority3
|
||||
const right3 = arr[i].priority4 - middleValue.priority4
|
||||
|
||||
let isLeft = false
|
||||
|
||||
if (left === 0 && (right < 0 || (right === 0 && right2 < 0) || (right === 0 && right2 === 0 && right3 < 0))) {
|
||||
isLeft = true
|
||||
}
|
||||
|
||||
if (left < 0 || isLeft) {
|
||||
leftArr.push(arr[i])
|
||||
} else {
|
||||
rightArr.push(arr[i])
|
||||
}
|
||||
}
|
||||
|
||||
return sortArray(leftArr).concat([middleValue], sortArray(rightArr))
|
||||
} else {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将模块数组按字母的 ASCII 值进行排序(目前只支持16位字母排序)
|
||||
* @private
|
||||
* @param {Array|Object} sortData 模块数组
|
||||
* @param {String} key 排序字段
|
||||
* @param {String} returnType 返回类型 Array|Object
|
||||
* @returns 排序后的数组或对象
|
||||
*/
|
||||
const quickSort = ({ sortData, key = 'name', returnType = 'array' }) => {
|
||||
const maxNumberLength = 59
|
||||
let indexArr = []
|
||||
if (sortData instanceof Array) {
|
||||
sortData.forEach((item) => {
|
||||
setIndex(item, key, maxNumberLength, indexArr)
|
||||
})
|
||||
} else if (typeof sortData === 'object') {
|
||||
for (const sortKey in sortData) {
|
||||
if (Object.prototype.hasOwnProperty.call(sortData, sortKey)) {
|
||||
const dataItem = sortData[sortKey]
|
||||
let sortItem = {}
|
||||
|
||||
if (typeof dataItem === 'object') {
|
||||
sortItem = {
|
||||
...sortData[sortKey]
|
||||
}
|
||||
} else {
|
||||
sortItem[realNameMap.realValue] = dataItem
|
||||
}
|
||||
sortItem[key] = sortData[key] || sortKey
|
||||
setIndex(sortItem, key, maxNumberLength, indexArr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return sortData
|
||||
}
|
||||
|
||||
return returnType === 'array' ? sortArray(indexArr) : arrayToObject(sortArray(indexArr), key)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定条件搜索模块列表,并排序与生成必要字段
|
||||
* @private
|
||||
* @param {Function} filterIntercept 搜索条件
|
||||
* @param {Boolean} isSort 是否需要排序
|
||||
*/
|
||||
const getSortModules = ({ filterIntercept, isSort = true }) => {
|
||||
let modules = []
|
||||
let componentCount = 0
|
||||
if (typeof filterIntercept === 'function') {
|
||||
Object.keys(moduleMap).forEach((key) => {
|
||||
const component = moduleMap[key]
|
||||
component.name = key
|
||||
if (filterIntercept(component) === true && component.exclude !== true) {
|
||||
const dirs = component.path.split('/')
|
||||
const componentName = dirs.slice(1, dirs.indexOf('src'))
|
||||
component.UpperName = componentName.pop().split('-').map(capitalize).join('')
|
||||
component.LowerName = kebabCase({ str: component.UpperName })
|
||||
// 工程的父文件夹
|
||||
component.parentDir = componentName
|
||||
// libPath: 'packages/todo/dist/pc.js' 组件输出路径
|
||||
component.libPath = component.path.replace('/index.js', '/src/index.js').replace('/src/', '/dist/lib/').replace('.vue', '.js')
|
||||
// libName: '@opentiny/vue/todo/pc'
|
||||
component.libName = component.libPath
|
||||
.replace('packages/', '')
|
||||
.replace('/index', '')
|
||||
.replace('.js', '')
|
||||
.replace('/dist/', '/')
|
||||
.replace(/\/lib$/, '')
|
||||
// 处理子目录
|
||||
if (componentName.length) {
|
||||
component.libName = component.libName.replace(componentName.join('/'), '').replace(/^\//, '')
|
||||
}
|
||||
// importName: '@opentiny/vue-tag/pc'
|
||||
component.importName = importName + '-' + component.libName
|
||||
// libName: '@opentiny/vue/todo/pc'
|
||||
component.libName = importName + '/' + component.libName
|
||||
// tmpName: 'pc'
|
||||
component.tmpName = component.libPath.replace('.js', '').split('/').slice(-1)[0]
|
||||
// global: 'TinyTodoPc'
|
||||
component.global = 'Tiny' + key
|
||||
modules.push(component)
|
||||
}
|
||||
component.type === 'component' && componentCount++
|
||||
})
|
||||
logGreen(`[Contain Components]: Total(${componentCount}) `)
|
||||
} else {
|
||||
modules = moduleMap
|
||||
}
|
||||
return isSort ? quickSort({ sortData: modules }) : modules
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有模块,并排序、格式化
|
||||
* @param {Boolean} isSort 是否需要排序
|
||||
* @returns 模块对象
|
||||
*/
|
||||
const getAllModules = (isSort) => getSortModules({ filterIntercept: () => true, isSort })
|
||||
|
||||
/**
|
||||
* 获取所有组件,并排序、格式化
|
||||
* @param {Boolean} isSort 是否需要排序
|
||||
* @returns 组件对象
|
||||
*/
|
||||
const getComponents = (isSort) =>
|
||||
getSortModules({
|
||||
filterIntercept: (item) => !['template'].includes(item.type),
|
||||
isSort
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {String} key 根据模块对象的 Key 获取对应的值
|
||||
* @returns 模块对象
|
||||
*/
|
||||
const getModuleInfo = (key) => moduleMap[key] || {}
|
||||
|
||||
/**
|
||||
* 将输入的 Map 写入到 modules.json 文件中,并格式化
|
||||
* @param {String|Object} moduleMap 模块 Json 对象集合或 Json 字符串
|
||||
*/
|
||||
const writeModuleMap = (moduleMap) => {
|
||||
writeFileSync(
|
||||
pathJoin('..', 'modules.json'),
|
||||
prettierFormat({
|
||||
str: typeof componentMap === 'string' ? moduleMap : JSON.stringify(moduleMap),
|
||||
options: {
|
||||
parser: 'json',
|
||||
printWidth: 10
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 modules.json 中的模块信息
|
||||
* @returns 模块对象
|
||||
*/
|
||||
const readModuleMap = () => moduleMap || {}
|
||||
|
||||
/**
|
||||
* 获取模块项的模块
|
||||
* @param {String} componentName 组件名称(大写,例如:ImgPreview)
|
||||
* @param {String} templateName 模板名称/路径
|
||||
* @param {Oject} newObj 新增对象
|
||||
* @returns 模块对象
|
||||
*/
|
||||
const addModule = ({ componentName, templateName, newObj = {} }) => {
|
||||
const isEntry = templateName.endsWith('index')
|
||||
|
||||
return {
|
||||
path: `packages/${componentName}/` + (isEntry ? `${templateName}.js` : `src/${templateName}.vue`),
|
||||
type: isEntry ? 'component' : 'template',
|
||||
exclude: false,
|
||||
...newObj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定条件搜索原始模块列表
|
||||
* @private
|
||||
* @param {Function} filterIntercept 搜索条件
|
||||
*/
|
||||
const getModules = (filterIntercept) => {
|
||||
let modules = {}
|
||||
|
||||
if (typeof filterIntercept === 'function') {
|
||||
for (const key in moduleMap) {
|
||||
if (Object.prototype.hasOwnProperty.call(moduleMap, key)) {
|
||||
const component = moduleMap[key]
|
||||
|
||||
if (filterIntercept(component) === true && component.exclude !== true) {
|
||||
modules[key] = component
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modules = moduleMap
|
||||
}
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据组件名称查找模块列表
|
||||
* @private
|
||||
* @param {String} name 组件名称
|
||||
* @param {Boolean} inversion 是否取反
|
||||
* @param {Boolean} isOriginal 是否取原始数据
|
||||
* @param {Boolean} isSort 是否需要排序
|
||||
*/
|
||||
const getByName = ({ name, inversion = false, isOriginal = false, isSort = true }) => {
|
||||
const callback = (item) => (inversion ? item.path.indexOf(`/${name}/`) === -1 : item.path.indexOf(`/${name}/`) > -1)
|
||||
|
||||
return isOriginal ? getModules(callback) : getSortModules({ filterIntercept: callback, isSort })
|
||||
}
|
||||
|
||||
const getMobileComponents = () => {
|
||||
const modules = getAllModules()
|
||||
const componentNames = modules.filter((item) => item.tmpName === 'mobile').map((item) => item.UpperName)
|
||||
|
||||
const components = modules.filter(
|
||||
(item) => item.onlyMode === 'mobile' || item.onlyMode === 'all' || (item.type === 'component' && componentNames.includes(item.UpperName))
|
||||
)
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
const getPcComponents = () => {
|
||||
const modules = getAllModules()
|
||||
|
||||
const components = modules.filter((item) => item.type === 'component' && item.onlyMode !== 'mobile')
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
const getOnlyMobileComponents = () => getAllModules().filter((item) => item.onlyMode === 'mobile')
|
||||
|
||||
/**
|
||||
* 动态创建 modules.json ,适配新建组件
|
||||
* @param {String} componentName 组件名称 (驼峰大写:img-preview)
|
||||
* @param {Boolean} isMobile 是否为移动组件
|
||||
*/
|
||||
const createModuleMapping = (componentName, templateName, isMobile = false) => {
|
||||
const upperName = capitalizeKebabCase(componentName)
|
||||
|
||||
// 生成 modules.json 文件
|
||||
moduleMap[upperName] = addModule({
|
||||
isMobile,
|
||||
templateName,
|
||||
componentName
|
||||
})
|
||||
|
||||
const moduleJson = quickSort({ sortData: moduleMap, returnType: 'object' })
|
||||
|
||||
writeFileSync(
|
||||
pathJoin('..', 'modules.json'),
|
||||
prettierFormat({
|
||||
str: JSON.stringify(moduleJson),
|
||||
options: {
|
||||
parser: 'json',
|
||||
printWidth: 10
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
quickSort,
|
||||
getByName,
|
||||
addModule,
|
||||
importName,
|
||||
exampleBase,
|
||||
defaultMode,
|
||||
createModuleMapping,
|
||||
isPcComponent,
|
||||
getAllModules,
|
||||
getComponents,
|
||||
getModuleInfo,
|
||||
readModuleMap,
|
||||
writeModuleMap,
|
||||
getPcComponents,
|
||||
isMobileComponent,
|
||||
getMobileComponents,
|
||||
getOnlyMobileComponents,
|
||||
getNoTemplateComponents
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/**
|
||||
* 用于发布单组件包
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
const utils = require('./utils')
|
||||
const { logGreen } = require('./utils')
|
||||
|
||||
const sourcePkg = 'packages'
|
||||
const packages = 'dist'
|
||||
const tgzs = 'tgzs'
|
||||
const packageName = 'package.json'
|
||||
const NPM_TAG = process.env.NPM_TAG || '~0.1.0'
|
||||
const VERSION_TAG = process.env.VERSION_TAG || '0.1.0'
|
||||
const NPM_WAREHOUSE = process.env.NPM_WAREHOUSE
|
||||
const targetVersion = utils.getTinyVersion('themeVersion')
|
||||
const targetVersionArr = targetVersion.split('.')
|
||||
const themeVersionDependencies = `~${targetVersionArr[0]}.${targetVersionArr[1]}.0`
|
||||
|
||||
const packPackages = (p, packagePath) => {
|
||||
execSync('npm pack -q', { cwd: path.join(packages, p) })
|
||||
fs.readdirSync(path.join(packages, p)).forEach((item) => {
|
||||
if (item.endsWith('.tgz')) {
|
||||
const tgzPath = path.join(packages, p, item)
|
||||
fs.moveSync(tgzPath, path.join(tgzs, item), { overwrite: true })
|
||||
fs.unlinkSync(packagePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理每个组件包的package.json文件
|
||||
const dealPackage = (p, packageJSON) => {
|
||||
const packageDeps = packageJSON.dependencies || []
|
||||
Object.keys(packageDeps).forEach((key) => {
|
||||
if (key.includes('@opentiny/vue')) {
|
||||
packageDeps[key] = NPM_TAG
|
||||
}
|
||||
})
|
||||
let dependencies = {
|
||||
'@opentiny/vue-renderless': themeVersionDependencies,
|
||||
'@opentiny/vue-common': NPM_TAG,
|
||||
'@opentiny/vue-icon': NPM_TAG,
|
||||
'@opentiny/vue-theme': themeVersionDependencies,
|
||||
'@opentiny/vue-theme-mobile': themeVersionDependencies
|
||||
}
|
||||
if (p === 'icon') {
|
||||
packageJSON.dependencies = Object.assign(packageJSON.dependencies || {}, {
|
||||
'@opentiny/vue-common': NPM_TAG,
|
||||
'@opentiny/vue-theme': themeVersionDependencies
|
||||
})
|
||||
} else if (p === 'locale') {
|
||||
dependencies = {
|
||||
'@opentiny/vue-renderless': themeVersionDependencies
|
||||
}
|
||||
} else if (p === 'common') {
|
||||
dependencies = {
|
||||
'@opentiny/vue-renderless': themeVersionDependencies,
|
||||
'@opentiny/vue-theme': themeVersionDependencies
|
||||
}
|
||||
if (VERSION_TAG.startsWith('2')) {
|
||||
dependencies['@vue/composition-api'] = '1.2.2'
|
||||
}
|
||||
}
|
||||
packageJSON.dependencies = Object.assign(packageJSON.dependencies || {}, dependencies)
|
||||
packageJSON.sideEffects = false
|
||||
packageJSON.version = VERSION_TAG
|
||||
}
|
||||
|
||||
const release = (p) => {
|
||||
const packagePath = path.join(packages, p, packageName)
|
||||
const packageJSON = fs.readJSONSync(packagePath)
|
||||
const componentEntry = path.join(packagePath, '../lib', 'index.js')
|
||||
dealPackage(p, packageJSON)
|
||||
fs.writeFileSync(packagePath, JSON.stringify(packageJSON, null, 2))
|
||||
if (fs.existsSync(componentEntry)) {
|
||||
let componentEntryContent = fs.readFileSync(componentEntry).toString('UTF-8')
|
||||
componentEntryContent = componentEntryContent.replace('process.env.COMPONENT_VERSION', `'${VERSION_TAG}'`)
|
||||
fs.writeFileSync(componentEntry, componentEntryContent)
|
||||
}
|
||||
logGreen(`${p} pack done`)
|
||||
|
||||
// 测试情况下可以打包成压缩包
|
||||
if (NPM_WAREHOUSE === 'test') {
|
||||
packPackages(p, packagePath)
|
||||
}
|
||||
}
|
||||
|
||||
const dealFile = (componentDir, distDir) => {
|
||||
if (componentDir.includes('common')) {
|
||||
// 如果是vue3.0的打包命令下
|
||||
if (VERSION_TAG.startsWith('3')) {
|
||||
// 删除 vue2.0文件
|
||||
fs.removeSync(path.join(distDir, 'adapter/vue2.js'))
|
||||
// 重写adapter/index.js
|
||||
fs.copySync(path.join(__dirname, '../', 'template/common/vue3.js'), path.join(distDir, 'adapter/index.js'))
|
||||
} else {
|
||||
// 删除 vue3.0文件
|
||||
fs.removeSync(path.join(distDir, 'adapter/vue3.js'))
|
||||
// 重写adapter/index.js
|
||||
fs.copySync(path.join(__dirname, '../', 'template/common/vue2.js'), path.join(distDir, 'adapter/index.js'))
|
||||
}
|
||||
} else if (componentDir.includes('locale')) {
|
||||
// 如果是vue3.0的打包命令下
|
||||
if (VERSION_TAG.startsWith('3')) {
|
||||
// 删除 vue2.0文件
|
||||
fs.removeSync(path.join(distDir, 'vue2.js'))
|
||||
// 重写index.js
|
||||
fs.copySync(path.join(__dirname, '../', 'template/locale/vue3.js'), path.join(distDir, 'index.js'))
|
||||
} else {
|
||||
// 删除 vue3.0文件
|
||||
fs.removeSync(path.join(distDir, 'vue3.js'))
|
||||
// 重写index.js
|
||||
fs.copySync(path.join(__dirname, '../', 'template/locale/vue2.js'), path.join(distDir, 'index.js'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 读取packages文件夹下的所有组件,并执行copy操作
|
||||
const releaseAll = () => {
|
||||
fs.readdirSync(path.join(sourcePkg)).forEach((item) => {
|
||||
const componentDir = path.join(sourcePkg, item)
|
||||
const stat = fs.statSync(componentDir)
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const distPath = path.join(sourcePkg, item, packages)
|
||||
const packageJson = path.join(sourcePkg, item, packageName)
|
||||
|
||||
if (fs.existsSync(distPath)) {
|
||||
fs.copySync(distPath, path.join(packages, item), {
|
||||
overwrite: true
|
||||
})
|
||||
fs.copySync(packageJson, path.join(packages, item, packageName), {
|
||||
overwrite: true
|
||||
})
|
||||
} else {
|
||||
fs.copySync(componentDir, path.join(packages, item), {
|
||||
overwrite: true
|
||||
})
|
||||
|
||||
// 处理common和locale包,分别针对vue2和vue3
|
||||
dealFile(componentDir, path.join(packages, item))
|
||||
}
|
||||
|
||||
release(item)
|
||||
}
|
||||
})
|
||||
|
||||
logGreen('-- all release done --')
|
||||
}
|
||||
|
||||
releaseAll()
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* 用于发布 @opentiny/vue 包
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const semver = require('semver')
|
||||
const { execSync } = require('child_process')
|
||||
const sourcePkg = 'packages'
|
||||
const source = 'dist'
|
||||
const packageName = 'package.json'
|
||||
const packagePath = path.join(source, packageName)
|
||||
const packageJSON = fs.readJSONSync(packageName)
|
||||
|
||||
const keys = ['name', 'version', 'description', 'main', 'files', 'sideEffects', 'author', 'license', 'repository', 'dependencies', 'engines', 'browserslist']
|
||||
|
||||
const allDist = 'allDist'
|
||||
const toOneZip = process.env.tiny_mode === 'pc'
|
||||
const NPM_TAG = process.env.NPM_TAG
|
||||
// 命令行中指定的版本号
|
||||
const VERSION_TAG = process.env.VERSION_TAG
|
||||
const NPM_WAREHOUSE = process.env.NPM_WAREHOUSE
|
||||
|
||||
for (let key in packageJSON) {
|
||||
if (Object.prototype.hasOwnProperty.call(packageJSON, key)) {
|
||||
!~keys.indexOf(key) && delete packageJSON[key]
|
||||
}
|
||||
}
|
||||
|
||||
// 配置指定的版本号
|
||||
if (VERSION_TAG) {
|
||||
packageJSON.version = VERSION_TAG
|
||||
}
|
||||
|
||||
// 根据modules.json生成所有组件列表信息
|
||||
const genDependencies = () => {
|
||||
const { getComponents } = require('./module-utils')
|
||||
let dependencies = {}
|
||||
|
||||
getComponents(false).forEach((component) => {
|
||||
const packPath = component.path.replace(/index\.js$/, 'package.json')
|
||||
|
||||
if (!fs.existsSync(packPath)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (NPM_TAG) {
|
||||
dependencies[component.importName] = NPM_TAG
|
||||
} else {
|
||||
let { version } = fs.readJSONSync(packPath)
|
||||
|
||||
if (version) {
|
||||
const major = semver.major(version)
|
||||
const minor = semver.minor(version)
|
||||
|
||||
version = `${major}.${minor}.0`
|
||||
dependencies[component.importName] = '~' + version
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return dependencies
|
||||
}
|
||||
|
||||
// 根据组件列表信息重新package.json的dependencies信息
|
||||
packageJSON.dependencies = Object.assign(packageJSON.dependencies || {}, genDependencies())
|
||||
|
||||
fs.writeFileSync(packagePath, JSON.stringify(packageJSON, null, 2))
|
||||
fs.copySync(packagePath, path.join(source, 'vue', packageName), {
|
||||
overwrite: true
|
||||
})
|
||||
|
||||
if (toOneZip) {
|
||||
const vuePackage = path.join(allDist, 'vue')
|
||||
|
||||
if (!fs.existsSync(allDist)) {
|
||||
fs.mkdirSync(allDist)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(vuePackage)) {
|
||||
fs.mkdirSync(vuePackage)
|
||||
}
|
||||
|
||||
fs.copyFileSync(packageName, path.join(vuePackage, packageName))
|
||||
|
||||
fs.readdirSync(source).forEach((item) => {
|
||||
const stat = fs.statSync(path.join(source, item))
|
||||
|
||||
if (!stat.isDirectory()) {
|
||||
fs.copyFileSync(path.join(source, item), path.join(vuePackage, item))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const entrys = ['pc.js', 'mobile.js', 'index.js']
|
||||
|
||||
entrys.forEach((name) => {
|
||||
fs.copyFileSync(path.join(sourcePkg, name), path.join(source, name))
|
||||
fs.copySync(path.join(sourcePkg, name), path.join(source, 'vue', name), {
|
||||
overwrite: true
|
||||
})
|
||||
})
|
||||
// 只有在发布npm测试仓库的时候才执行以下压缩包的逻辑
|
||||
if (NPM_WAREHOUSE === 'test') {
|
||||
execSync('npm pack', { cwd: source })
|
||||
|
||||
fs.readdirSync(source).forEach((item) => {
|
||||
if (item.endsWith('.tgz')) {
|
||||
const tgzPath = path.join(source, item)
|
||||
|
||||
fs.moveSync(tgzPath, path.join('tgzs', item), { overwrite: true })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
/**
|
||||
* 打包运行时通用配置
|
||||
*
|
||||
* 全量运行时(组件分组)
|
||||
* 运行时版本号
|
||||
* 运行时外部依赖路径
|
||||
*/
|
||||
const fs = require('fs-extra')
|
||||
const { getVersion, pathJoin, logRed } = require('./utils')
|
||||
const moduleUtils = require('./module-utils')
|
||||
|
||||
const runtimeComponents = {
|
||||
core: [
|
||||
'Common',
|
||||
'Icon',
|
||||
'Locale',
|
||||
'Alert',
|
||||
'Col',
|
||||
'Container',
|
||||
'DialogBox',
|
||||
'Layout',
|
||||
'Loading',
|
||||
'Popover',
|
||||
'Row',
|
||||
'Tooltip',
|
||||
'Carousel',
|
||||
'CarouselItem',
|
||||
'Collapse',
|
||||
'CollapseItem',
|
||||
'Split',
|
||||
'TimeLine',
|
||||
'Milestone',
|
||||
'Floatbar',
|
||||
'Steps',
|
||||
'TabItem',
|
||||
'Tabs',
|
||||
'Breadcrumb',
|
||||
'BreadcrumbItem',
|
||||
'FallMenu',
|
||||
'NavMenu',
|
||||
'Rate',
|
||||
'Tag',
|
||||
'TopBox',
|
||||
'Notify',
|
||||
'Image',
|
||||
'ImageViewer',
|
||||
'ScrollText',
|
||||
'Scrollbar',
|
||||
'UserHead',
|
||||
'SlideBar',
|
||||
'Slider',
|
||||
'Link',
|
||||
'Progress',
|
||||
'Crop'
|
||||
],
|
||||
base: [
|
||||
'Autocomplete',
|
||||
'BulletinBoard',
|
||||
'Button',
|
||||
'ButtonGroup',
|
||||
'Calendar',
|
||||
'Cascader',
|
||||
'CascaderMenu',
|
||||
'CascaderNode',
|
||||
'CascaderPanel',
|
||||
'Checkbox',
|
||||
'CheckboxButton',
|
||||
'CheckboxGroup',
|
||||
'DatePanel',
|
||||
'DatePicker',
|
||||
'DateRange',
|
||||
'DateTable',
|
||||
'DetailPage',
|
||||
'DropTimes',
|
||||
'FileUpload',
|
||||
'Form',
|
||||
'FormItem',
|
||||
'Grid',
|
||||
'GridColumn',
|
||||
'GridManager',
|
||||
'GridToolbar',
|
||||
'Input',
|
||||
'IpAddress',
|
||||
'LinkMenu',
|
||||
'Modal',
|
||||
'MonthRange',
|
||||
'MonthTable',
|
||||
'Numeric',
|
||||
'Option',
|
||||
'OptionGroup',
|
||||
'Pager',
|
||||
'PagerItem',
|
||||
'Picker',
|
||||
'PopUpload',
|
||||
'Popeditor',
|
||||
'Radio',
|
||||
'RadioButton',
|
||||
'RadioGroup',
|
||||
'Search',
|
||||
'Select',
|
||||
'SelectDropdown',
|
||||
'Switch',
|
||||
'Table',
|
||||
'TextPopup',
|
||||
'Time',
|
||||
'TimePanel',
|
||||
'TimePicker',
|
||||
'TimeRange',
|
||||
'TimeSelect',
|
||||
'TimeSpinner',
|
||||
'ToggleMenu',
|
||||
'Transfer',
|
||||
'TransferPanel',
|
||||
'Tree',
|
||||
'TreeMenu',
|
||||
'Upload',
|
||||
'UploadDragger',
|
||||
'UploadList',
|
||||
'YearTable'
|
||||
],
|
||||
business: ['UserContact', 'Wizard'],
|
||||
chart: [
|
||||
'BaiduMap',
|
||||
'ChartBar',
|
||||
'ChartCandle',
|
||||
'ChartCore',
|
||||
'ChartFunnel',
|
||||
'ChartGauge',
|
||||
'ChartWaterfall',
|
||||
'ChartGraph',
|
||||
'ChartHeatmap',
|
||||
'ChartHistogram',
|
||||
'ChartLine',
|
||||
'ChartMap',
|
||||
'ChartPie',
|
||||
'ChartRadar',
|
||||
'ChartRing',
|
||||
'ChartSankey',
|
||||
'ChartScatter',
|
||||
'ChartSunburst',
|
||||
'ChartTree',
|
||||
'Chart',
|
||||
'ChartBoxplot'
|
||||
],
|
||||
external: [
|
||||
'CardTemplate',
|
||||
'CreditCard',
|
||||
'CreditCardForm',
|
||||
'SvgIcon',
|
||||
'AutonaviMap',
|
||||
'ChartWordcloud',
|
||||
'ChartLiquidfill'
|
||||
]
|
||||
}
|
||||
|
||||
const echartsVersion = getVersion('echarts')
|
||||
const auroraVueVersion = getVersion('@opentiny/vue')
|
||||
const echartsSource = 'lib/echarts.min.js' + echartsVersion
|
||||
const dependencies = {
|
||||
vue: 'node_modules/vue/dist/vue.min.js',
|
||||
'vue-i18n': 'node_modules/vue-i18n/dist/vue-i18n.min.js',
|
||||
axios: 'node_modules/axios/dist/axios.min.js',
|
||||
'axios-mock-adapter':
|
||||
'node_modules/axios-mock-adapter/dist/axios-mock-adapter.min.js',
|
||||
'@vue/composition-api':
|
||||
'node_modules/@vue/composition-api/dist/vue-composition-api.prod.js',
|
||||
'@aurora/core': 'node_modules/@aurora/core/dist/aurora.min.js',
|
||||
'@aurora/service': 'node_modules/@aurora/service/dist/aurora.service.min.js',
|
||||
cropperjs: 'node_modules/cropperjs/dist/cropper.min.js',
|
||||
vue3: 'example/node_modules/vue/dist/vue.global.prod.js',
|
||||
'vue3-i18n': 'example/node_modules/vue-i18n/dist/vue-i18n.global.js'
|
||||
}
|
||||
|
||||
const runtimeDeps = {
|
||||
base: {
|
||||
vue: 'lib/vue.min.js' + getVersion('vue'),
|
||||
axios: 'lib/axios.min.js' + getVersion('axios'),
|
||||
'vue-i18n': 'lib/vue-i18n.min.js' + getVersion('vue-i18n'),
|
||||
'axios-mock-adapter':
|
||||
'lib/axios-mock-adapter.min.js' + getVersion('axios-mock-adapter')
|
||||
},
|
||||
aurora: {
|
||||
'@aurora/core': 'lib/aurora.min.js' + getVersion('@aurora/core'),
|
||||
'@aurora/service':
|
||||
'lib/aurora.service.min.js' + getVersion('@aurora/service')
|
||||
},
|
||||
aui3Lib: {
|
||||
'@vue/composition-api':
|
||||
'lib/vue-composition-api.prod.js' + getVersion('@vue/composition-api'),
|
||||
echarts: echartsSource,
|
||||
'echarts/lib/echarts': echartsSource,
|
||||
'echarts/lib/chart/bar': echartsSource,
|
||||
'echarts/lib/chart/boxplot': echartsSource,
|
||||
'echarts/lib/chart/candlestick': echartsSource,
|
||||
'echarts/lib/chart/chord': echartsSource,
|
||||
'echarts/lib/chart/custom': echartsSource,
|
||||
'echarts/lib/chart/effectScatter': echartsSource,
|
||||
'echarts/lib/chart/funnel': echartsSource,
|
||||
'echarts/lib/chart/gauge': echartsSource,
|
||||
'echarts/lib/chart/graph': echartsSource,
|
||||
'echarts/lib/chart/heatmap': echartsSource,
|
||||
'echarts/lib/chart/line': echartsSource,
|
||||
'echarts/lib/chart/lines': echartsSource,
|
||||
'echarts/lib/chart/map': echartsSource,
|
||||
'echarts/lib/chart/parallel': echartsSource,
|
||||
'echarts/lib/chart/pictorialBar': echartsSource,
|
||||
'echarts/lib/chart/pie': echartsSource,
|
||||
'echarts/lib/chart/radar': echartsSource,
|
||||
'echarts/lib/chart/sankey': echartsSource,
|
||||
'echarts/lib/chart/scatter': echartsSource,
|
||||
'echarts/lib/chart/sunburst': echartsSource,
|
||||
'echarts/lib/chart/themeRiver': echartsSource,
|
||||
'echarts/lib/chart/tree': echartsSource,
|
||||
'echarts/lib/chart/treemap': echartsSource,
|
||||
'echarts/lib/component/legend': echartsSource,
|
||||
'echarts/lib/component/tooltip': echartsSource,
|
||||
'echarts/lib/component/dataZoom': echartsSource,
|
||||
'echarts/lib/component/visualMap': echartsSource,
|
||||
cropperjs: 'lib/cropper.min.js' + getVersion('cropperjs'),
|
||||
'@opentiny/vue-renderless-common':
|
||||
'aui/common/renderless.js' +
|
||||
getVersion('@opentiny/vue-renderless')
|
||||
},
|
||||
aui3Component: {
|
||||
'@opentiny/vue-locale':
|
||||
'COMPONENT_DIR/locale.js' + auroraVueVersion,
|
||||
'@opentiny/vue-icon': 'COMPONENT_DIR/icon.js' + auroraVueVersion,
|
||||
'@opentiny/vue-common': 'COMPONENT_DIR/common.js' + auroraVueVersion
|
||||
}
|
||||
}
|
||||
|
||||
const getPartDeps = (keys = []) => {
|
||||
const tempDeps = {}
|
||||
|
||||
for (let key in runtimeDeps) {
|
||||
if (Object.prototype.hasOwnProperty.call(runtimeDeps, key)) {
|
||||
keys.includes(key) && Object.assign(tempDeps, runtimeDeps[key])
|
||||
}
|
||||
}
|
||||
|
||||
return tempDeps
|
||||
}
|
||||
|
||||
const getAllDeps = () => {
|
||||
return getPartDeps(Object.keys(runtimeDeps))
|
||||
}
|
||||
|
||||
const getAllComponents = () => {
|
||||
const componentMap = moduleUtils.getPcComponents(true)
|
||||
const systemMap = {}
|
||||
|
||||
for (let i = 0, len = componentMap.length; i < len; i++) {
|
||||
const libName = componentMap[i].LowerName
|
||||
const libEntry = componentMap[i].path
|
||||
let version = auroraVueVersion
|
||||
|
||||
try {
|
||||
version =
|
||||
'?v=' +
|
||||
require('../' +
|
||||
libEntry.replace('index.js', 'package.json')).version.replace(
|
||||
/[\^|~]/g,
|
||||
''
|
||||
)
|
||||
} catch (e) {
|
||||
logRed(e)
|
||||
}
|
||||
|
||||
systemMap[componentMap[i].importName] =
|
||||
'COMPONENT_DIR/' + libName + '.js' + version
|
||||
}
|
||||
|
||||
return systemMap
|
||||
}
|
||||
|
||||
const getFullRuntimeDeps = () => {
|
||||
return { ...getAllDeps(), ...getAllComponents() }
|
||||
}
|
||||
|
||||
const getComponentRuntimeDeps = () => {
|
||||
return {
|
||||
...getPartDeps(['theme', 'aui3Lib', 'aui3Component']),
|
||||
...getAllComponents()
|
||||
}
|
||||
}
|
||||
|
||||
const getFullRuntime = (name) => {
|
||||
const arr =
|
||||
typeof name === 'string' ? [name] : name || Object.keys(runtimeComponents)
|
||||
|
||||
return [].concat(...arr.map((key) => runtimeComponents[key]))
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 @opentiny/vue-renderless 中的公共代码,打成独立包(避免组件运行不正常)
|
||||
*/
|
||||
const getRenderlessExports = () => {
|
||||
const RENDERLESS_PATH = pathJoin(
|
||||
'..',
|
||||
'node_modules',
|
||||
'@aurora',
|
||||
'renderless',
|
||||
'common',
|
||||
'runtime.js'
|
||||
)
|
||||
|
||||
let EXTERNAL_RENDERLESS = []
|
||||
|
||||
// 获取需要排除的依赖
|
||||
if (fs.existsSync(RENDERLESS_PATH)) {
|
||||
const runtimeExport = fs.readFileSync(RENDERLESS_PATH).toString('UTF-8')
|
||||
|
||||
EXTERNAL_RENDERLESS = runtimeExport.match(/import(.*)from(.*)/g) || []
|
||||
|
||||
EXTERNAL_RENDERLESS = EXTERNAL_RENDERLESS.map((item) => {
|
||||
let moduleLine = item.replace(/^import\s+/g, '').split(/\s+from\s+/)
|
||||
|
||||
return {
|
||||
libraryName: moduleLine.pop().replace(/'/g, '').replace(';', ''),
|
||||
exportName: moduleLine.pop().split(/\s/).pop()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
EXTERNAL_RENDERLESS,
|
||||
RENDERLESS_PATH
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dependencies,
|
||||
getAllDeps,
|
||||
getPartDeps,
|
||||
getFullRuntime,
|
||||
getAllComponents,
|
||||
getFullRuntimeDeps,
|
||||
getRenderlessExports,
|
||||
getComponentRuntimeDeps,
|
||||
getExternalComponents: () => runtimeComponents.external
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* 初始化/创建 ICON 组件,从 @opentiny/vue-theme/svgs 中提取 SVG 图标创建对应的 ICON 组件
|
||||
*/
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const utils = require('./utils')
|
||||
const semver = require('semver')
|
||||
const { EOL } = require('os')
|
||||
|
||||
const svgRE = /\.svg$/
|
||||
const svgDir = utils.pathJoin('../../', 'vue-theme', 'theme', 'svgs')
|
||||
const iconDir = utils.pathJoin('..', 'packages', 'icon')
|
||||
const packageJson = 'package.json'
|
||||
const templatePath = utils.pathJoin('..', 'template')
|
||||
const render = utils.renderTemplate({ leftChar: '[[', rightChar: ']]' })
|
||||
|
||||
// 检查是否按照依赖包
|
||||
if (!fs.existsSync(svgDir)) {
|
||||
utils.logYellow('The @opentiny/vue-theme is not exist , please npm install @opentiny/vue-theme.')
|
||||
}
|
||||
|
||||
// 是否包含 package/icon 目录
|
||||
if (!fs.existsSync(iconDir)) {
|
||||
fs.mkdirSync(iconDir)
|
||||
|
||||
const version = utils.getTinyVersion()
|
||||
const iconTemplate = fs.readJSONSync(path.join(templatePath, 'component', packageJson))
|
||||
|
||||
// 删除多余的依赖
|
||||
if (iconTemplate.dependencies) {
|
||||
delete iconTemplate.dependencies['@opentiny/vue-renderless']
|
||||
}
|
||||
|
||||
const packageContent = render(JSON.stringify(iconTemplate), {
|
||||
NAME: 'icon',
|
||||
MINOR: semver.minor(version)
|
||||
})
|
||||
|
||||
fs.writeFileSync(path.join(iconDir, packageJson), packageContent)
|
||||
}
|
||||
|
||||
const exportComponents = []
|
||||
const exportIcons = []
|
||||
const componentTemplate = fs.readFileSync(path.join(templatePath, 'icon', 'index.js'), { encoding: 'utf8' })
|
||||
|
||||
// 根据 @opentiny/vue-theme/svgs 中的 svg 图片创建对应的 icon 组件
|
||||
fs.readdirSync(svgDir).forEach((fileName) => {
|
||||
if (svgRE.test(fileName)) {
|
||||
const svgName = fileName.replace(svgRE, '')
|
||||
const iconPath = path.join(iconDir, svgName)
|
||||
const iconName = utils.capitalizeKebabCase(svgName)
|
||||
const fullIconName = `Icon${iconName}`
|
||||
|
||||
if (!fs.existsSync(iconPath)) {
|
||||
fs.mkdirSync(iconPath)
|
||||
const iconEntryContent = render(componentTemplate, {
|
||||
CNAME: iconName,
|
||||
SNAME: fileName
|
||||
})
|
||||
|
||||
fs.writeFileSync(path.join(iconPath, 'index.js'), utils.prettierFormat({ str: iconEntryContent }))
|
||||
}
|
||||
exportComponents.push(`import ${fullIconName} from './${svgName}'`)
|
||||
exportIcons.push(fullIconName)
|
||||
}
|
||||
})
|
||||
|
||||
if (exportComponents.length) {
|
||||
fs.writeFileSync(
|
||||
path.join(iconDir, 'index.js'),
|
||||
utils.prettierFormat({
|
||||
str: `${exportComponents.join(EOL)}
|
||||
|
||||
export {
|
||||
${exportIcons.join(',' + EOL)}
|
||||
}
|
||||
|
||||
export default {
|
||||
${exportIcons.join(',' + EOL)}
|
||||
}
|
||||
`
|
||||
})
|
||||
)
|
||||
|
||||
utils.logGreen('npm run create:icon done.')
|
||||
} else {
|
||||
utils.logRed('npm run create:icon fail.')
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const { execSync } = require('child_process')
|
||||
const log = global.console
|
||||
|
||||
const logger = log.log
|
||||
|
||||
/**
|
||||
* 根据运行上下文获取路径(运行时打包用)
|
||||
* @returns 文件绝对路径
|
||||
*/
|
||||
const resolveCwd = (...args) => path.join(process.cwd(), ...args)
|
||||
|
||||
/**
|
||||
* 获取模板替换路径(动态)
|
||||
* @param {String} posixPath 路径
|
||||
* @returns 文件绝对路径
|
||||
*/
|
||||
const assetsPath = (posixPath) => path.posix.join('static', posixPath)
|
||||
|
||||
/**
|
||||
* 根据运行上下文获取,当前运行组件的名称
|
||||
* @returns 当前运行组件目录名称
|
||||
*/
|
||||
const getComponentName = () => process.cwd().split(path.sep).pop()
|
||||
|
||||
/**
|
||||
* 获取当前上下文的路径
|
||||
* @returns 文件绝对路径
|
||||
*/
|
||||
const pathJoin = (...args) => path.join(__dirname, ...args)
|
||||
|
||||
/**
|
||||
* 获取用户输入命令参数
|
||||
* @returns 参数数组
|
||||
*/
|
||||
const getInputCmd = () => {
|
||||
const args = []
|
||||
const argv = process.argv || []
|
||||
|
||||
argv.forEach((item) => {
|
||||
if (item.indexOf(path.sep) === -1) {
|
||||
args.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前执行 cli 命令的工具:node\npm\yarn
|
||||
* @returns node\npm\yarn
|
||||
*/
|
||||
const getCurrentCliTool = () => {
|
||||
const npmExecpaths = process.env.npm_execpaths
|
||||
|
||||
if (!npmExecpaths) {
|
||||
return 'node'
|
||||
}
|
||||
|
||||
return npmExecpaths.substring(npmExecpaths.lastIndexOf(path.sep) + 1).replace(/.js|-cli/g, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 node 命令
|
||||
* @param {String} cmdStr 命令字符串
|
||||
*/
|
||||
const execCmd = (cmdStr) => {
|
||||
cmdStr && execSync(cmdStr, { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 首字母大写
|
||||
* @param {String} str 字符串
|
||||
* @returns 字符串
|
||||
*/
|
||||
const capitalize = (str) => (typeof str === 'string' ? str.slice(0, 1).toUpperCase() + str.slice(1) : str)
|
||||
|
||||
/**
|
||||
* 首字母大写
|
||||
* @param {String} str 字符串
|
||||
* @returns 字符串
|
||||
*/
|
||||
const capitalizeKebabCase = (str, splitChar = '-') => (typeof str === 'string' ? str.split(splitChar).map(capitalize).join('') : str)
|
||||
|
||||
/**
|
||||
* @description 将驼峰字符串转化为以指定字符分割的小写字符串
|
||||
* @example kebabCase({ str : 'ImgPreviewItem' } )
|
||||
* @example 输出结果:img-preview-item
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param splitChar 分隔符
|
||||
*/
|
||||
const kebabCase = ({ str, splitChar = '-' }) => {
|
||||
if (!str || typeof str !== 'string') {
|
||||
return str
|
||||
}
|
||||
|
||||
return str
|
||||
.split('')
|
||||
.map((char, index) => {
|
||||
const charCod = char.charCodeAt(0)
|
||||
|
||||
if (charCod < 65 || charCod > 122) {
|
||||
return char
|
||||
}
|
||||
|
||||
return (charCod >= 65 && charCod) <= 90 ? (index === 0 ? '' : splitChar) + char.toLowerCase() : char
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 采用 prettier 美化字符串
|
||||
* @param {String} str 格式字符
|
||||
* @param {Object} options 格式字符
|
||||
*/
|
||||
const prettierFormat = ({ str, options = {} }) =>
|
||||
require('prettier').format(str, {
|
||||
printWidth: 100,
|
||||
jsxBracketSameLine: false,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
singleQuote: true,
|
||||
semi: false,
|
||||
trailingComma: 'none',
|
||||
bracketSpacing: true,
|
||||
parser: 'babel',
|
||||
...options
|
||||
})
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {String} path dotted to indicate levels in an object.
|
||||
* @param {Object} view for the data.
|
||||
*/
|
||||
function extractValue(path, view) {
|
||||
if (view && view[path]) {
|
||||
return view[path]
|
||||
}
|
||||
|
||||
const parts = path.split('.')
|
||||
let part = ''
|
||||
|
||||
while (view && (part = parts.shift())) {
|
||||
view = typeof view === 'object' && part in view ? view[part] : undefined
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染字符串模板
|
||||
* @param {String} leftChar 匹配左边字符
|
||||
* @param {String} rightChar 匹配右边字符
|
||||
*/
|
||||
const renderTemplate = ({ leftChar = '{{', rightChar = '}}' } = {}) => {
|
||||
const specialChar = ['[', ']']
|
||||
const _leftChar = leftChar.split('').map((item) => (specialChar.includes(item) ? '\\' : '') + item)
|
||||
|
||||
const _rightChar = rightChar.split('').map((item) => (specialChar.includes(item) ? '\\' : '') + item)
|
||||
|
||||
const REGEX = new RegExp(`${_leftChar.join('')}([a-zA-Z.-_0-9]+)${_rightChar.join('')}`, 'g')
|
||||
|
||||
return (input, view) => {
|
||||
if (input.indexOf(leftChar) === -1) {
|
||||
return input
|
||||
}
|
||||
|
||||
let result
|
||||
const replaced = input.replace(REGEX, (original, path) => {
|
||||
const value = extractValue(path, view)
|
||||
|
||||
if (undefined === value || value === null) {
|
||||
return original
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
result = value
|
||||
return
|
||||
}
|
||||
|
||||
return value
|
||||
})
|
||||
|
||||
return undefined === result ? replaced : result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描指定目录下面的组件目录
|
||||
* @param {String} dirPath 绝对路径
|
||||
* @param {Boolean} isDeep 是否深度遍历
|
||||
* @param {Function} fileFilter 文件筛选拦截函数
|
||||
* @param {Function} callback 遍历回调
|
||||
*/
|
||||
const walkFileTree = ({ dirPath, isDeep = false, fileFilter, callback }) => {
|
||||
if (!dirPath || typeof callback !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
const dirs = fs.readdirSync(path.isAbsolute(dirPath) ? dirPath : path.join(__dirname, dirPath))
|
||||
|
||||
if (Array.isArray(dirs) && dirs.length > 0) {
|
||||
dirs.forEach((file) => {
|
||||
let isFind = true
|
||||
const subPath = path.join(dirPath, file)
|
||||
const isDirectory = fs.statSync(subPath).isDirectory()
|
||||
|
||||
if (typeof fileFilter === 'function') {
|
||||
isFind = fileFilter({ file, subPath, dirs, isDirectory }) === true
|
||||
}
|
||||
|
||||
if (isFind && isDirectory) {
|
||||
if (isDeep) {
|
||||
walkFileTree({ isDeep, dirPath: subPath, fileFilter, callback })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
callback({ file, subPath, dirs, isDirectory })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根目录 package.json 中的 version
|
||||
* @param {String} 对象的 Key
|
||||
*/
|
||||
const getTinyVersion = (key = 'version') => {
|
||||
const packageJson = fs.readJsonSync(pathJoin('..', 'package.json'))
|
||||
|
||||
return packageJson[key] || packageJson
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定包名的版本号
|
||||
*
|
||||
* @param {String} name NPM 包名
|
||||
* @param {String} context 上下文
|
||||
* @returns
|
||||
*/
|
||||
const getVersion = (name, context = '..') => {
|
||||
let version
|
||||
const packageJSON = getTinyVersion('full')
|
||||
|
||||
try {
|
||||
version = fs.readJsonSync(pathJoin(context, 'node_modules', name, 'package.json')).version
|
||||
} catch (e) {
|
||||
version = (packageJSON.devDependencies || packageJSON.dependencies || {})[name] || packageJSON.version
|
||||
}
|
||||
|
||||
return '?v=' + version.replace(/[\^|~]/g, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 在控制台显示绿色提示
|
||||
* @param {String} 提示内容
|
||||
*/
|
||||
const logGreen = (str) => {
|
||||
logger(chalk.green('### ' + str))
|
||||
}
|
||||
|
||||
/**
|
||||
* 在控制台显示黄色提示
|
||||
* @param {String} 提示内容
|
||||
*/
|
||||
const logYellow = (str) => {
|
||||
logger(chalk.yellow('### ' + str))
|
||||
}
|
||||
|
||||
/**
|
||||
* 在控制台显示青色提示
|
||||
* @param {String} 提示内容
|
||||
*/
|
||||
const logCyan = (str) => {
|
||||
logger(chalk.cyan('### ' + str))
|
||||
}
|
||||
|
||||
/**
|
||||
* 在控制台显示红色提示
|
||||
* @param {String} 提示内容
|
||||
*/
|
||||
const logRed = (str) => {
|
||||
logger(chalk.red('### ' + str))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
logRed,
|
||||
execCmd,
|
||||
logCyan,
|
||||
pathJoin,
|
||||
logGreen,
|
||||
logYellow,
|
||||
kebabCase,
|
||||
assetsPath,
|
||||
capitalize,
|
||||
getVersion,
|
||||
resolveCwd,
|
||||
getInputCmd,
|
||||
walkFileTree,
|
||||
renderTemplate,
|
||||
prettierFormat,
|
||||
getTinyVersion,
|
||||
getComponentName,
|
||||
getCurrentCliTool,
|
||||
capitalizeKebabCase
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module.exports = { extends: ['@commitlint/config-conventional'] }
|
|
@ -0,0 +1,33 @@
|
|||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
|
||||
const ROOTPATH = path.join(__dirname, './')
|
||||
|
||||
const publish = () => {
|
||||
const publishDir = path.join(ROOTPATH, 'packages')
|
||||
fs.readdirSync(publishDir).forEach((item) => {
|
||||
const childPath = path.join(publishDir, item)
|
||||
const stat = fs.statSync(childPath)
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const distPath = path.join(childPath, './dist')
|
||||
if (fs.existsSync(distPath) && fs.statSync(distPath).isDirectory()) {
|
||||
fs.removeSync(distPath)
|
||||
}
|
||||
if (item.startsWith('chart')) {
|
||||
fs.readdirSync(childPath).forEach((value) => {
|
||||
const chartChildPath = path.join(childPath, value)
|
||||
const chartStat = fs.statSync(chartChildPath)
|
||||
if (value.includes('-') && chartStat.isDirectory()) {
|
||||
const distPath = path.join(chartChildPath, './dist')
|
||||
fs.existsSync(distPath) &&
|
||||
fs.statSync(distPath).isDirectory() &&
|
||||
fs.removeSync(distPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
publish()
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
const commonjs = require('@rollup/plugin-commonjs')
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve')
|
||||
const vue = require('rollup-plugin-vue')
|
||||
const { babel } = require('@rollup/plugin-babel')
|
||||
const { pathJoin, logGreen, logRed } = require('../../build/utils')
|
||||
const rollup = require('rollup')
|
||||
const svgVue = require('./rollup-vue3-svg')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
|
||||
const inputOptions = {
|
||||
plugins: [
|
||||
vue({
|
||||
css: true
|
||||
}),
|
||||
svgVue({}),
|
||||
nodeResolve(),
|
||||
babel({
|
||||
exclude: /node_modules/,
|
||||
babelrc: false,
|
||||
configFile: false, // 必须为 false 不然会取根文件的 babel.config.js 配置,产生一堆 runtime 代码
|
||||
babelHelpers: 'bundled',
|
||||
extensions: ['.js', '.vue'],
|
||||
presets: ['@babel/preset-env'],
|
||||
plugins: ['@babel/plugin-proposal-export-default-from', '@babel/plugin-proposal-export-namespace-from']
|
||||
}),
|
||||
// 如果打包文件中包含 jsx 语法, commonjs 必须放置在 babel 配置下面,否则会报错 PLUGIN_ERROR
|
||||
commonjs()
|
||||
]
|
||||
}
|
||||
|
||||
const outputOptions = {
|
||||
format: 'es',
|
||||
exports: 'named'
|
||||
}
|
||||
|
||||
const build = (icons) => {
|
||||
icons.forEach((itconComponent) => {
|
||||
const inputs3 = { ...inputOptions }
|
||||
|
||||
inputs3.input = pathJoin('..', 'packages', 'icon', itconComponent.path)
|
||||
|
||||
if (itconComponent.path === 'index.js') {
|
||||
inputs3.external = (deps) => !deps.includes('index.js')
|
||||
} else if (itconComponent.path === 'lowercase.js') {
|
||||
inputs3.external = (deps) => !deps.includes('lowercase.js')
|
||||
} else {
|
||||
inputs3.external = (deps) => !/@opentiny[\\/]vue-theme/.test(deps) && !deps.includes('index.js')
|
||||
}
|
||||
|
||||
rollup
|
||||
.rollup(inputs3)
|
||||
.then((bundle) => {
|
||||
const outs = { ...outputOptions }
|
||||
outs.file = pathJoin('..', 'packages', 'icon', itconComponent.libPath)
|
||||
bundle.write(outs)
|
||||
logGreen(`${itconComponent.path} compile icon done`)
|
||||
})
|
||||
.catch((e) => {
|
||||
logRed(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function createComponentMap(iconDir) {
|
||||
const components = []
|
||||
fs.readdirSync(iconDir).forEach((iconFile) => {
|
||||
if (['dist', 'runtime'].includes(iconFile)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (fs.statSync(path.join(iconDir, iconFile)).isDirectory()) {
|
||||
components.push({
|
||||
path: `${iconFile}/index.js`,
|
||||
libPath: `dist/lib/${iconFile}.js`
|
||||
})
|
||||
} else {
|
||||
iconFile.endsWith('.js') &&
|
||||
components.push({
|
||||
path: `${iconFile}`,
|
||||
libPath: `dist/lib/${iconFile}`
|
||||
})
|
||||
}
|
||||
})
|
||||
return components
|
||||
}
|
||||
|
||||
build(createComponentMap(pathJoin('..', 'packages', 'icon')))
|
|
@ -0,0 +1,107 @@
|
|||
const rollup = require('rollup')
|
||||
const replace = require('@rollup/plugin-replace')
|
||||
const { readJSONSync } = require('fs-extra')
|
||||
const utils = require('../../build/utils')
|
||||
const config = require('./config')
|
||||
const moduleUtils = require('../../build/module-utils')
|
||||
const fs = require('fs-extra')
|
||||
const isSingle = process.env.BUILD_TARGET === 'single'
|
||||
|
||||
const inputOptions = {
|
||||
plugins: config.plugins,
|
||||
external: config.external
|
||||
}
|
||||
|
||||
const outputOptions = {
|
||||
format: 'es',
|
||||
globals: config.globals,
|
||||
exports: 'named'
|
||||
}
|
||||
|
||||
const replaceConstant = {
|
||||
'process.env.BUILD_TARGET': JSON.stringify(process.env.BUILD_TARGET),
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
|
||||
}
|
||||
|
||||
if (process.env.TINY_MODE === 'pc') {
|
||||
outputOptions.format = 'umd'
|
||||
replaceConstant['process.env.TINY_MODE'] = JSON.stringify(process.env.tiny_mode)
|
||||
}
|
||||
|
||||
const build = ({ comp, callbackFn }) => {
|
||||
inputOptions.input = utils.pathJoin('..', comp.path)
|
||||
|
||||
inputOptions.plugins.push(replace(replaceConstant))
|
||||
rollup
|
||||
.rollup(inputOptions)
|
||||
.then((bundle) => {
|
||||
outputOptions.file = utils.pathJoin('..', comp.libPath)
|
||||
if (outputOptions.format === 'umd') {
|
||||
outputOptions.name = comp.global
|
||||
}
|
||||
bundle.write(outputOptions).finally(() => {
|
||||
const filePath = utils.pathJoin('..', comp.libPath)
|
||||
if (filePath.endsWith('index.js')) {
|
||||
const indexStr = fs.readFileSync(filePath).toString('UTF-8')
|
||||
const resStr = indexStr.replace('./src/pc', './pc').replace('./src/mobile', './mobile')
|
||||
fs.writeFileSync(filePath, resStr)
|
||||
}
|
||||
callbackFn()
|
||||
})
|
||||
})
|
||||
.catch((e) => {
|
||||
utils.logRed(e)
|
||||
callbackFn()
|
||||
})
|
||||
}
|
||||
|
||||
let componentsArr = []
|
||||
|
||||
const buildAll = (count = 0) => {
|
||||
let comp = componentsArr[count++]
|
||||
if (comp) {
|
||||
if (!isSingle) {
|
||||
comp.libPath = 'dist/' + comp.libName.replace('@opentiny/vue/', '')
|
||||
comp.libPath += (comp.type === 'component' ? '/index' : '') + '.js'
|
||||
}
|
||||
build({
|
||||
comp,
|
||||
callbackFn() {
|
||||
buildAll(count)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
utils.logGreen(`npm run build:ui${isSingle ? '-single' : ''} done.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (isSingle) {
|
||||
const inputNameArr = utils.getInputCmd()
|
||||
if (inputNameArr.length > 0) {
|
||||
inputNameArr.forEach((input) => {
|
||||
const activeComName = utils.kebabCase({ str: input })
|
||||
|
||||
if (activeComName) {
|
||||
componentsArr.push(
|
||||
...moduleUtils.getByName({
|
||||
name: activeComName,
|
||||
isSort: false
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const activeCompName = utils.getComponentName()
|
||||
componentsArr = moduleUtils.getByName({
|
||||
name: activeCompName,
|
||||
isSort: false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
componentsArr = moduleUtils.getAllModules(false)
|
||||
}
|
||||
if (componentsArr.length > 0) {
|
||||
buildAll()
|
||||
} else {
|
||||
utils.logYellow('please enter the component name after command.')
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
const fs = require('fs-extra')
|
||||
const { babel } = require('@rollup/plugin-babel')
|
||||
const vue = require('rollup-plugin-vue')
|
||||
const alias = require('@rollup/plugin-alias')
|
||||
const commonjs = require('@rollup/plugin-commonjs')
|
||||
const postcss = require('rollup-plugin-postcss')
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve')
|
||||
const { pathJoin } = require('../../build/utils')
|
||||
const { getAllModules } = require('../../build/module-utils')
|
||||
|
||||
const external = ['vue', './pc', './mobile', '@opentiny/vue-common', '@opentiny/vue-locale', '@vue/composition-api', '@opentiny/vue-renderless']
|
||||
|
||||
const globals = {
|
||||
vue: 'Vue',
|
||||
'@vue/composition-api': 'vueCompositionApi',
|
||||
'@opentiny/vue-locale': 'TinyVueLocale',
|
||||
'@opentiny/vue-common': 'TinyVueCommon',
|
||||
'@opentiny/vue-renderless': 'TinyRenderLess'
|
||||
}
|
||||
|
||||
const aliasList = {}
|
||||
const components = getAllModules(false)
|
||||
|
||||
components.forEach((itemComponent) => {
|
||||
aliasList[itemComponent.libName] = pathJoin(`../${itemComponent.path}`)
|
||||
|
||||
if (itemComponent.private) {
|
||||
return
|
||||
}
|
||||
|
||||
const isComponent = itemComponent.type === 'component'
|
||||
|
||||
external.push(itemComponent.importName)
|
||||
external.push(itemComponent.libName)
|
||||
globals[itemComponent.libName] = itemComponent.global // TinyTodo
|
||||
|
||||
if (isComponent) {
|
||||
if (fs.existsSync(pathJoin('../../tiny-vue-theme'))) {
|
||||
aliasList[`@opentiny/vue-theme/${itemComponent.LowerName}/index.css`] = pathJoin(`../../tiny-vue-theme/src/${itemComponent.LowerName}/index.css`)
|
||||
aliasList[`@opentiny/vue-theme/${itemComponent.LowerName}/index.js`] = pathJoin(`../../tiny-vue-theme/src/${itemComponent.LowerName}/index.js`)
|
||||
}
|
||||
external.push(`${itemComponent.libName}/index.js`)
|
||||
} else {
|
||||
external.push(`${itemComponent.libName}.js`)
|
||||
}
|
||||
})
|
||||
|
||||
exports.aliasList = aliasList
|
||||
|
||||
exports.external = (deps) => external.includes(deps) || /^@opentiny[\\/](vue-common|vue-renderless|vue-theme|vue-icon|cropperjs)/.test(deps)
|
||||
|
||||
exports.globalsMap = globals
|
||||
|
||||
const op = {
|
||||
resolve: ['.js', '.vue', '.css'],
|
||||
extract: false,
|
||||
css: true,
|
||||
extensions: ['.js', '.jsx', '.vue', '.css']
|
||||
}
|
||||
|
||||
exports.plugins = [
|
||||
alias({
|
||||
resolve: op.resolve,
|
||||
'@opentiny/vue-locale': pathJoin('../packages/locale/index'),
|
||||
'@opentiny/vue-common': pathJoin('../packages/common/index'),
|
||||
...aliasList
|
||||
}),
|
||||
postcss({
|
||||
extract: op.extract
|
||||
}),
|
||||
vue({
|
||||
css: op.css
|
||||
}),
|
||||
nodeResolve({
|
||||
extensions: op.extensions
|
||||
}),
|
||||
babel({
|
||||
configFile: false,
|
||||
babelrc: false,
|
||||
exclude: /node_modules/,
|
||||
comments: false,
|
||||
presets: ['@babel/preset-env'],
|
||||
babelHelpers: 'bundled',
|
||||
extensions: ['.js', '.vue', '.jsx'],
|
||||
plugins: ['@babel/plugin-syntax-dynamic-import', '@vue/babel-plugin-jsx']
|
||||
}),
|
||||
commonjs()
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
let compilerDom = require('@vue/compiler-dom')
|
||||
|
||||
function vue3SvgInline() {
|
||||
return {
|
||||
name: 'vue3SvgInline',
|
||||
|
||||
transform(source, id) {
|
||||
if (id.indexOf('vue-theme') === -1) {
|
||||
return null
|
||||
}
|
||||
const parsedSvg = source.match(/<svg([\s\S]*?)<\/svg>/)[0]
|
||||
const { code } = compilerDom.compile(parsedSvg, {
|
||||
mode: 'module'
|
||||
})
|
||||
|
||||
return `
|
||||
${code}
|
||||
export default {
|
||||
render
|
||||
}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = vue3SvgInline
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tiny Vue</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main3.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "vue-example",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"test": "vitest test",
|
||||
"build:icon3": "cross-env NODE_ENV=production node build/build-icon.js",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/babel-plugin-jsx": "^1.1.0",
|
||||
"rollup-plugin-postcss": "^2.0.3",
|
||||
"rollup-plugin-vue": "^6.0.0",
|
||||
"vue": "^3.2.11",
|
||||
"@vue/test-utils": "^2.0.0",
|
||||
"jsdom": "16.4.0",
|
||||
"vue-i18n": "^9.1.7",
|
||||
"vitest": "^0.22.1",
|
||||
"vue-router": "^4.0.11",
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"@vitejs/plugin-vue-jsx": "^2.0.0",
|
||||
"vite-plugin-markdown-vue": "^0.1.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {
|
||||
"no-debugger": "off"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 183 KiB |
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<link rel="icon" href="./favicon.ico" />
|
||||
<title> TinyVue </title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but TINY next - Originjs doesn't work properly without
|
||||
JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="head"></div>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 515 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 430 KiB |
After Width: | Height: | Size: 350 KiB |
After Width: | Height: | Size: 529 KiB |
After Width: | Height: | Size: 496 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 690 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 231 KiB |
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<router-view />
|
||||
</template>
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<div style="width: 870px">
|
||||
<component :is="template"></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from '@opentiny/vue-common'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
link: String
|
||||
},
|
||||
setup(props) {
|
||||
const mode = localStorage.getItem('vue-example-mode') || 'pc'
|
||||
|
||||
return {
|
||||
template: defineAsyncComponent(() => import(/* @vite-ignore */ `./demo/${mode}/${props.link}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,559 @@
|
|||
.hljs {
|
||||
margin: 12px 0 25px 0;
|
||||
}
|
||||
|
||||
.highlight .hljs {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #faffff;
|
||||
border-radius: 4px;
|
||||
padding: 1px 3px;
|
||||
font-family: Menlo, YaHei Consolas Hybrid, Consolas, Courier New, monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
background-image: none;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
color: var(--ti-common-color-line-active);
|
||||
}
|
||||
|
||||
input::-ms-clear,
|
||||
input::-ms-reveal {
|
||||
display: none;
|
||||
}
|
||||
.main-cnt {
|
||||
padding: 80px 0 40px;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
width: 1140px;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.page-container h2 {
|
||||
font-size: 28px;
|
||||
color: #1f2d3d;
|
||||
margin: 0;
|
||||
padding-bottom: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.page-container h2 + p {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.displaywrap .page-container h2 + p {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.page-container h3 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.page-container h2,
|
||||
.page-container h3,
|
||||
.page-container h4,
|
||||
.page-container h5 {
|
||||
font-weight: 400;
|
||||
color: #1f2f3d;
|
||||
}
|
||||
|
||||
.page-container h2 a,
|
||||
.page-container h3 a,
|
||||
.page-container h4 a,
|
||||
.page-container h5 a {
|
||||
float: left;
|
||||
margin-left: -20px;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.page-container h2 a:hover,
|
||||
.page-container h2:hover a,
|
||||
.page-container h3 a:hover,
|
||||
.page-container h3:hover a,
|
||||
.page-container h4 a:hover,
|
||||
.page-container h4:hover a,
|
||||
.page-container h5 a:hover,
|
||||
.page-container h5:hover a {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.page-container p {
|
||||
font-size: 16px;
|
||||
color: #5e6d82;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
|
||||
.page-container .tip {
|
||||
padding: 8px 16px;
|
||||
background-color: #ecf8ff;
|
||||
border-radius: 4px;
|
||||
border-left: 5px solid #50bfff;
|
||||
margin: 20px 0;
|
||||
font-size: 14px;
|
||||
color: #5e6d82;
|
||||
}
|
||||
|
||||
.page-container .tip .highlight-lines,
|
||||
.page-container .tip .line-numbers-wrapper {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.page-container .tip code {
|
||||
font-size: 14px;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.page-container .warn {
|
||||
padding: 8px 16px;
|
||||
background-color: #fffbe6;
|
||||
border-radius: 4px;
|
||||
border-left: 5px solid #ffd666;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.page-container .warn code {
|
||||
background-color: hsla(0, 0%, 100%, 0.7);
|
||||
color: #445368;
|
||||
}
|
||||
.page-container .error {
|
||||
padding: 8px 16px;
|
||||
background-color: #fff1f0;
|
||||
border-radius: 4px;
|
||||
border-left: 5px solid #ff7875;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.page-container .attach-icon .hae-icon.error,
|
||||
.page-container .attach-icon .hae-icon.warn {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.page-container .error code {
|
||||
background-color: hsla(0, 0%, 100%, 0.7);
|
||||
color: #445368;
|
||||
}
|
||||
|
||||
.page-container.academy-container {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left h2,
|
||||
.page-container.academy-container .main-left h2 + p {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left h2 {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left h3 {
|
||||
margin: 40px 0 20px 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left p > img,
|
||||
.page-container.academy-container .main-left img {
|
||||
max-width: 1200px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left code.hljs {
|
||||
max-width: 720px;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left hr {
|
||||
max-width: 1200px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left ul {
|
||||
list-style: disc inside;
|
||||
padding-left: 12px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left ul > li {
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left ul > li > p {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.page-container.academy-container .main-left ul > li > ul {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
/* vue-press */
|
||||
.content code {
|
||||
color: #476582;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0;
|
||||
font-size: 0.85em;
|
||||
background-color: rgba(27, 31, 35, 0.05);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.content code,
|
||||
.content pre,
|
||||
.content kbd,
|
||||
.content samp {
|
||||
font-family: 'source-code-pro', 'Menlo', 'Monaco', 'Consolas', 'Courier New',
|
||||
'monospace';
|
||||
}
|
||||
.custom-block .custom-block-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: -0.4rem;
|
||||
}
|
||||
|
||||
.page-container .content .table {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
margin: 10px 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.page-container .content .table th,
|
||||
.page-container .content .table td {
|
||||
color: #333;
|
||||
padding: 12px;
|
||||
border: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
.page-container .content .table th {
|
||||
background-color: #eee;
|
||||
}
|
||||
.page-container .content .table td:first-child {
|
||||
width: 15%;
|
||||
}
|
||||
.page-container .content blockquote {
|
||||
border-left: 4px solid var(--theme-color, #42b983);
|
||||
color: #858585;
|
||||
margin: 2em 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.demo-popover-class1 {
|
||||
background: #eee !important;
|
||||
}
|
||||
.demo-popover-class2 {
|
||||
background: #999 !important;
|
||||
}
|
||||
|
||||
/* hightline */
|
||||
.page-main.noborder .content > h2:first-of-type {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.page-main.noborder .content > p.overviewicon {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.page-main:not(.noborder) .content > h2 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content > h2:not(:first-of-type) {
|
||||
margin-top: 36px;
|
||||
}
|
||||
|
||||
.content .badge.warn {
|
||||
border-left: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.content > h2 {
|
||||
font-size: 1.65rem;
|
||||
padding-bottom: 0.3rem;
|
||||
margin-bottom: 16px;
|
||||
text-indent: -1px;
|
||||
}
|
||||
|
||||
.content > h3 {
|
||||
margin: 40px 0 20px 0;
|
||||
padding-bottom: 0.3rem;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
}
|
||||
|
||||
.content > h4 {
|
||||
font-size: 20px;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.content > p > code {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.content > p > strong {
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.content pre code {
|
||||
font-size: 14px;
|
||||
font-family: 'source-code-pro', 'Menlo', 'Monaco', 'Consolas', 'Courier New',
|
||||
'monospace';
|
||||
}
|
||||
|
||||
.content pre code.hljs {
|
||||
padding: 18px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.content .apiBox pre.preview-code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.content .visual-editor pre {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.content > ul > li {
|
||||
color: #5e6d82;
|
||||
}
|
||||
|
||||
.content .apiContainer ul,
|
||||
.content .visual-editor ul,
|
||||
.content .attrContainer ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content .float-css ul {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content .box_all ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.content .logBox ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.content ul ul {
|
||||
list-style-type: circle;
|
||||
}
|
||||
|
||||
.content .visual-editor ul {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.content .hae-carousel ul {
|
||||
padding: 0 4px;
|
||||
line-height: 1.42857143;
|
||||
font-family: Helvetica, Arial, 'microsoft yahei';
|
||||
}
|
||||
|
||||
.content a.hae-icon.outer-link:hover,
|
||||
.content p a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.content a.hae-icon.outer-link::after {
|
||||
content: '\E840';
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
position: relative;
|
||||
top: -6px;
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
.content > .custom-block > p {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.content div[class*='language-'] {
|
||||
position: relative;
|
||||
background-color: #282c34;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.custom-block.danger,
|
||||
.custom-block.tip,
|
||||
.custom-block.warning {
|
||||
padding: 0.1rem 1.5rem;
|
||||
border-left-width: 0.5rem;
|
||||
border-left-style: solid;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.content .custom-block.tip {
|
||||
background-color: #f3f5f7;
|
||||
border-color: #42b983;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.content .custom-block.warning {
|
||||
background-color: rgba(255, 229, 100, 0.3);
|
||||
border-color: #e7c000;
|
||||
color: #6b5900;
|
||||
}
|
||||
|
||||
.content .custom-block.warning .custom-block-title {
|
||||
color: #b29400;
|
||||
}
|
||||
|
||||
.content .custom-block.danger {
|
||||
background-color: #ffe6e6;
|
||||
border-color: #c00;
|
||||
color: #4d0000;
|
||||
}
|
||||
|
||||
.content .custom-block.danger .custom-block-title {
|
||||
color: #900;
|
||||
}
|
||||
|
||||
div[class*='language-'] .highlight-lines {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
padding-top: 1.3rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
div[class*='language-'] .highlight-lines .highlighted {
|
||||
background-color: rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
|
||||
div[class*='language-'] pre,
|
||||
div[class*='language-'] pre[class*='language-'] {
|
||||
background: transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.content pre,
|
||||
.content pre[class*='language-'] {
|
||||
line-height: 1.4;
|
||||
padding: 1.25rem 1.5rem;
|
||||
margin: 0.85rem 0;
|
||||
background-color: #282c34;
|
||||
border-radius: 6px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.content pre[class*='language-'] code,
|
||||
.content pre code {
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
line-height: 1.42857143;
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.builtin,
|
||||
.token.important,
|
||||
.token.keyword,
|
||||
.token.selector {
|
||||
color: #cc99cd;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.function,
|
||||
.token.number {
|
||||
color: #f08d49;
|
||||
}
|
||||
|
||||
.token.attr-value,
|
||||
.token.char,
|
||||
.token.regex,
|
||||
.token.string,
|
||||
.token.variable {
|
||||
color: #7ec699;
|
||||
}
|
||||
|
||||
.token.entity,
|
||||
.token.operator,
|
||||
.token.url {
|
||||
color: #67cdcc;
|
||||
}
|
||||
|
||||
.token.block-comment,
|
||||
.token.cdata,
|
||||
.token.comment,
|
||||
.token.doctype,
|
||||
.token.prolog {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.attr-name,
|
||||
.token.deleted,
|
||||
.token.namespace,
|
||||
.token.tag {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #6196cc;
|
||||
}
|
||||
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.property,
|
||||
.token.symbol {
|
||||
color: #f8c555;
|
||||
}
|
||||
|
||||
.token.bold,
|
||||
.token.important {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
.content .tiny-mobile-tabbar-demo {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.content .tiny-mobile-tabbar-demo .tiny-mobile-tabbar--fixed {
|
||||
position: absolute;
|
||||
}
|
||||
.content .tiny-mobile-dialog-box-demo {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
.content .tiny-mobile-dialog-box-demo .v-modal,
|
||||
.content .tiny-mobile-dialog-box__wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo {
|
||||
height: 610px;
|
||||
position: relative;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-wrap {
|
||||
height: auto;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-direction {
|
||||
height: 300px;
|
||||
top: 380px;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-filter {
|
||||
justify-content: left;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo .tiny-mobile-dropdown-item {
|
||||
position: absolute;
|
||||
width: 351px;
|
||||
left: 0;
|
||||
top: 42px !important;
|
||||
}
|
||||
.content
|
||||
.tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-direction
|
||||
.tiny-mobile-dropdown-item {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 648px;
|
||||
bottom: 0 !important;
|
||||
top: 40px !important;
|
||||
overflow: inherit;
|
||||
}
|
||||
.content
|
||||
.tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-direction
|
||||
.tiny-mobile-dropdown-item__content {
|
||||
position: relative;
|
||||
}
|
||||
.content
|
||||
.tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-wrap
|
||||
.tiny-mobile-dropdown-item {
|
||||
overflow: visible;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo .tiny-popup {
|
||||
width: 351px;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-wrap .tiny-popup {
|
||||
height: auto;
|
||||
max-height: initial;
|
||||
}
|
||||
.content .tiny-mobile-dropdown-menu-demo .tiny-overlay {
|
||||
position: absolute;
|
||||
}
|
||||
.content
|
||||
.tiny-mobile-dropdown-menu-demo.mobile-dropdown-menu-direction
|
||||
.tiny-overlay {
|
||||
top: 407px !important;
|
||||
}
|
||||
.content .tiny-mobile-image-viewer-demo {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.content .tiny-mobile-image-viewer-demo .tiny-mobile-image-viewer__wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
.content .tiny-mobile-exception-demo {
|
||||
height: 610px;
|
||||
background: #ccc;
|
||||
position: relative;
|
||||
}
|
||||
.content .tiny-mobile-exception-demo .tiny-mobile-exception {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
}
|
||||
.content .tiny-mobile-exception-demo .tiny-mobile-exception__footer {
|
||||
position: absolute;
|
||||
}
|
||||
.tiny-mobile-action-sheet-demo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.tiny-mobile-action-sheet-demo .tiny-mobile-action-sheet {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.tiny-mobile-action-sheet-demo.action-sheet-wrap .tiny-mobile-action-sheet {
|
||||
height: calc(100% - 180px);
|
||||
}
|
||||
.tiny-mobile-action-sheet-demo.action-sheet-slot .tiny-mobile-action-sheet {
|
||||
height: calc(100% - 195px);
|
||||
}
|
||||
.tiny-mobile-action-sheet-demo .tiny-mobile-action-sheet__mask,
|
||||
.tiny-mobile-action-sheet-demo .tiny-mobile-action-sheet__content {
|
||||
position: absolute;
|
||||
/* height: 100%; */
|
||||
bottom: 45px;
|
||||
}
|
||||
.tiny-mobile-mini-picker-demo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.tiny-mobile-mini-picker-demo .tiny-mobile-mini-picker {
|
||||
height: calc(100% - 48px);
|
||||
position: relative;
|
||||
}
|
||||
.tiny-mobile-mini-picker-demo.mini-picker-wrap .tiny-mobile-mini-picker {
|
||||
height: calc(100% - 200px);
|
||||
position: relative;
|
||||
}
|
||||
.tiny-mobile-mini-picker-demo .tiny-mobile-button,
|
||||
.tiny-mobile-mini-picker-demo .tiny-mobile-mini-picker__mask,
|
||||
.tiny-mobile-mini-picker-demo .tiny-mobile-mini-picker__content {
|
||||
position: absolute;
|
||||
}
|
||||
.tiny-mobile-mini-picker-demo .tiny-mobile-input-form__input {
|
||||
text-align: right;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<div class="panel page-container">
|
||||
<div class="left">
|
||||
<tiny-tree-menu
|
||||
_mode="pc"
|
||||
:data="MenuData.component"
|
||||
node-key="path"
|
||||
accordion
|
||||
:show-filter="false"
|
||||
@node-click="nodeClick"
|
||||
:default-expanded-keys="[defaultexpandedkeys]"
|
||||
:current-node-key="defaultexpandedkeys"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<span>{{ data.name }}</span>
|
||||
</template>
|
||||
</tiny-tree-menu>
|
||||
</div>
|
||||
<div class="right">
|
||||
<router-view class="content"></router-view>
|
||||
<div @click="switchMode" class="switch-mode">切换到 {{ isPc ? 'Mobile' : 'PC' }} 示例</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TreeMenu } from '@opentiny/vue'
|
||||
import MenuDataMob from '@/nav.config.comp.mobile.json'
|
||||
import MenuData from '@/nav.config.comp.json'
|
||||
import '@/assets/markdown.css'
|
||||
import '@/assets/tiny-mobile-demo.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyTreeMenu: TreeMenu
|
||||
},
|
||||
methods: {
|
||||
nodeClick(node) {
|
||||
node.path && this.$route.path !== node.path && this.$router.push(node.path)
|
||||
},
|
||||
switchMode() {
|
||||
localStorage.setItem('vue-example-mode', this.isPc ? 'mobile' : 'pc')
|
||||
location.hash = '#/'
|
||||
location.reload()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
defaultexpandedkeys() {
|
||||
return this.$route.path
|
||||
},
|
||||
isPc() {
|
||||
return this.$root.tiny_mode.value !== 'mobile'
|
||||
},
|
||||
MenuData() {
|
||||
return this.isPc ? MenuData : MenuDataMob
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.panel {
|
||||
min-width: 800px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 250px;
|
||||
float: left;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.left > div {
|
||||
width: 250px;
|
||||
position: fixed;
|
||||
font-size: 12px;
|
||||
overflow-y: scroll;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
text-align: left;
|
||||
margin: 20px auto;
|
||||
width: calc(100% - 260px);
|
||||
}
|
||||
.content {
|
||||
width: 900px;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.right section .demo-header > h2 {
|
||||
font-weight: 400;
|
||||
color: #1f2f3d;
|
||||
}
|
||||
|
||||
.right section > h3 {
|
||||
margin: 40px 0 20px 0;
|
||||
padding-bottom: 0.3rem;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
font-weight: 400;
|
||||
color: #1f2f3d;
|
||||
}
|
||||
|
||||
.switch-mode {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
color: var(--ti-common-color-line-active);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,16 @@
|
|||
import { tinyImpressionTheme, tinyInfinityTheme, tinyDeepTheme, tinyGalaxyTheme } from '@opentiny/vue-theme/theme'
|
||||
|
||||
export const CURRENT_THEME_KEY = 'tiny-current-theme'
|
||||
export const DEFAULT_THEME = 'tiny-default-theme'
|
||||
export const IMPRESSION_THEME = 'tiny-impression-theme'
|
||||
export const INFINITY_THEME = 'tiny-infinity-theme'
|
||||
export const DEEP_THEME = 'tiny-deep-theme'
|
||||
export const GALAXY_THEME = 'tiny-galaxy-theme'
|
||||
|
||||
export const THEME_MAP = {
|
||||
[DEFAULT_THEME]: null,
|
||||
[IMPRESSION_THEME]: tinyImpressionTheme,
|
||||
[INFINITY_THEME]: tinyInfinityTheme,
|
||||
[DEEP_THEME]: tinyDeepTheme,
|
||||
[GALAXY_THEME]: tinyGalaxyTheme
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<div class="tiny-mobile-action-sheet-demo action-sheet-wrap">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">上滑列表</h1>
|
||||
<p class="page__desc">弹出式菜单</p>
|
||||
</div>
|
||||
<tiny-button _mode="mobile" @click="fn" type="primary" size="large"
|
||||
>上滑列表</tiny-button
|
||||
>
|
||||
<tiny-action-sheet
|
||||
_mode="mobile"
|
||||
v-model="activeName"
|
||||
:menus="menus"
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
></tiny-action-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ActionSheet, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyActionSheet: ActionSheet,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 1,
|
||||
boxVisibility: false,
|
||||
menus: [
|
||||
{
|
||||
id: 1,
|
||||
label:
|
||||
'我是小花,我是小花,我是小花,我是小花,我是小花,我是小花,我是小花'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '我是小树'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '我是小草'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '我是小叶',
|
||||
warn: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fn() {
|
||||
this.boxVisibility = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="tiny-mobile-action-sheet-demo">
|
||||
<tiny-button _mode="mobile" @click="fn">cliclk me!</tiny-button>
|
||||
<tiny-action-sheet
|
||||
_mode="mobile"
|
||||
v-model="activeName"
|
||||
:menus="menus"
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
@click="clickItem"
|
||||
></tiny-action-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ActionSheet, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyActionSheet: ActionSheet,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: '',
|
||||
boxVisibility: false,
|
||||
menus: [
|
||||
{
|
||||
id: 1,
|
||||
label:
|
||||
'我是小花,我是小花,我是小花,我是小花,我是小花,我是小花,我是小花'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '我是小树'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '我是小草'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '我是小叶',
|
||||
warn: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fn() {
|
||||
this.boxVisibility = true
|
||||
},
|
||||
clickItem(value) {
|
||||
console.log(value, '获取了当前点击的返回值')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div class="tiny-mobile-action-sheet-demo">
|
||||
<tiny-button _mode="mobile" @click="fn">cliclk me!</tiny-button>
|
||||
<tiny-action-sheet
|
||||
_mode="mobile"
|
||||
v-model="activeName"
|
||||
:menus="menus"
|
||||
ellipsis
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
></tiny-action-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ActionSheet, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyActionSheet: ActionSheet,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: '',
|
||||
boxVisibility: false,
|
||||
menus: [
|
||||
{
|
||||
id: 1,
|
||||
label:
|
||||
'我是小花,我是小花,我是小花,我是小花,我是小花,我是小花,我是小花'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '我是小树'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '我是小草'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '我是小叶',
|
||||
warn: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fn() {
|
||||
this.boxVisibility = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div class="tiny-mobile-action-sheet-demo action-sheet-wrap">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">上滑列表</h1>
|
||||
<p class="page__desc">弹出式菜单</p>
|
||||
</div>
|
||||
<tiny-button @click="fn" type="primary" size="large">上滑列表</tiny-button>
|
||||
<tiny-action-sheet
|
||||
v-model="activeName"
|
||||
ref="action"
|
||||
:menus="menus"
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
>
|
||||
<template #action>
|
||||
<tiny-button @click="visibleHandle" type="primary" size="large"
|
||||
>取消</tiny-button
|
||||
>
|
||||
</template>
|
||||
</tiny-action-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ActionSheet, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyActionSheet: ActionSheet,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 1,
|
||||
boxVisibility: false,
|
||||
menus: [
|
||||
{
|
||||
id: 1,
|
||||
label:
|
||||
'我是小花,我是小花,我是小花,我是小花,我是小花,我是小花,我是小花'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '我是小树'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '我是小草'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '我是小叶',
|
||||
warn: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
visibleHandle() {
|
||||
this.$refs.action.visibleHandle()
|
||||
},
|
||||
fn() {
|
||||
this.boxVisibility = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div class="tiny-mobile-action-sheet-demo action-sheet-slot">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">上滑列表</h1>
|
||||
<p class="page__desc">弹出式菜单</p>
|
||||
</div>
|
||||
<tiny-button @click="fn" type="primary" size="large">上滑列表</tiny-button>
|
||||
<tiny-action-sheet
|
||||
v-model="activeName"
|
||||
:menus="menus"
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
>
|
||||
<template #item="data">
|
||||
<div>
|
||||
{{ data.item.label }}
|
||||
</div>
|
||||
</template>
|
||||
</tiny-action-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ActionSheet, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyActionSheet: ActionSheet,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 1,
|
||||
boxVisibility: false,
|
||||
menus: [
|
||||
{
|
||||
id: 1,
|
||||
label:
|
||||
'我是小花,我是小花,我是小花,我是小花,我是小花,我是小花,我是小花'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '我是小树'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '我是小草'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '我是小叶',
|
||||
warn: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fn() {
|
||||
this.boxVisibility = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<div class="alert-wrap">
|
||||
<tiny-alert>type 为默认值 info</tiny-alert>
|
||||
<tiny-alert type="error">type 为 error</tiny-alert>
|
||||
<tiny-alert type="success">type 为 success</tiny-alert>
|
||||
<tiny-alert type="warning">type 为 warning</tiny-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAlert: Alert
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.alert-wrap .tiny-mobile-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div class="alert-wrap">
|
||||
<tiny-alert>默认关闭按钮</tiny-alert>
|
||||
<tiny-alert :closable="false">不可关闭</tiny-alert>
|
||||
<tiny-alert close-text="关闭">自定义关闭按钮为文本</tiny-alert>
|
||||
<tiny-alert @close="close">关闭时触发回调</tiny-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAlert: Alert
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
console.log('已关闭!')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.alert-wrap .tiny-mobile-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<div class="alert-wrap">
|
||||
<tiny-alert :icon="IconCustom">自定义图标</tiny-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert } from '@opentiny/vue'
|
||||
import { iconCustom } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAlert: Alert
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
IconCustom: iconCustom()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.alert-wrap .tiny-mobile-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<div class="alert-wrap">
|
||||
<tiny-alert>默认大小</tiny-alert>
|
||||
<tiny-alert size="normal">size 为 normal</tiny-alert>
|
||||
<tiny-alert size="large">size 为 large</tiny-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAlert: Alert
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.alert-wrap .tiny-mobile-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<div class="alert-wrap">
|
||||
<tiny-alert>
|
||||
<span style="color: red">根据 default slot 自定义内容</span>
|
||||
</tiny-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAlert: Alert
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.alert-wrap .tiny-mobile-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="avatar-wrap">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">HeadIcon</h1>
|
||||
<p class="page__desc">头像图标</p>
|
||||
</div>
|
||||
<tiny-avatar :src="circleUrl" size="large"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" size="medium"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" size="small"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="320"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="80"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="56"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="48"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="40"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="36"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="32"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="30"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="20"></tiny-avatar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Avatar } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAvatar: Avatar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
circleUrl: 'static/images/watercolor.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
.avatar-wrap {
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
height: calc(100% - 118px);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<div class="avatar-wrap">
|
||||
<tiny-avatar :src="circleUrl" :src-set="srcSet" size="large"></tiny-avatar>
|
||||
<tiny-avatar :icon="IconClockWork" size="large"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" fit="contain" size="large"></tiny-avatar>
|
||||
<tiny-avatar :src="errorUrl" :error="onError" fit="none" size="large"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" shape="square" fit="none" size="large"></tiny-avatar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Avatar } from '@opentiny/vue'
|
||||
import { iconClockWork } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAvatar: Avatar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
IconClockWork: iconClockWork(),
|
||||
circleUrl: 'static/images/floral.png',
|
||||
srcSet: 'static/images/watercolor.png 100w,static/images/floral.png 300w,static/images/fruit.jpg 500w',
|
||||
errorUrl: 'error.png', //使用错误路径
|
||||
onError() {
|
||||
console.log('加载失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.avatar-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
.avatar-wrap svg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<div class="avatar-wrap">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">HeadIcon</h1>
|
||||
<p class="page__desc">头像图标</p>
|
||||
</div>
|
||||
<div class="boyx">
|
||||
<tiny-avatar :src="dogUrl" :size="320"></tiny-avatar>
|
||||
<p>320x320</p>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="80"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="80"></tiny-avatar>
|
||||
<span>80x80</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="56"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="56"></tiny-avatar>
|
||||
<span>56x56</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="48"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="48"></tiny-avatar>
|
||||
<span>48x48</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="40"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="40"></tiny-avatar>
|
||||
<span>40x40</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="36"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="36"></tiny-avatar>
|
||||
<span>36x36</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="32"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="32"></tiny-avatar>
|
||||
<span>32x32</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="30"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="30"></tiny-avatar>
|
||||
<span>30x30</span>
|
||||
</div>
|
||||
<div>
|
||||
<tiny-avatar :src="dogUrl" :size="20"></tiny-avatar>
|
||||
<tiny-avatar :src="circleUrl" :size="20"></tiny-avatar>
|
||||
<span>20x20</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Avatar } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyAvatar: Avatar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
circleUrl: 'static/images/floral.png',
|
||||
dogUrl: 'static/images/fruit.jpg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.boyx {
|
||||
padding: 20px;
|
||||
}
|
||||
.boyx > div,
|
||||
.boyx > p {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
.avatar-wrap {
|
||||
height: calc(100% - 0px);
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="value1" :max="1"> 我的待办 </tiny-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="value1">
|
||||
我的待办
|
||||
<template #content>共{{ value1 }}项</template>
|
||||
</tiny-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="unread" :hidden="unread === 0">我的待办</tiny-badge>
|
||||
<br />
|
||||
<tiny-button :disabled="unread === 0" @click="read"
|
||||
>读取一条消息</tiny-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
unread: 2
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
read() {
|
||||
if (this.unread > 0) {
|
||||
this.unread = this.unread - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="2" :href="'/'" target="_self"
|
||||
>当前标签页打开</tiny-badge
|
||||
>
|
||||
<br />
|
||||
<tiny-badge :value="2" :href="'/'" target="_blank"
|
||||
>新建标签页打开</tiny-badge
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="value1" is-dot> 小圆点标记 </tiny-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="value1" :max="1" is-mini>小尺寸</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1">默认尺寸</tiny-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div class="badge-wrap">
|
||||
<tiny-badge :value="value1" :max="1">默认主题</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1" type="primary">primary</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1" type="success">success</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1" type="warning">warning</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1" type="danger">danger</tiny-badge>
|
||||
<br />
|
||||
<tiny-badge :value="value1" :max="1" type="info">info</tiny-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Badge } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBadge: Badge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.badge-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<div class="body">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">Button</h1>
|
||||
<p class="page__desc">按钮</p>
|
||||
</div>
|
||||
<tiny-button size="large">默认按钮</tiny-button>
|
||||
<tiny-button type="primary" size="large">主要按钮</tiny-button>
|
||||
<tiny-button type="success" size="large">成功按钮</tiny-button>
|
||||
<tiny-button type="info" size="large">信息按钮</tiny-button>
|
||||
<tiny-button type="warning" size="large">警告按钮</tiny-button>
|
||||
<tiny-button type="danger" size="large">危险按钮</tiny-button>
|
||||
<tiny-button type="primary" disabled size="large">主要按钮</tiny-button>
|
||||
<tiny-button type="success" disabled size="large">成功按钮</tiny-button>
|
||||
<tiny-button type="info" disabled size="large">信息按钮</tiny-button>
|
||||
<tiny-button type="warning" disabled size="large">警告按钮</tiny-button>
|
||||
<tiny-button type="danger" disabled size="large">危险按钮</tiny-button>
|
||||
|
||||
<div class="btb">
|
||||
<tiny-button type="primary" size="small" plain>默认按钮</tiny-button>
|
||||
<tiny-button type="primary" size="small" plain disabled
|
||||
>默认按钮</tiny-button
|
||||
>
|
||||
</div>
|
||||
<div class="btb">
|
||||
<tiny-button type="primary" size="mini">按钮</tiny-button>
|
||||
</div>
|
||||
<div class="btb">
|
||||
<tiny-button :icon="IconMessageCircle" type="primary" size="mini" plain
|
||||
>加入会议</tiny-button
|
||||
>
|
||||
</div>
|
||||
<tiny-button type="primary" size="medium">主要按钮</tiny-button>
|
||||
<tiny-button type="success" size="medium">成功按钮</tiny-button>
|
||||
<tiny-button type="info" size="medium">信息按钮</tiny-button>
|
||||
<tiny-button type="primary" size="medium" plain>主要按钮</tiny-button>
|
||||
<div class="btb">
|
||||
<span>底部悬浮按钮</span>
|
||||
</div>
|
||||
<div class="btb">
|
||||
<tiny-button type="primary" size="small" plain @click="dat = 0"
|
||||
>有间距双按钮</tiny-button
|
||||
>
|
||||
<tiny-button type="primary" size="small" plain @click="dat = 1"
|
||||
>无间距双按钮</tiny-button
|
||||
>
|
||||
</div>
|
||||
<div class="btb">
|
||||
<tiny-button type="primary" size="small" plain @click="dat = 2"
|
||||
>确定单按钮</tiny-button
|
||||
>
|
||||
<tiny-button type="primary" size="small" plain @click="dat = 3"
|
||||
>删除单按钮</tiny-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="test" v-if="dat === 1">
|
||||
<tiny-button size="large">取消</tiny-button>
|
||||
<tiny-button type="primary" size="large">确认</tiny-button>
|
||||
</div>
|
||||
<div class="test" v-if="dat === 0">
|
||||
<div style="width: calc(50% - 10px); margin-right: 10px">
|
||||
<tiny-button size="large">取消</tiny-button>
|
||||
</div>
|
||||
<div style="width: calc(50% - 10px)">
|
||||
<tiny-button type="primary" size="large">确认</tiny-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="test" v-if="dat === 3">
|
||||
<tiny-button size="large" type="danger">删除</tiny-button>
|
||||
</div>
|
||||
<div class="test" v-if="dat === 2">
|
||||
<tiny-button type="primary" size="large">确认</tiny-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
import { iconMessageCircle } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dat: 0,
|
||||
IconMessageCircle: iconMessageCircle()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.body {
|
||||
height: calc(100% - 60px);
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
.test {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
background-color: white;
|
||||
}
|
||||
.btb {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.button-wrap {
|
||||
height: calc(100% - 118px);
|
||||
position: relative;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.test .tiny-mobile-button {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button @click="click">默认按钮</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
console.log('click event!!!')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button :icon="IconSearch"></tiny-button>
|
||||
<tiny-button type="primary" :icon="IconEdit"></tiny-button>
|
||||
<tiny-button type="success" :icon="IconYes"></tiny-button>
|
||||
<tiny-button type="info" :icon="IconMail"></tiny-button>
|
||||
<tiny-button type="warning" :icon="IconStarO"></tiny-button>
|
||||
<tiny-button type="danger" :icon="IconDel"></tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
import {
|
||||
iconDel,
|
||||
iconYes,
|
||||
iconEdit,
|
||||
iconMail,
|
||||
iconStarO,
|
||||
iconSearch
|
||||
} from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
IconDel: iconDel(),
|
||||
IconYes: iconYes(),
|
||||
IconEdit: iconEdit(),
|
||||
IconMail: iconMail(),
|
||||
IconStarO: iconStarO(),
|
||||
IconSearch: iconSearch()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button loading>加载中</tiny-button>
|
||||
<tiny-button type="primary" loading>加载中</tiny-button>
|
||||
<tiny-button type="success" loading>加载中</tiny-button>
|
||||
<tiny-button type="info" loading>加载中</tiny-button>
|
||||
<tiny-button type="warning" loading>加载中</tiny-button>
|
||||
<tiny-button type="danger" loading>加载中</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div class="demo-form-native-type">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">Form</h1>
|
||||
<p class="page__desc">表单(纯展示)</p>
|
||||
</div>
|
||||
<div class="demo-padds-native-type">
|
||||
<tiny-form ref="ruleForm" :model="createData" :rules="rules">
|
||||
<tiny-form-item label="优秀" prop="users">
|
||||
<tiny-input
|
||||
v-model="createData.users"
|
||||
placeholder="请输入内容"
|
||||
type="form"
|
||||
></tiny-input>
|
||||
</tiny-form-item>
|
||||
<tiny-form-item>
|
||||
<tiny-button @click="handleSubmit('ruleForm')">重置</tiny-button>
|
||||
</tiny-form-item>
|
||||
</tiny-form>
|
||||
</div>
|
||||
<tiny-dialog-box
|
||||
:visible="boxVisibility"
|
||||
@update:visible="boxVisibility = $event"
|
||||
:modal-append-to-body="false"
|
||||
title="消息提示"
|
||||
>
|
||||
<span>reset</span>
|
||||
</tiny-dialog-box>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Form, FormItem, Input, Button, DialogBox } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyForm: Form,
|
||||
TinyFormItem: FormItem,
|
||||
TinyInput: Input,
|
||||
TinyButton: Button,
|
||||
TinyDialogBox: DialogBox
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
createData: {
|
||||
users: ''
|
||||
},
|
||||
rules: {
|
||||
users: [{ required: true, message: '必填', trigger: 'change' }]
|
||||
},
|
||||
boxVisibility: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSubmit(formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
this.boxVisibility = true
|
||||
this.$refs[formName].resetFields()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-padds-native-type {
|
||||
padding: 15px;
|
||||
background: white;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
.demo-form-native-type {
|
||||
height: 100%;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.demo-form-native-type .tiny-form-item__label {
|
||||
background: #fff;
|
||||
}
|
||||
.demo-padds-native-type .tiny-mobile-input-form__input {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button plain>朴素按钮</tiny-button>
|
||||
<tiny-button type="primary" plain>主要按钮</tiny-button>
|
||||
<tiny-button type="success" plain>成功按钮</tiny-button>
|
||||
<tiny-button type="info" plain>信息按钮</tiny-button>
|
||||
<tiny-button type="warning" plain>警告按钮</tiny-button>
|
||||
<tiny-button type="danger" plain>危险按钮</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button round>默认1秒</tiny-button>
|
||||
<tiny-button type="primary" round :reset-time="2000">禁用2秒</tiny-button>
|
||||
<tiny-button type="success" round :reset-time="5000">禁用5秒</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button round>圆角按钮</tiny-button>
|
||||
<tiny-button type="primary" round>主要按钮</tiny-button>
|
||||
<tiny-button type="success" round>成功按钮</tiny-button>
|
||||
<tiny-button type="info" round>信息按钮</tiny-button>
|
||||
<tiny-button type="warning" round>警告按钮</tiny-button>
|
||||
<tiny-button type="danger" round>危险按钮</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button>默认尺寸</tiny-button>
|
||||
<tiny-button type="primary" size="large">large</tiny-button>
|
||||
<tiny-button type="success" size="medium">medium</tiny-button>
|
||||
<tiny-button type="info" size="small">small</tiny-button>
|
||||
<tiny-button type="warning" size="mini">mini</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div class="button-wrap">
|
||||
<tiny-button type="text">文字按钮</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-wrap {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.button-wrap .tiny-mobile-button:not(:nth-child(3n)) {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div class="checkbox-group-wrap">
|
||||
<tiny-checkbox-group v-model="checkboxGroup">
|
||||
<tiny-checkbox
|
||||
v-for="(city, index) in cities"
|
||||
:label="city"
|
||||
:key="index"
|
||||
>{{ city }}</tiny-checkbox
|
||||
>
|
||||
</tiny-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, CheckboxGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyCheckboxGroup: CheckboxGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxGroup: ['北京'],
|
||||
cities: ['上海', '北京', '广州', '深圳']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkbox-group-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<div class="checkbox-group-wrap">
|
||||
<tiny-checkbox-group v-model="checkboxGroup">
|
||||
<tiny-checkbox
|
||||
v-for="(city, index) in cities"
|
||||
:label="city"
|
||||
:key="index"
|
||||
:disabled="city === '北京'"
|
||||
>{{ city }}</tiny-checkbox
|
||||
>
|
||||
</tiny-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, CheckboxGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyCheckboxGroup: CheckboxGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxGroup: ['北京'],
|
||||
cities: ['上海', '北京', '广州', '深圳']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkbox-group-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<div class="checkbox-group-wrap">
|
||||
<tiny-checkbox-group v-model="checkboxGroup" @change="handleChange">
|
||||
<tiny-checkbox
|
||||
v-for="(city, index) in cities"
|
||||
:label="city"
|
||||
:key="index"
|
||||
>{{ city }}</tiny-checkbox
|
||||
>
|
||||
</tiny-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, CheckboxGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyCheckboxGroup: CheckboxGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxGroup: ['北京'],
|
||||
cities: ['上海', '北京', '广州', '深圳']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange(val) {
|
||||
console.log('当前值为:' + val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkbox-group-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div class="checkbox-group-wrap">
|
||||
<tiny-checkbox-group v-model="checkboxGroup" :min="1" :max="3">
|
||||
<tiny-checkbox
|
||||
v-for="(city, index) in cities"
|
||||
:label="city"
|
||||
:key="index"
|
||||
>{{ city }}</tiny-checkbox
|
||||
>
|
||||
</tiny-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, CheckboxGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyCheckboxGroup: CheckboxGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxGroup: ['北京'],
|
||||
cities: ['上海', '北京', '广州', '深圳']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkbox-group-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div class="checkbox-group-wrap">
|
||||
<tiny-checkbox-group v-model="checkboxGroup" vertical>
|
||||
<tiny-checkbox
|
||||
v-for="(city, index) in cities"
|
||||
:label="city"
|
||||
:key="index"
|
||||
>{{ city }}</tiny-checkbox
|
||||
>
|
||||
</tiny-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, CheckboxGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyCheckboxGroup: CheckboxGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxGroup: ['北京'],
|
||||
cities: ['上海', '北京', '广州', '深圳']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkbox-group-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div class="checkbox-wrap">
|
||||
<div class="page__hd">
|
||||
<h1 class="page__title">Checkbox</h1>
|
||||
<p class="page__desc">勾选框-多选</p>
|
||||
</div>
|
||||
<p class="padds">样例1:</p>
|
||||
<div class="padds">
|
||||
<tiny-radio v-model="value" label="1" border>主文本 1</tiny-radio>
|
||||
</div>
|
||||
<div class="borders"></div>
|
||||
<div class="padds">
|
||||
<tiny-radio v-model="value1" label="3" border>主文本 2</tiny-radio>
|
||||
</div>
|
||||
|
||||
<p class="padds">样例2:</p>
|
||||
<div class="padds">
|
||||
<tiny-checkbox v-model="checked.a">A、非常喜欢</tiny-checkbox>
|
||||
</div>
|
||||
<div class="padds">
|
||||
<tiny-checkbox v-model="checked.b">B、喜欢</tiny-checkbox>
|
||||
</div>
|
||||
<div class="padds">
|
||||
<tiny-checkbox v-model="checked.c">C、一般</tiny-checkbox>
|
||||
</div>
|
||||
<div class="padds">
|
||||
<tiny-checkbox v-model="checked.d">D、不喜欢</tiny-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Checkbox, Radio } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCheckbox: Checkbox,
|
||||
TinyRadio: Radio
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: '1',
|
||||
value1: '2',
|
||||
checked: {
|
||||
a: true,
|
||||
b: false,
|
||||
c: false,
|
||||
d: false,
|
||||
e: false,
|
||||
f: false,
|
||||
g: false,
|
||||
h: false
|
||||
},
|
||||
dataList: [
|
||||
{
|
||||
id: 1,
|
||||
content: '主文本1',
|
||||
subtext: '次文本1',
|
||||
contentdes: '这是描述文本'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.borders {
|
||||
height: 1px;
|
||||
width: calc(100% - 52px);
|
||||
margin-left: 52px;
|
||||
background: #ddd;
|
||||
}
|
||||
.padds {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
.page__hd {
|
||||
padding: 40px;
|
||||
}
|
||||
.page__title {
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
.page__desc {
|
||||
margin-top: 5px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
.checkbox-wrap {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 356px;
|
||||
height: calc(100% - 0px);
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|