Compare commits

..

1 Commits
dev ... dev

Author SHA1 Message Date
MojaveHao 8ad6c1b086
chore: 改正了一些错别字 2024-08-08 21:15:13 +08:00
9507 changed files with 201911 additions and 142155 deletions

View File

@ -618,105 +618,6 @@
"contributions": [
"tool"
]
},
{
"login": "Nowitzki41",
"name": "Nowitzki41",
"avatar_url": "https://avatars.githubusercontent.com/u/22088253?v=4",
"profile": "https://github.com/Nowitzki41",
"contributions": [
"code"
]
},
{
"login": "dufu1991",
"name": "dufu1991",
"avatar_url": "https://avatars.githubusercontent.com/u/24769077?v=4",
"profile": "https://github.com/dufu1991",
"contributions": [
"doc"
]
},
{
"login": "hu-qi",
"name": "huqi",
"avatar_url": "https://avatars.githubusercontent.com/u/17986122?v=4",
"profile": "https://github.com/hu-qi",
"contributions": [
"doc"
]
},
{
"login": "tsinghua-lau",
"name": "Mao Tao",
"avatar_url": "https://avatars.githubusercontent.com/u/43164478?v=4",
"profile": "https://github.com/tsinghua-lau",
"contributions": [
"doc"
]
},
{
"login": "Darkingtail",
"name": "Darkingtail",
"avatar_url": "https://avatars.githubusercontent.com/u/51188676?v=4",
"profile": "https://github.com/Darkingtail",
"contributions": [
"bug"
]
},
{
"login": "hashiqi12138",
"name": "hashiqi",
"avatar_url": "https://avatars.githubusercontent.com/u/52161363?v=4",
"profile": "https://github.com/hashiqi12138",
"contributions": [
"bug"
]
},
{
"login": "discreted66",
"name": "liukun",
"avatar_url": "https://avatars.githubusercontent.com/u/190872652?v=4",
"profile": "https://github.com/discreted66",
"contributions": [
"code"
]
},
{
"login": "lcy0620",
"name": "lcy0620",
"avatar_url": "https://avatars.githubusercontent.com/u/188683944?v=4",
"profile": "https://github.com/lcy0620",
"contributions": [
"code"
]
},
{
"login": "sakurajiajia",
"name": "木斯佳",
"avatar_url": "https://avatars.githubusercontent.com/u/37933037?v=4",
"profile": "https://github.com/sakurajiajia",
"contributions": [
"doc"
]
},
{
"login": "552847957",
"name": "552847957",
"avatar_url": "https://avatars.githubusercontent.com/u/8729901?v=4",
"profile": "https://github.com/552847957",
"contributions": [
"doc"
]
},
{
"login": "Lingchen111",
"name": "Lingchen111",
"avatar_url": "https://avatars.githubusercontent.com/u/123021749?v=4",
"profile": "https://github.com/Lingchen111",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 8,

View File

@ -1,7 +0,0 @@
---
description:
globs:
alwaysApply: true
---
作为一个很专业的高级前端开发工程师,从专业的角度出发解决需求和问题。

View File

@ -1,10 +0,0 @@
---
description: 用于写产品需求和开发文档
globs:
alwaysApply: false
---
# 文档需求编写
- 需求尽量写的简单清晰易懂一写
- 在需求设计阶段遵从逐步迭代的原则,早期版本可以尽量简洁一些

View File

@ -50,8 +50,6 @@ module.exports = {
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-invalid-this': 'off',
'vue/no-deprecated-dollar-scopedslots-api': 'off',
'@typescript-eslint/lines-between-class-members': 'off',
'@typescript-eslint/no-this-alias': 'off'
'vue/no-deprecated-dollar-scopedslots-api': 'off'
}
}

View File

@ -1,5 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Questions or need help
url: https://github.com/opentiny/tiny-vue/discussions
url: https://github.com/opentiny/ui-vue/discussions
about: Add this WeChat(opentiny-official), we will invite you to the WeChat discussion group later.

32
.github/labeler.yaml vendored
View File

@ -1,32 +0,0 @@
version: v1
labels:
- label: "enhancement"
sync: true
matcher:
title: "^(feat|✨).*: ?.*"
commit: "^feat.*: ?.*"
- label: "bug"
sync: true
matcher:
title: "^(fix|🐛).*: ?.*"
commit: "^fix.*: ?.*"
- label: "documentation"
sync: true
matcher:
title: "^docs?: ?.*"
commit: "^docs?: ?.*"
- label: "refactoring"
sync: true
matcher:
title: "^refactor.*: ?.*"
commit: "^refactor.*: ?.*"
- label: "chore"
sync: true
matcher:
title: "^chore.*: ?.*"
commit: "^chore.*: ?.*"
- label: "ospp-2024"
sync: true
matcher:
baseBranch: "^ospp-2024/.*"

View File

@ -9,6 +9,7 @@ jobs:
build:
runs-on: windows-latest
outputs:
publishVersion: ${{ steps.parseTag.outputs.publishVersion }}
branchVersion: ${{ steps.parseTag.outputs.branchVersion }}
steps:
- name: Parse Tag
@ -17,7 +18,9 @@ jobs:
with:
script: |
const tag = `${{ github.ref_name }}`
const branchVersion = tag.slice(1).split('.').slice(0, 2).join('.') + '.0'
const publishVersion = tag.slice(3)
const branchVersion = tag.slice(1)
core.setOutput('publishVersion', publishVersion)
core.setOutput('branchVersion', branchVersion)
- name: CheckOut Code
@ -33,48 +36,45 @@ jobs:
with:
node-version: 20.10.0
registry-url: 'https://registry.npmjs.org'
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Run Build Components
run: pnpm build:ui
run: pnpm build:ui -t ${{ steps.parseTag.outputs.publishVersion }}
- name: Run Build Sass Common
run: pnpm build:ui saas-common -d saas
run: pnpm build:ui saas-common -t ${{ steps.parseTag.outputs.publishVersion }} -d saas
- name: Run Build Runtime
run: pnpm build:runtime
- name: Run Build Theme
run: pnpm build:theme
- name: Run Build Renderless
run: pnpm build:renderless
- name: Run Build ThemeSaas
run: pnpm build:themeSaas
- name: Run Build Utils
run: pnpm build:utils
- name: Run Build Hooks
run: pnpm build:hooks
- name: Run Build Runtime
run: pnpm build:runtime
- name: Run Build ThemeMobile
run: pnpm build:themeMobile
- name: Publish Vue3 And Vue2 components
run: pnpm pub:all && pnpm pub:runtime && pnpm pub:utils && pnpm pub:hooks
run: pnpm pub:all
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -1,66 +0,0 @@
name: Auto Deploy Site
on:
push:
branches: [dev]
paths:
- 'examples/sites/**'
- '!examples/sites/**/*.spec.ts'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: pages
cancel-in-progress: true
jobs:
# Build job
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: Install deps
run: pnpm i --no-frozen-lockfile
- name: Build site
run: export NODE_OPTIONS="--max-old-space-size=8192" && pnpm -F @opentiny/vue-docs build
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./examples/sites/dist
destination: ./_site
- name: Repair build artifact
run: |
sudo chmod -R 777 ./_site
cp ./examples/sites/dist/assets/_commonjsHelpers*.js ./_site/assets
cp ./_site/index.html ./_site/404.html
sed -i 's/\/static/\/tiny-vue\/static/' ./_site/static/js/design-common.js
sh ./examples/sites/dist/cp-component-md.sh
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

View File

@ -1,21 +0,0 @@
name: Auto Label (Pull Request)
on:
pull_request_target:
types: [opened, edited]
issues:
types: [opened, edited]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
config-path: .github/labeler.yaml

View File

@ -1,80 +0,0 @@
name: Dispatch Alpha All Publish
run-name: Dispatch All Publish Alpha--${{ inputs.version }}
on:
workflow_dispatch:
inputs:
version:
description: |
输入您将要发布的版本号,
例如: `3.xx.xx`.
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
steps:
- name: CheckOut Code
uses: actions/checkout@master
with:
ref: ${{ github.ref_name }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20.10.0
registry-url: 'https://registry.npmjs.org'
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Run Build Components
run: pnpm build:ui
- name: Run Build Sass Common
run: pnpm build:ui saas-common -d saas
- name: Run Build Theme
run: pnpm build:theme
- name: Run Build Renderless
run: pnpm build:renderless
- name: Run Build ThemeSaas
run: pnpm build:themeSaas
- name: Run Build Utils
run: pnpm build:utils
- name: Run Build Hooks
run: pnpm build:hooks
- name: Run Build Runtime
run: pnpm build:runtime
- name: Run Release alpha
run: pnpm release:alpha
- name: Publish Vue3 And Vue2 components
run: pnpm pub:all && pnpm pub:runtime && pnpm pub:utils && pnpm pub:hooks && pnpm pub:site
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}

View File

@ -1,123 +0,0 @@
name: Dispatch Alpha Renderless Theme Runtime
run-name: Dispatch Alpha Renderless Theme Runtime--${{ inputs.components }}
on:
workflow_dispatch:
inputs:
components:
description: |
输入需要打包的模块名称,多个以英文逗号分隔,
例如: `theme,renderless,runtime,docs,utils,hooks`
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
steps:
- name: Parse Components
id: parseComponents
uses: actions/github-script@v6
with:
script: |
const branchName = `${{ github.ref_name }}`
const moduleName = `${{ inputs.components }}`
const validModuleNames = ['theme', 'renderless', 'runtime', 'docs','utils','hooks']
if (!validModuleNames.some(name => moduleName.includes(name))) {
throw new Error('请输入正确的包名称')
}
- name: CheckOut Code
uses: actions/checkout@master
with:
ref: ${{ github.ref_name }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20.10.0
registry-url: 'https://registry.npmjs.org'
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Run Build Theme
if: contains(inputs.components, 'theme') == true
run: pnpm build:theme
- name: Run Build Renderless
if: contains(inputs.components, 'renderless') == true
run: pnpm build:renderless
- name: Run Build ThemeSaas
if: contains(inputs.components, 'theme-saas') == true
run: pnpm build:themeSaas
- name: Run Build Runtime
if: contains(inputs.components, 'runtime') == true
run: pnpm build:runtime
- name: Run Build Utils
if: contains(inputs.components, 'utils') == true
run: pnpm build:utils
- name: Run Build Hooks
if: contains(inputs.components, 'hooks') == true
run: pnpm build:hooks
- name: Run Release alpha
run: pnpm release:alpha -u
- name: Publish
run: |
pnpm pub:all
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}
- name: Publish Utils
if: contains(inputs.components, 'utils') == true
run: |
pnpm pub:utils
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}
- name: Publish Runtime
if: contains(inputs.components, 'runtime') == true
run: |
pnpm pub:runtime
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}
- name: Publish Hooks
if: contains(inputs.components, 'hooks') == true
run: |
pnpm pub:hooks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}
- name: Publish Docs
if: contains(inputs.components, 'docs') == true
run: |
pnpm pub:site
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}

View File

@ -1,5 +1,5 @@
name: Dispatch Renderless Theme Runtime
run-name: Dispatch Renderless Theme Runtime--${{ inputs.components }}
name: Dispatch Renderless Theme
run-name: Dispatch Renderless Theme--${{ inputs.components }}
on:
workflow_dispatch:
@ -7,7 +7,7 @@ on:
components:
description: |
输入需要打包的模块名称,多个以英文逗号分隔,
例如: `theme,renderless,runtime,docs,utils,hooks`
例如: `theme,renderless,runtime`
required: true
type: string
concurrency:
@ -25,9 +25,8 @@ jobs:
script: |
const branchName = `${{ github.ref_name }}`
const moduleName = `${{ inputs.components }}`
const validModuleNames = ['theme', 'renderless', 'runtime', 'docs','utils','hooks']
if (!validModuleNames.some(name => moduleName.includes(name))) {
if (!moduleName.includes('theme') && !moduleName.includes('renderless')) {
throw new Error('请输入正确的包名称')
}
@ -77,48 +76,16 @@ jobs:
if: contains(inputs.components, 'theme-saas') == true
run: pnpm build:themeSaas
- name: Run Build ThemeMobile
if: contains(inputs.components, 'theme-mobile') == true
run: pnpm build:themeMobile
- name: Run Build Runtime
if: contains(inputs.components, 'runtime') == true
run: pnpm build:runtime
- name: Run Build Utils
if: contains(inputs.components, 'utils') == true
run: pnpm build:utils
- name: Run Build Hooks
if: contains(inputs.components, 'hooks') == true
run: pnpm build:hooks
- name: Publish
run: |
pnpm pub:all
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish Utils
if: contains(inputs.components, 'utils') == true
run: |
pnpm pub:utils
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish Runtime
if: contains(inputs.components, 'runtime') == true
run: |
pnpm pub:runtime
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish Hooks
if: contains(inputs.components, 'hooks') == true
run: |
pnpm pub:hooks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish Docs
if: contains(inputs.components, 'docs') == true
run: |
pnpm pub:site
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -1,66 +0,0 @@
name: Dispatch Alpha Ui Publish
run-name: Dispatch Alpha Ui--${{ inputs.components }}
on:
workflow_dispatch:
inputs:
components:
description: |
输入需要打包的组件名称,多个以空格分隔,
例如: `input alert`.
required: false
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
steps:
- name: CheckOut Code
uses: actions/checkout@master
with:
ref: ${{ github.ref_name }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20.10.0
registry-url: 'https://registry.npmjs.org'
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Run Build Components
if: inputs.components != ''
run: pnpm build:ui ${{ inputs.components }}
- name: Run Build All Components
if: inputs.components == ''
run: pnpm build:ui
- name: Run Release alpha
run: pnpm release:alpha -u
- name: Publish
run: |
pnpm pub:all
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_OPENTINY_VUE_TOKEN }}

View File

@ -1,14 +1,7 @@
name: E2E Test ALL
run-name: E2E Test All origin--${{ inputs.origin }}
run-name: E2E Test All
on:
workflow_dispatch:
inputs:
origin:
description: |
输入需要测试的域名地址,包括微服务路径,如果不输入则采用本地启动服务测试,
例如: `https://opentiny.github.io/tiny-vue-web-doc`.
required: false
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true
@ -44,32 +37,23 @@ jobs:
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: dev start
if: contains(inputs.origin, 'http') == false
run: pnpm site & sleep 5
- name: Release E2E Config
if: contains(inputs.origin, 'http') == true
run: pnpm release:e2eConfig -o ${{ inputs.origin }} & sleep 5
- name: update playwright
run: pnpm recursive update @playwright/test
- name: Install Playwright browsers
run: pnpm install:browser --with-deps chromium
- name: Run Playwright tests
run: pnpm test:e2e3 --shard=${{ matrix.shard }} --reporter=blob
- name: Upload blob report to GitHub Actions Artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: all-blob-reports-${{ strategy.job-index }}
name: all-blob-reports
path: examples/vue3/blob-report
retention-days: 0.5
@ -89,17 +73,16 @@ jobs:
npm install -g @playwright/test
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
with:
pattern: all-blob-reports-*
merge-multiple: true
name: all-blob-reports
path: all-blob-reports
- name: Merge into HTML Report
run: playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report

View File

@ -1,5 +1,5 @@
name: E2E Test Dispatch
run-name: E2E Test Dispatch--${{ inputs.testDemos }}--origin--${{ inputs.origin }}
run-name: E2E Test Dispatch--${{ inputs.testDemos }}--
on:
workflow_dispatch:
inputs:
@ -9,12 +9,6 @@ on:
such as `input, alert`.
required: true
type: string
origin:
description: |
输入需要测试的域名地址,包括微服务路径,如果不输入则采用本地启动服务测试,
例如: `https://opentiny.github.io/tiny-vue-web-doc`.
required: false
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true
@ -50,13 +44,8 @@ jobs:
run: pnpm i --no-frozen-lockfile
- name: dev start
if: contains(inputs.origin, 'http') == false
run: pnpm site & sleep 5
- name: Release E2E Config
if: contains(inputs.origin, 'http') == true
run: pnpm release:e2eConfig -o ${{ inputs.origin }} & sleep 5
- name: Install Playwright browsers
run: pnpm install:browser --with-deps chromium

View File

@ -4,327 +4,106 @@ on:
pull_request:
types: [opened, reopened, synchronize, edited]
# 并发控制确保相同PR的工作流不会同时运行多个实例
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
cancel-in-progress: true
jobs:
detect-changed-files:
name: Detect Changed Files
parse-components:
name: Parse Affected Components
runs-on: ubuntu-latest
outputs:
# 输出三个变量供后续任务使用
changed_components: ${{ steps.find-changed-components.outputs.changed_components }} # 自动检测到的变更组件
manual_components: ${{ steps.parse-title.outputs.manual_components }} # 从PR标题手动指定的组件
testclis: ${{ steps.parse-test-cli.outputs.testClis }} # 测试命令列表
testComponents: ${{ steps.parseTitle.outputs.testComponents }}
testclis: ${{ steps.parsetestCli.outputs.testClis }}
steps:
# 检出代码,需要完整历史以便比较变更
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0 # 获取完整的git历史用于检测文件变更
# 使用tj-actions/changed-files获取PR中所有变更的文件
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v41
# 根据变更的文件自动识别受影响的组件
- name: Find changed components
id: find-changed-components
uses: actions/github-script@v6
with:
script: |
const changedFiles = '${{ steps.changed-files.outputs.all_changed_files }}'.split(' ').filter(file => file.trim() !== '');
console.log('变更的文件列表:', changedFiles);
// 增强组件路径匹配规则,确保能正确识别各种路径格式
const componentPathRules = [
// 匹配 packages/renderless/src/{组件名} 路径,支持更深层次的子目录
{
pattern: /^packages\/renderless\/src\/([^/]+)\//,
group: 1,
type: 'renderless'
},
// 匹配 packages/vue/src/{组件名} 路径,支持更深层次的子目录
{
pattern: /^packages\/vue\/src\/([^/]+)\//,
group: 1,
type: 'vue'
},
// 匹配示例目录下的组件路径 - 只匹配目录不匹配package.json等文件
{
pattern: /^examples\/sites\/demos\/pc\/app\/([^/]+)\//,
group: 1,
type: 'demo'
},
// 匹配 packages/theme/src/{组件名} 样式路径
{
pattern: /^packages\/theme\/src\/([^/]+)\//,
group: 1,
type: 'theme'
}
];
// 定义子组件到父组件的映射关系
const subComponentMapping = {
'calendar-bar': 'calendar',
'carousel-item': 'carousel',
'cascader-menu': 'cascader',
'cascader-node': 'cascader',
'cascader-panel': 'cascader',
'checkbox-button': 'checkbox',
'checkbox-group': 'checkbox',
'col': 'layout',
'collapse-item': 'collapse',
'date-range': 'date-picker',
'date-table': 'date-picker',
'dropdown-item': 'dropdown',
'dropdown-menu': 'dropdown',
'form-item': 'form',
'grid-toolbar': 'grid',
'image-viewer': 'image',
'month-range': 'date-picker',
'month-table': 'date-picker',
'option': 'select',
'option-group': 'select',
'pager-item': 'pager',
'picker': 'date-picker',
'quarter-panel': 'date-picker',
'radio-button': 'radio',
'radio-group': 'radio',
'row': 'layout',
'select-dropdown': 'select',
'skeleton-item': 'skeleton',
'svgs': 'icon',
'tab-item': 'tabs',
'textarea': 'input',
'time-panel': 'time-picker',
'time-range': 'time-picker',
'time-spinner': 'time-picker',
'timeline-item': 'timeline',
'transfer-panel': 'transfer',
'tree-node': 'tree',
'upload': 'file-upload',
'upload-dragger': 'file-upload',
'upload-list': 'file-upload',
'year-range': 'date-picker',
'year-table': 'date-picker'
};
// 从文件路径中提取组件名称
const components = new Set();
const detectedComponents = {}; // 用于记录检测到的组件和相关文件
const unmatchedFiles = []; // 记录未匹配的文件
changedFiles.forEach(file => {
// 跳过工作流文件等非组件相关文件
if (file.startsWith('.github/') ||
file.includes('README') ||
file.includes('.md') ||
file.includes('theme-saas') || // 跳过theme-saas相关文件
file.includes('theme/src/common/')) { // 跳过组件通用样式文件
console.log(`跳过非测试相关文件: ${file}`);
return;
}
let matched = false;
for (const rule of componentPathRules) {
const match = file.match(rule.pattern);
if (match && match[rule.group]) {
matched = true;
let componentName = match[rule.group];
// 检查是否是需要映射的子组件
if (subComponentMapping[componentName]) {
console.log(`检测到子组件 ${componentName},映射到父组件 ${subComponentMapping[componentName]}`);
componentName = subComponentMapping[componentName];
}
// 记录找到的组件
components.add(componentName);
// 记录组件来源和相关文件,用于调试
if (!detectedComponents[componentName]) {
detectedComponents[componentName] = {
type: rule.type,
files: []
};
}
detectedComponents[componentName].files.push(file);
console.log(`成功匹配组件 ${componentName}: ${file} (类型: ${rule.type})`);
break; // 一个文件只匹配一个组件
}
}
// 检查theme目录中的特殊路径格式
if (!matched && file.includes('/theme/src/') && !file.includes('/common/')) {
// 尝试从theme路径中提取组件名
const themePath = file.split('/');
// 常见的组件样式文件命名模式
const possibleComponentNames = [];
for (let i = 0; i < themePath.length; i++) {
// 跳过明显不是组件名的路径部分
if (['src', 'lib', 'theme', 'packages'].includes(themePath[i])) {
continue;
}
// 检查是否像是组件名(小写字母,可能包含连字符)
if (/^[a-z][a-z0-9\-]*$/.test(themePath[i])) {
possibleComponentNames.push(themePath[i]);
}
}
if (possibleComponentNames.length > 0) {
// 使用最后一个可能的组件名(通常最具体)
let componentName = possibleComponentNames[possibleComponentNames.length - 1];
// 检查是否是需要映射的子组件
if (subComponentMapping[componentName]) {
console.log(`检测到子组件 ${componentName},映射到父组件 ${subComponentMapping[componentName]}`);
componentName = subComponentMapping[componentName];
}
components.add(componentName);
if (!detectedComponents[componentName]) {
detectedComponents[componentName] = {
type: 'theme',
files: []
};
}
detectedComponents[componentName].files.push(file);
console.log(`通过主题样式路径分析匹配到组件 ${componentName}: ${file}`);
matched = true;
}
}
// 记录未匹配到的文件,用于调试
if (!matched) {
unmatchedFiles.push(file);
console.log(`未能匹配组件: ${file}`);
}
});
// 打印详细的检测结果,方便调试
console.log('检测结果详情:', JSON.stringify(detectedComponents, null, 2));
console.log('未匹配文件列表:', unmatchedFiles);
// 构建E2E测试的组件过滤器表达式
if (components.size > 0) {
// 构建符合E2E测试命令需要的过滤表达式格式
const componentFilters = Array.from(components)
.map(comp => `"\\/app\\/${comp}\\/"`)
.join(' ');
console.log(`检测到变更的组件: ${Array.from(components).join(', ')}`);
core.setOutput('changed_components', componentFilters);
} else {
console.log('没有检测到变更的组件');
core.setOutput('changed_components', '');
}
# 从PR标题中解析手动指定的组件列表
- name: Parse Title for Manual Components
id: parse-title
- name: Parse Title
id: parseTitle
uses: actions/github-script@v6
with:
script: |
const prTitle = context.payload.pull_request.title
// 匹配PR标题中的 [component1, component2] 格式
const regex = /\[(.*?)\]/
const matches = prTitle.match(regex)
if (matches && matches.length > 1 && matches[1]) {
// 处理和格式化手动指定的组件列表
let components = matches[1]
.split(',')
.map((c) => c.trim())
.filter((c) => /^[a-z\-\/]+$/.test(c)) // 确保组件名符合规范
.map((c) => `"\\/app\\/${c}\\/"`)
components = [...new Set(components)].join(' ') // 去重并转为字符串
core.setOutput('manual_components', components)
.filter((c) => /^[a-z\-\/]+$/.test(c))
.map((c) => `"\\/${c}\\/"`)
components = [...new Set(components)].slice(0, 3).join(' ')
core.setOutput('testComponents', components)
} else {
core.setOutput('manual_components', '')
}
const warningString =`**[e2e-test-warn]**
The component to be tested is missing.
# 当没有检测到任何组件时,生成警告提示
- name: Generate warning if no components detected
id: warning
if: ${{ steps.find-changed-components.outputs.changed_components == '' && steps.parse-title.outputs.manual_components == '' }}
The title of the Pull request should look like "fix(vue-renderless): [action-menu, alert] fix xxx bug".
Please make sure you've read our [contributing guide](https://github.com/opentiny/tiny-vue/blob/dev/CONTRIBUTING.md)
`
core.setOutput('tip', warningString)
core.warning(warningString)
}
- name: generate user-tip.txt
if: ${{ steps.parseTitle.outputs.tip }}
run: |
cat << EOF > user-tip.txt
**[e2e-test-warn]**
没有检测到要测试的组件。
系统会自动检测PR中变更的组件文件或者您可以在PR标题中使用[component1, component2]格式手动指定要测试的组件。
例如: "fix(vue-renderless): [action-menu, alert] fix xxx bug"
请确保您已阅读我们的[贡献指南](https://github.com/opentiny/tiny-vue/blob/dev/CONTRIBUTING.md)
${{ steps.parseTitle.outputs.tip }}
EOF
echo "warning=true" >> $GITHUB_OUTPUT
# 上传警告信息作为工作流制品
- name: Upload warning
if: ${{ steps.warning.outputs.warning }}
- name: Upload User Tip
if: ${{ steps.parseTitle.outputs.tip }}
uses: actions/upload-artifact@v4
with:
name: user-tip
path: user-tip.txt
retention-days: 1 # 保留1天
retention-days: 1
- name: Save PR number
if: ${{ steps.parseTitle.outputs.tip }}
run: echo ${{ github.event.number }} > ./pr-id.txt
# 解析测试命令配置
- name: Upload PR number
if: ${{ steps.parseTitle.outputs.tip }}
uses: actions/upload-artifact@v4
with:
name: pr
path: ./pr-id.txt
- name: Parse Test Cli
id: parse-test-cli
id: parsetestCli
uses: actions/github-script@v6
with:
script: |
// 从GitHub变量中获取测试命令列表如果未配置则使用默认命令
const testClis = '${{ vars.PLAYWRIGHT_CLIS }}' ? '${{ vars.PLAYWRIGHT_CLIS }}'.split(',') : ['pnpm test:e2e3']
core.setOutput('testClis', JSON.stringify(testClis))
core.setOutput('testclis', JSON.stringify(testClis))
# PR测试任务运行实际的E2E测试
pr-test:
name: PR E2E Test
needs: detect-changed-files # 依赖前一个任务的输出
runs-on: ubuntu-latest
# 只有当检测到变更组件或手动指定组件时才运行测试
if: ${{ needs.detect-changed-files.outputs.changed_components != '' || needs.detect-changed-files.outputs.manual_components != '' }}
if: ${{ needs.parse-components.outputs.testComponents }}
strategy:
matrix:
testcli: ${{ fromJson(needs.detect-changed-files.outputs.testclis) }} # 使用矩阵策略运行多个测试命令
env:
# 合并自动检测和手动指定的组件列表
TEST_COMPONENTS: ${{ needs.detect-changed-files.outputs.changed_components }} ${{ needs.detect-changed-files.outputs.manual_components }}
steps:
# 检出代码
- uses: actions/checkout@v3
testcli: ${{ fromJson(needs.parse-components.outputs.testclis) }}
# 设置pnpm
name: PR E2E Test
needs: parse-components
runs-on: ubuntu-latest
env:
TEST_COMPONENTS: ${{ needs.parse-components.outputs.testComponents }}
steps:
- uses: actions/checkout@v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
# 设置Node.js环境
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 20
# 缓存Playwright浏览器安装加速工作流
- name: Cache Playwright Installation
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
# 获取pnpm缓存目录
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
# 设置pnpm缓存
- uses: actions/cache@v3
name: Setup pnpm cache
with:
@ -333,19 +112,11 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
# 安装依赖
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
# 安装Playwright浏览器
- name: Install Playwright browsers
run: pnpm install:browser --with-deps chromium
# 显示要测试的组件列表,便于调试
- name: Show detected components
run: |
echo "Testing components: $TEST_COMPONENTS"
# 运行E2E测试
- name: E2E Test
run: ${{ matrix.testcli }} ${{ env.TEST_COMPONENTS }} --retries=1 --workers=2 # 带重试和并行工作进程
run: ${{ matrix.testcli }} ${{ env.TEST_COMPONENTS }} --retries=1 --workers=2

View File

@ -1,131 +0,0 @@
name: Unit Test PR
run-name: Unit Test PR--${{ github.event.pull_request.title }}
on:
pull_request:
types: [opened, reopened, synchronize, edited]
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
cancel-in-progress: true
jobs:
parse-components:
name: Parse Affected Components
runs-on: ubuntu-latest
outputs:
testComponents: ${{ steps.parseTitle.outputs.testComponents }}
utilsModified: ${{ steps.check-utils-changes.outputs.modified }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Parse Title
id: parseTitle
uses: actions/github-script@v6
with:
script: |
const prTitle = context.payload.pull_request.title
const regex = /\[(.*?)\]/
const matches = prTitle.match(regex)
if (matches && matches.length > 1 && matches[1]) {
let components = matches[1]
.split(',')
.map((c) => c.trim())
.filter((c) => /^[a-z\-\/]+$/.test(c))
.map((c) => `${c}`)
components = [...new Set(components)].slice(0, 3).join(' ')
core.setOutput('testComponents', components)
} else {
const warningString =`**[unit-test-warn]**
The component to be tested is missing.
The title of the Pull request should look like "fix(vue-renderless): [action-menu, alert] fix xxx bug".
Please make sure you've read our [contributing guide](https://github.com/opentiny/tiny-vue/blob/dev/CONTRIBUTING.md)
`
core.setOutput('tip', warningString)
core.warning(warningString)
}
- name: Check Utils Changes
id: check-utils-changes
run: |
# 从远程仓库获取目标分支的最新代码
git fetch origin ${{ github.base_ref }}
# 获取当前PR分支相对于目标分支的所有变更文件列表
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}..HEAD)
# 使用grep检查变更文件列表中是否包含utils包的改动
# ^packages/utils/ 表示以packages/utils/开头的文件路径
if echo "$CHANGED_FILES" | grep -q "^packages/utils/"; then
# 如果检测到utils包有改动设置modified输出变量为true
echo "modified=true" >> $GITHUB_OUTPUT
echo "Utils package has been modified, utils tests will be executed"
else
# 如果没有检测到utils包的改动设置modified输出变量为false
echo "modified=false" >> $GITHUB_OUTPUT
echo "No changes detected in utils package"
fi
- name: generate user-tip.txt
if: ${{ steps.parseTitle.outputs.tip }}
run: |
cat << EOF > user-tip.txt
${{ steps.parseTitle.outputs.tip }}
EOF
- name: Upload User Tip
if: ${{ steps.parseTitle.outputs.tip }}
uses: actions/upload-artifact@v4
with:
name: user-tip
path: user-tip.txt
retention-days: 1
- name: Save PR number
if: ${{ steps.parseTitle.outputs.tip }}
run: echo ${{ github.event.number }} > ./pr-id.txt
- name: Upload PR number
if: ${{ steps.parseTitle.outputs.tip }}
uses: actions/upload-artifact@v4
with:
name: pr
path: ./pr-id.txt
pr-test:
name: PR Unit Test
needs: parse-components
runs-on: ubuntu-latest
env:
TEST_COMPONENTS: ${{ needs.parse-components.outputs.testComponents }}
UTILS_MODIFIED: ${{ needs.parse-components.outputs.utilsModified }}
steps:
- uses: actions/checkout@v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 20
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Unit Test for Components
if: ${{ env.TEST_COMPONENTS }}
run: pnpm test:unit3 ${{ env.TEST_COMPONENTS }}
- name: Utils Unit Test
if: ${{ env.UTILS_MODIFIED == 'true' }}
run: pnpm test:utils

23
.gitignore vendored
View File

@ -4,6 +4,7 @@ dist/
dist2/
dist2.7/
dist3/
dist-react/
allDist/
packages/**/runtime
coverage/
@ -23,6 +24,12 @@ test-results
/packages/vue-runtime/all.ts
/packages/vue-runtime/simple.ts
/packages/react/index.ts
/packages/react/pc.ts
/packages/react/mobile.ts
/packages/react/app.ts
/packages/react/mobile-first.ts
/examples/**/playwright-report
/examples/**/test-results
vite.config.ts.timestamp*
@ -51,9 +58,12 @@ yarn-error.log*
tgzs
*.tgz
# theme 的汇总文件是自动生成的
packages/theme/src/old-theme-index.less
packages/theme/src/index.less
packages/theme/scripts/theme.json
packages/theme/scripts/theme-result.txt
packages/theme/scripts/themeExcel.xlsx
packages/theme/src/theme/*-theme/component.js
pnpm-lock.yaml
gulp/bundle.json
@ -67,9 +77,4 @@ test-results
examples/sites/public/tiny-vue*.js
examples/sites/public/tiny-vue*.mjs
examples/sites/public/tailwind.css
examples/sites/public/index.css
# next 屏蔽
next/cloud-icons/categorys.ts
next/scene-theme/docs/.vitepress/cache
examples/sites/public/index.css

View File

@ -80,15 +80,6 @@
"backgroundColor": "transparent",
"bold": false,
"italic": false
},
{
"tag": "--",
"color": "#FFFFFF",
"strikethrough": false,
"underline": false,
"backgroundColor": "#5CB300",
"bold": false,
"italic": false
}
],
"vue.codeActions.enabled": false

View File

@ -57,15 +57,17 @@ The commit message should be in the form of a `type(scope): description of the m
1. The specification of the title is the same as the commit information, which is entered in the form of `type(scope): description information`.
2. Trigger component **e2e test**: CI will automatically trigger the test cases of the corresponding components according to the files modified by the PR. If you need to manually trigger the test of a specific component, you can add the component name in the format of `[componentName1, componentName2]` in the Pull Request title, and the system will execute the test cases of these specified components.
2. **e2e test** of trigger components: Adding '[componentName1, componentName2]' to the Pull Request title will execute test cases for componentName1, componentName2, and declare this structure when changes to code affect components.
- Note: The `github action` under this project will use the component name declared by `[componentName1, componentName2]` to match the path name under the `examples/sites/demos` directory to identify the test e2e cases to be executed. (Because running all test cases is too time-consuming)
- Note: The `github action` in this project identifies test e2e use cases to be executed by matching the component names declared by `[componentName1, componentName2]` with the path names in the `examples/sites/demos` directory. (Because running the full test case is too time consuming)
- When modifying a sub-component of a component, such as the `col` component, which has no corresponding examples and test cases, the `layout` component should be tested, because the `col` component is a sub-component of the `layout` component. The PR title can be: `fix(col): [layout] xxxxxxxxxxxxxx`
3. Example title:
- Added alert component documentation: `docs(alert): xxxxxxxxxxxxxxx`, `docs(site):xxxxxxxxxxxxxxx`
- Added alert component test cases: `test(alert): xxxxxxxxxxxxxx`
- Fixed the defect of alert component @opentiny/vue-renderless (manually trigger e2e test cases): `fix(vue-renderless/alert): [alert] xxxxxxxxxxxxxxx`
- Supplement alert component document: `docs(alert): [alert] xxxxxxxxxxxxxxx`, `docs(site): [alert] xxxxxxxxxxxxxxx`
- Supplement alert component test case: `test(alert): [alert] xxxxxxxxxxxxxx`
- Fixed bug in alert component @opentiny/vue-renderless: `fix(vue-renderless/alert): [alert] xxxxxxxxxxxxxx`
#### Pull Request Description

View File

@ -57,15 +57,17 @@ commit 信息要以 `type(scope): 描述信息` 的形式填写,例如 `fix(vu
1. 标题的规范与 commit 信息一样,以`type(scope): 描述信息` 的形式填写。
2. 触发组件的 **e2e 测试**: CI 会自动根据 PR 修改的文件来触发相应组件的测试用例。如果需要手动触发特定组件的测试,可以在 Pull Request 标题中添加 `[componentName1, componentName2]` 格式的组件名称,系统将会执行这些指定组件的测试用例
2. 触发组件的 **e2e 测试**: 在 Pull Request 标题里添加 `[componentName1, componentName2]`,将会执行 componentName1componentName2 的测试用例,当改动的代码会影响组件时,需要声明这个结构
- 注:本项目下的 `github action` 会用`[componentName1, componentName2]`声明的组件名匹配 `examples/sites/demos` 目录下的路径名称识别要执行的测试e2e用例。因为全量跑测试用例太耗费时间
- 当修改了某个组件的子组件,比如`col`组件,它本身没有对应的示例以及测试用例,这时应该要测试的是`layout`组件,因为`col`组件是`layout`组件的子组件PR 标题可以这样: `fix(col): [layout] xxxxxxxxxxxxxx`
3. 标题示例:
- 补充 alert 组件文档: `docs(alert): xxxxxxxxxxxxxxx`, `docs(site):xxxxxxxxxxxxxxx`
- 补充 alert 组件测试用例: `test(alert): xxxxxxxxxxxxxx`
- 修复 alert 组件 @opentiny/vue-renderless 下的缺陷(手动触发 e2e 测试用例): `fix(vue-renderless/alert): [alert] xxxxxxxxxxxxxx`
- 补充 alert 组件文档: `docs(alert): [alert] xxxxxxxxxxxxxxx`, `docs(site): [alert] xxxxxxxxxxxxxxx`
- 补充 alert 组件测试用例: `test(alert): [alert] xxxxxxxxxxxxxx`
- 修复 alert 组件 @opentiny/vue-renderless 下的缺陷: `fix(vue-renderless/alert): [alert] xxxxxxxxxxxxxx`
#### Pull Request 的描述
@ -143,4 +145,3 @@ pnpm dev:vue2
```
/examples/sites/src/data/contributorMap.js
```

View File

@ -1,109 +0,0 @@
# TinyVue 仓库结构说明
## packages/
### 1. 核心组件与运行时
├── vue/ # Vue核心组件库
│ └── src/ # 源码目录
│ ├── alert/ # alert组件源码目录
│ ├── button/ # button组件源码目录
│ └── ... # 其他组件
├── vue-runtime/ # Vue运行时支持
├── vue-common/ # Vue2/Vue3通用基础组件库
│ └── src/
│ ├── adapter/ # Vue2/Vue3适配层
│ │ ├── vue2/ # Vue2版本适配器
│ │ └── vue3/ # Vue3版本适配器
├── renderless/ # 无渲染组件逻辑
│ └── src/
│ ├── alert/ # Alert组件逻辑层
│ ├── button/ # Button组件逻辑层
│ └── ... # 其他组件逻辑层
├── vue-hooks/ # Vue Hooks集合
│ └── src/ # Hooks源码
### 2. 主题与样式
├── theme/ # 主题系统
│ └── src/
│ ├── alert/ # Alert组件样式
│ ├── button/ # Button组件样式
│ └── ... # 其他组件样式
├── theme-saas/ # SaaS主题包
│ └── src/
│ ├── alert/ # Alert组件样式
│ ├── button/ # Button组件样式
│ └── ... # 其他组件样式
### 3. 图标相关
├── vue-icon/ # Vue图标组件库
│ └── src/ # 源码目录
├── vue-icon-saas/ # SaaS图标组件
│ └── src/ # 源码目录
├── vue-icon-multicolor/ # 多色图标支持
│ └── src/ # 源码目录
### 5. 工具与指令
├── utils/ # 工具函数库
│ └── src/
│ ├── dom/ # DOM相关工具函数
│ ├── is/ # 类型判断工具函数
│ └── ... # 其他工具函数
├── vue-directive/ # Vue指令集合
│ └── src/ # 指令源码
### 6. 国际化
├── vue-locale/ # 国际化支持
│ └── src/
│ ├── vue2/ # Vue2版本国际化适配器
│ ├── vue3/ # Vue3版本国际化适配器
│ └── lang/ # 语言包资源
### 7. 设计规范
├── design/ # 设计规范和资源
├── aurora/ # Aurora设计规范
├── saas/ # SaaS设计规范
└── smb/ # SMB设计规范
---
## examples/ # 示例代码
├── sites/ # 本地官网
├── vue3/ # Vue3本地开发工程
├── vue2/ # Vue2本地开发工程
├── docs/ # 本地开发模板包含 pc 和 mobile-first 模式
└── public/ # 公共资源
---
## internals/ # 内部工具和配置
├── cli/ # 构建脚本
├── automate/ # 内部自动化相关脚本
├── playwright-config/ # playwright测试配置
├── unplugin-virtual-template/ # vite插件解析虚拟模块
└── vue-test-utils/ # vitest测试工具提供 mountPcMode 和 mountMobilefirstMode
---
### 主要目录说明
1. **packages/**: 核心源码包分为组件、主题、图标、SaaS、工具、国际化等子模块便于维护和按需引入。
2. **examples/**: 示例代码包含多版本Vue的示例、文档和演示站点用于测试和展示。
3. **internals/**: 内部工具,包含构建工具、配置和内部开发支持。
---

View File

@ -169,19 +169,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="12.5%"><a href="https://github.com/trueLoving"><img src="https://avatars.githubusercontent.com/u/44056372?v=4?s=100" width="100px;" alt="Aoi Kaze"/><br /><sub><b>Aoi Kaze</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=trueLoving" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://simonhe.me"><img src="https://avatars.githubusercontent.com/u/57086651?v=4?s=100" width="100px;" alt="Simon He"/><br /><sub><b>Simon He</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=Simon-He95" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://study.linlove.cn/"><img src="https://avatars.githubusercontent.com/u/44194929?v=4?s=100" width="100px;" alt="zhangpaopao"/><br /><sub><b>zhangpaopao</b></sub></a><br /><a href="#tool-zhangpaopao0609" title="Tools">🔧</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Nowitzki41"><img src="https://avatars.githubusercontent.com/u/22088253?v=4?s=100" width="100px;" alt="Nowitzki41"/><br /><sub><b>Nowitzki41</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=Nowitzki41" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/dufu1991"><img src="https://avatars.githubusercontent.com/u/24769077?v=4?s=100" width="100px;" alt="dufu1991"/><br /><sub><b>dufu1991</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=dufu1991" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/hu-qi"><img src="https://avatars.githubusercontent.com/u/17986122?v=4?s=100" width="100px;" alt="huqi"/><br /><sub><b>huqi</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=hu-qi" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tsinghua-lau"><img src="https://avatars.githubusercontent.com/u/43164478?v=4?s=100" width="100px;" alt="Mao Tao"/><br /><sub><b>Mao Tao</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=tsinghua-lau" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Darkingtail"><img src="https://avatars.githubusercontent.com/u/51188676?v=4?s=100" width="100px;" alt="Darkingtail"/><br /><sub><b>Darkingtail</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/issues?q=author%3ADarkingtail" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/hashiqi12138"><img src="https://avatars.githubusercontent.com/u/52161363?v=4?s=100" width="100px;" alt="hashiqi"/><br /><sub><b>hashiqi</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/issues?q=author%3Ahashiqi12138" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/discreted66"><img src="https://avatars.githubusercontent.com/u/190872652?v=4?s=100" width="100px;" alt="liukun"/><br /><sub><b>liukun</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=discreted66" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/lcy0620"><img src="https://avatars.githubusercontent.com/u/188683944?v=4?s=100" width="100px;" alt="lcy0620"/><br /><sub><b>lcy0620</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=lcy0620" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/sakurajiajia"><img src="https://avatars.githubusercontent.com/u/37933037?v=4?s=100" width="100px;" alt="木斯佳"/><br /><sub><b>木斯佳</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=sakurajiajia" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/552847957"><img src="https://avatars.githubusercontent.com/u/8729901?v=4?s=100" width="100px;" alt="552847957"/><br /><sub><b>552847957</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=552847957" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Lingchen111"><img src="https://avatars.githubusercontent.com/u/123021749?v=4?s=100" width="100px;" alt="Lingchen111"/><br /><sub><b>Lingchen111</b></sub></a><br /><a href="https://github.com/opentiny/tiny-vue/commits?author=Lingchen111" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@ -1,6 +1 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'header-max-length': [1, 'always', 150]
}
}
module.exports = { extends: ['@commitlint/config-conventional'] }

View File

@ -19,6 +19,7 @@
</div>
<div class="fi-1 of-auto">
<tiny-pc v-if="modeState.mode === 'pc'" :show-fixed-menu="state.showFixedMenu"></tiny-pc>
<tiny-mobile v-else-if="modeState.mode === 'mobile'" :show-fixed-menu="state.showFixedMenu"></tiny-mobile>
<tiny-mobile-first v-else :show-fixed-menu="state.showFixedMenu"></tiny-mobile-first>
</div>
</div>
@ -29,6 +30,7 @@ import './style.css'
import { ButtonGroup, Link } from '@opentiny/vue'
import { iconEditorMenuRight, iconEditorMenuLeft } from '@opentiny/vue-icon'
import TinyPc from './pc.vue'
import TinyMobile from './mobile.vue'
import TinyMobileFirst from './mobile-first.vue'
import { hooks } from '@opentiny/vue-common'
import { useModeCtx } from './uses'
@ -36,6 +38,7 @@ import { useModeCtx } from './uses'
export default {
components: {
TinyPc,
TinyMobile,
TinyMobileFirst,
TinyButtonGroup: ButtonGroup,
TinyLink: Link,
@ -47,6 +50,7 @@ export default {
const state = hooks.reactive({
groupData: [
{ text: 'PC', value: 'pc' },
{ text: 'Mobile', value: 'mobile' },
{ text: 'Mobile-first', value: 'mobile-first' }
],
vueVersion: hooks.version,

View File

@ -0,0 +1,189 @@
<template>
<div class="wp100 hp100 f-r of-hidden">
<div class="w230 pt20 of-auto sm-hidden b-r bg-white" :class="{ 'fixed-menu': showFixedMenu }">
<tiny-tree-menu
class="!w213"
:data="menuData"
:filter-node-method="fn.searchMenu"
@current-change="fn.clickMenu"
></tiny-tree-menu>
</div>
<div class="fi-1 f-c px20 pb30 f-c pr200 of-auto">
<!-- 标题 -->
<div class="py20">
<component :is="state.currMd"></component>
</div>
<div id="preview" class="bg-white">
<div class="mb20 py10 pl16 child<code>p4 child<code>bg-lightless">
<div class="mr20 fw-bold">
{{ state.currDemo?.name['zh-CN'] }}( <span class="allselect">{{ state.currDemo?.codeFiles[0] }}</span
>):
</div>
<div v-html="state.currDemo?.desc['zh-CN']"></div>
</div>
<!-- 预览 -->
<div class="rel px20" :id="state.currDemo?.demoId">
<div class="phone-container" @dblclick="fn.openInVscode(state.currDemo)">
<div class="mobile-view-container">
<component :is="state.comp"></component>
</div>
</div>
</div>
</div>
<!-- API表格 -->
<div v-if="state.currApi?.length" class="mt20 f24 fw-bold">组件API</div>
<div v-for="(oneGroup, idx) in state.currApi" :key="idx">
<div class="mt20 f-r f-pos-start fw-bold">
<div :id="oneGroup.name" class="f18">
{{ oneGroup.name }}
</div>
<div class="ml12 b-a-primary c-primary px8 py4">
{{ oneGroup.type }}
</div>
</div>
<div v-for="(oneApiArr, key) in oneGroup" :key="key">
<div v-if="key !== 'name' && key !== 'type' && oneApiArr.length > 0">
<div class="f18 py28">
{{ key }}
</div>
<table class="api-table">
<thead>
<tr>
<th width="20%">名称</th>
<th width="15%">类型</th>
<th width="20%">默认值</th>
<th width="55%">说明</th>
</tr>
</thead>
<tbody>
<tr v-for="row in oneApiArr" :key="row.name">
<td>
<a v-if="row.demoId" class="c-primary h:c-error cur-hand" @click="fn.selectDemo(row.demoId)">{{
row.name
}}</a>
<span v-else>{{ row.name }}</span>
</td>
<td>{{ row.type }}</td>
<td v-html="typeof row.defaultValue === 'string' ? row.defaultValue || '--' : row.defaultValue"></td>
<td v-html="row.desc['zh-CN']"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 右边浮动所有的demos -->
<tiny-floatbar v-if="state.demos?.length > 0" class="!top120 !z1 !right25">
<div class="f12 ofy-auto">
<div
v-for="demo in state.demos"
:key="demo.demoId"
@click="fn.selectDemo(demo.demoId)"
class="w130 px10 py4 bg-light f-r f-pos-between"
:class="{ 'c-error': state.currDemo === demo }"
>
<div class="link-primary h:c-error h:td-under ellipsis">
{{ demo.name['zh-CN'] }}
<Icon-star-icon v-if="state.currDemo === demo" style="fill: #ee343f" />
</div>
<IconOpeninVscode @click.stop="fn.openInVscode(demo)" class="f18 cur-hand" />
</div>
</div>
</tiny-floatbar>
</div>
</template>
<script>
import { hooks } from '@opentiny/vue-common'
import { Floatbar, TreeMenu, Button, Tooltip } from '@opentiny/vue'
import { iconStarActive, iconSelect } from '@opentiny/vue-icon'
import { menuData, demos, demoStr, demoVue, mds } from './resourceMobile.js'
import { useModeCtx } from './uses'
import { getDemosConfig, getApisConfig } from './utils/componentsDoc'
export default {
props: {
showFixedMenu: Boolean
},
components: {
TinyFloatbar: Floatbar,
TinyTreeMenu: TreeMenu,
TinyButton: Button,
TinyTooltip: Tooltip,
IconStarIcon: iconStarActive(),
IconOpeninVscode: iconSelect()
},
setup() {
const { state: modeState, fn: modeFn } = useModeCtx()
const state = hooks.reactive({
demos: [], //
currDemo: null, // demo
currApi: [], // pathapi
comp: null, //
currDemoSrc: '',
currMd: hooks.computed(() => mds[`${modeState.pathName}.cn.md`])
})
const fn = {
//
searchMenu: (value, data) => {
if (!value) return true
return data.label.toLowerCase().includes(value.toLowerCase())
},
// path
clickMenu: async (menu) => {
if (menu.nameCn && menu.key !== state.key) {
modeState.pathName = menu.key
await _switchPath()
}
},
//
selectDemo: async (demoId) => {
const demo = state.demos.find((d) => d.demoId === demoId)
if (state.currDemo !== demo) {
state.currDemo = demo
await _switchDemo()
}
},
openInVscode: (demo) => {
fetch(`/__open-in-editor?file=../sites/demos/mobile/app/${modeState.pathName}/${demo.codeFiles[0]}`)
}
}
hooks.onMounted(() => {
_switchPath()
})
// vue
async function _switchPath() {
const demosModule = demos[`../../sites/demos/mobile/app/${modeState.pathName}/webdoc/${modeState.pathName}.js`]
const demosConfig = await getDemosConfig(demosModule)
state.demos = demosConfig.demos
state.currDemo = state.demos.find((d) => d.demoId === modeState.demoId) || state.demos?.[0]
state.currApi = (await getApisConfig(modeState.pathName, 'mobile')).apis
await _switchDemo()
}
async function _switchDemo() {
modeState.demoId = state.currDemo.demoId
const path = `../../sites/demos/mobile/app/${modeState.pathName}/${state.currDemo?.codeFiles[0]}`
//
state.currDemoSrc = await demoStr[path]()
const comp = await demoVue[path]()
state.comp = hooks.markRaw(comp.default)
modeFn.cacheCtx()
modeFn.pushToUrl()
}
return {
menuData,
state,
fn,
modeState,
modeFn
}
}
}
</script>

View File

@ -96,14 +96,8 @@
</div>
</div>
</tiny-floatbar>
<!-- 切换主题 暂时先屏蔽等后续其他主题验收完成再放出此功能 -->
<tiny-dropdown
v-if="false"
class="!fixed bottom20 right140"
:show-icon="false"
@item-click="changeTheme"
:disabled="isSaasMode"
>
<!-- 切换主题 -->
<tiny-dropdown class="!fixed bottom20 right140" :show-icon="false" @item-click="changeTheme" :disabled="isSaasMode">
<span title="切换主题">
<SvgTheme></SvgTheme>
</span>
@ -157,6 +151,8 @@ import {
} from '@opentiny/vue'
import { iconStarActive, iconSelect } from '@opentiny/vue-icon'
import Loading from '@opentiny/vue-loading'
import designSmbConfig from '@opentiny/vue-design-smb'
import designAuroraConfig from '@opentiny/vue-design-aurora'
import designSaasConfig from '@opentiny/vue-design-saas'
import { menuData, demoStr, demoVue, mds, demos } from './resourcePc.js'
import { useTheme, useModeCtx } from './uses'
@ -198,7 +194,7 @@ export default {
currMd: hooks.computed(() => mds[`${modeState.pathName}.cn.md`]),
demoLoading: false
})
// hui chart api api
// hui chart api api
const huiNewChart = ['chart-process']
const fn = {
//
@ -249,11 +245,9 @@ export default {
await _switchDemo()
}
async function _switchDemo() {
if (!state.currDemo) {
return
}
modeState.demoId = state.currDemo.demoId
const path = `../../sites/demos/pc/app/${getPath(modeState.pathName)}/${state.currDemo?.codeFiles[0]}`
//
state.currDemoSrc = await demoStr[path]()
const comp = await demoVue[path]()
@ -265,8 +259,8 @@ export default {
}
const designConfigMap = {
'tiny-smb-theme': {},
'tiny-aurora-theme': {}
'tiny-smb-theme': designSmbConfig,
'tiny-aurora-theme': designAuroraConfig
}
const lastThemeKey = localStorage.getItem('tinyThemeToolkey')

View File

@ -0,0 +1,32 @@
// eager = true可以校验vue,json等文件错误。
// eager = false, 可以懒加载,优化速度
// demo源码
// 同web-doc的菜单资源
import { cmpMenus } from '../../sites/demos/mobile/menus.js'
export const demoStr = import.meta.glob('../../sites/demos/mobile/app/**/*.vue', { eager: false, as: 'raw' })
export const demoVue = import.meta.glob('../../sites/demos/mobile/app/**/*.vue', { eager: false })
// demos配置
export const demos = import.meta.glob('../../sites/demos/mobile/app/*/webdoc/*.js', { eager: false })
// 组件的md
const allMD = import.meta.glob('../../sites/demos/mobile/app/*/webdoc/*.cn.md', { eager: true })
export const mds = {}
for (const path in allMD) {
let key = path.split('/').slice(-1)[0]
mds[key] = allMD[path].default
}
const menuData = cmpMenus.slice(0)
function processMenu(menu, isTop) {
menu.id = menu.key
menu.label = isTop ? menu.label : `${menu.nameCn} ${menu.name}`
if (menu.children && menu.children.length > 0) {
menu.children.forEach((m) => processMenu(m, false))
}
}
menuData.forEach((m) => processMenu(m, true))
export { menuData }

View File

@ -1,10 +1,6 @@
import { cmpMenus } from '../../sites/demos/mobile-first/menus.js'
export const demoStr = import.meta.glob('../../sites/demos/mobile-first/app/**/*.vue', {
eager: false,
query: '?raw',
import: 'default'
})
export const demoStr = import.meta.glob('../../sites/demos/mobile-first/app/**/*.vue', { eager: false, as: 'raw' })
export const demoVue = import.meta.glob('../../sites/demos/mobile-first/app/**/*.vue', { eager: false })
// demos配置

View File

@ -5,11 +5,7 @@
// 同web-doc的菜单资源
import { cmpMenus } from '../../sites/demos/pc/menus.js'
export const demoStr = import.meta.glob('../../sites/demos/pc/app/**/*.vue', {
eager: false,
query: '?raw',
import: 'default'
})
export const demoStr = import.meta.glob('../../sites/demos/pc/app/**/*.vue', { eager: false, as: 'raw' })
export const demoVue = import.meta.glob('../../sites/demos/pc/app/**/*.vue', { eager: false })
// demos配置

View File

@ -1,4 +1,5 @@
import TinyThemeTool from '@opentiny/vue-theme/theme-tool'
import { tinyAuroraTheme, tinySmbTheme, tinyInfinityTheme } from '@opentiny/vue-theme/theme'
import { hooks } from '@opentiny/vue-common'
import { Notify } from '@opentiny/vue'
@ -20,9 +21,9 @@ export function useTheme({ readCacheImmediate = true } = {}) {
const lastThemeKey = localStorage.getItem('tinyThemeToolkey')
const THEME_MAP = {
'tiny-aurora-theme': null,
'tiny-smb-theme': null,
'tiny-infinity-theme': null
'tiny-aurora-theme': tinyAuroraTheme,
'tiny-smb-theme': tinySmbTheme,
'tiny-infinity-theme': tinyInfinityTheme
}
const changeTheme = ({ vm }) => {

View File

@ -3,22 +3,24 @@
"type": "module",
"version": "1.0.8",
"description": "",
"keywords": [],
"author": "",
"license": "ISC",
"keywords": [],
"files": [
"resources"
],
"dependencies": {
"@opentiny/vue": "workspace:~",
"@opentiny/vue-common": "workspace:~",
"@opentiny/vue-design-aurora": "workspace:~",
"@opentiny/vue-design-saas": "workspace:~",
"@opentiny/vue-icon": "workspace:~",
"@opentiny/vue-theme-mobile": "workspace:~",
"@opentiny/vue-theme-saas": "workspace:~",
"@opentiny/vue-design-aurora": "workspace:~",
"@opentiny/vue-design-smb": "workspace:~",
"@opentiny/vue-design-saas": "workspace:~",
"sortablejs": "1.15.0"
},
"devDependencies": {
"@playwright/test": "catalog:"
}
}
"@playwright/test": "~1.42.0"
},
"files": [
"resources"
]
}

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Opentiny openinula 组件调试</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,29 @@
{
"name": "@opentiny/openinula-docs",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@opentiny/openinula": "workspace:~",
"openinula": "^0.1.1"
},
"devDependencies": {
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"@vitejs/plugin-react": "^4.0.1",
"eslint": "^8.44.0",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.16",
"typescript": "^5.0.2",
"vite": "^4.3.8",
"vite-plugin-svgr": "^3.2.0"
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
import { Alert } from '@opentiny/openinula'
// 在这里导入组件,进行 api 调试
function App() {
return (
<div className="app">
<Alert description="默认提示组件" />
</div>
)
}
export default App

View File

@ -0,0 +1,4 @@
.app {
margin: 10px;
width: 500px;
}

View File

@ -0,0 +1,5 @@
import Inula from 'openinula'
import App from './App.tsx'
import './main.css'
Inula.render(<App />, document.getElementById('root'))

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,16 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from 'vite-plugin-svgr'
const alias = {
react: 'openinula',
'react-dom': 'openinula',
'react/jsx-dev-runtime': 'openinula/jsx-dev-runtime'
}
export default defineConfig({
plugins: [svgr(), react({ include: /\.(mdx|js|jsx|ts|tsx)$/ })],
resolve: {
alias
}
})

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Opentiny React 组件调试</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,33 @@
{
"name": "@opentiny/react-docs",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@opentiny/react": "workspace:~",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"@vitejs/plugin-react": "^4.0.1",
"autoprefixer": "^10.4.12",
"eslint": "^8.44.0",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.16",
"tailwindcss": "^3.3.3",
"typescript": "^5.0.2",
"vite": "^4.3.8",
"vite-plugin-react": "^4.0.1",
"vite-plugin-svgr": "^3.2.0"
}
}

View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,18 @@
import { Button, Alert, Switch, Badge } from '@opentiny/react'
// 在这里导入组件,进行 api 调试
function App() {
return (
<div
className='app'
>
<Button></Button>
<Alert description='默认提示组件'/>
<Switch/>
<Badge value={10}></Badge>
</div>
)
}
export default App

View File

@ -0,0 +1,8 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.app {
margin: 10px;
width: 500px;
}

View File

@ -0,0 +1,8 @@
// import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './main.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<App />
)

View File

@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'../../packages/react/src/**/*.{css,less,vue,js,jsx,ts,tsx}',
'!../../packages/react/src/**/node_modules',
],
theme: {
extend: {},
},
plugins: [],
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from "vite-plugin-svgr";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({ include: /\.(mdx|js|jsx|ts|tsx)$/ }), svgr()
],
})

View File

@ -0,0 +1,15 @@
module.exports = {
printWidth: 160, // 一行120字符数如果超过会进行换行
tabWidth: 2, // tab等2个空格
useTabs: false, // 用空格缩进行
semi: true, // 行尾使用分号
singleQuote: true, // 字符串使用单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格
jsxBracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n
};

View File

@ -0,0 +1,6 @@
*.js
*.ts
*.png
*.eot
*.ttf
*.woff

View File

@ -0,0 +1,11 @@
module.exports = {
extends: "stylelint-config-standard",//stylelint-config-airbnb
rules: {
"string-quotes": "single",
"property-no-unknown": true,
"selector-pseudo-class-no-unknown": true,
"at-rule-empty-line-before": "always",
"block-no-empty": true,
"indentation": 4 // http://cui.ulanqab.huawei.com/#/articalDetail?id=b76da810d8ed8
}
};

View File

@ -0,0 +1,44 @@
# react 组件文档开发说明
## 命令
### 启动
```bash
pnpm start
```
### 打包
```bash
pnpm build
```
### 编译 react.jsx 为 react.js
```bash
pnpm build:react2
```
此 vue 项目vue自身需要 jsx所以使用 react 的 jsx只能将其编译为 .js 才能使用
## 开发说明
### 目录说明
主要是 demos 底下的文件是用来配置文档展示那些组件,以及写组件示例的
```b
demos
/app
/alert
/webdoc
/alert.json 配置 alert 组件的文档展示
/base.vue base 示例文件,导入 base.jsx注册 web comp
/base.jsx base 写 react 示例
/webdoc
/introduce.md 组件库的介绍文档
/menu.js 组件库的左侧菜单配置
/config.js demo 配置
/overviewimage 组件总览的图标,在这里添加图标
```

28
examples/react-site/components.d.ts vendored Normal file
View File

@ -0,0 +1,28 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
declare module '@vue/runtime-core' {
export interface GlobalComponents {
NAnchor: typeof import('naive-ui')['NAnchor']
NAnchorLink: typeof import('naive-ui')['NAnchorLink']
NCard: typeof import('naive-ui')['NCard']
NCode: typeof import('naive-ui')['NCode']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDataTable: typeof import('naive-ui')['NDataTable']
NInput: typeof import('naive-ui')['NInput']
NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTooltip: typeof import('naive-ui')['NTooltip']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}
export {}

View File

@ -0,0 +1,20 @@
import { Alert as TinyAlert } from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyAlert description="type 为默认值 success"></TinyAlert>
<TinyAlert type="error" description="type 为 error"></TinyAlert>
<TinyAlert type="info" description="type 为 info"></TinyAlert>
<TinyAlert type="warning" description="type 为 warning"></TinyAlert>
</App>
)
}
}

View File

@ -0,0 +1,15 @@
<template>
<div>
<alert-base-demo></alert-base-demo>
</div>
</template>
<script>
import AlertBase from '@/webcomps/alert/base.js'
customElements.define(
'alert-base-demo',
AlertBase
)
export default {
}
</script>

View File

@ -0,0 +1,17 @@
import { Alert as TinyAlert } from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyAlert center description="文字居中"></TinyAlert>
</App>
)
}
}

View File

@ -0,0 +1,9 @@
<template>
<alert-center-demo></alert-center-demo>
</template>
<script lang="jsx">
import AlertCenter from "@/webcomps/alert/center.js";
customElements.define("alert-center-demo", AlertCenter);
export default {};
</script>

View File

@ -0,0 +1,18 @@
import { Alert as TinyAlert } from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyAlert size="normal" description="size 为 normal"></TinyAlert>
<TinyAlert size="large" title="size 为 large"></TinyAlert>
</App>
)
}
}

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-size-demo></alert-size-demo>
</div>
</template>
<script>
import AlertSize from "@/webcomps/alert/size.js";
customElements.define("alert-size-demo", AlertSize);
export default {};
</script>

View File

@ -0,0 +1,25 @@
import { Alert as TinyAlert } from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyAlert size="large" title="通过属性设置自定义 title"></TinyAlert>
<br/>
<TinyAlert
size="large"
slots={{
title: () => '通过 slot 设置自定义 title'
}}
>
</TinyAlert>
</App>
)
}
}

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-title-demo></alert-title-demo>
</div>
</template>
<script lang="jsx">
import AlertTitle from "@/webcomps/alert/title.js";
customElements.define("alert-title-demo", AlertTitle);
export default {};
</script>

View File

@ -0,0 +1,21 @@
import { Alert as TinyAlert } from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyAlert description="type 为默认值 success"></TinyAlert>
<TinyAlert type="info" description="type 为 info"></TinyAlert>
<TinyAlert type="error" description="type 为 error"></TinyAlert>
<TinyAlert type="success" description="type 为 success"></TinyAlert>
<TinyAlert type="warning" description="type 为 warning"></TinyAlert>
</App>
)
}
}

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-type-demo></alert-type-demo>
</div>
</template>
<script lang="jsx">
import AlertType from "@/webcomps/alert/type.js";
customElements.define("alert-type-demo", AlertType);
export default {};
</script>

View File

@ -0,0 +1,7 @@
---
title: Alert 警告
---
# Alert 警告
<div>Alert 警告,提供 warning、error、info、success 四种类型显示不同类别的信息。</div>

View File

@ -0,0 +1,7 @@
---
title: Alert
---
# Alert
<div>Alert alarms, including warning, error, info, and success.</div>

View File

@ -0,0 +1,228 @@
{
"column": "2",
"owner": "",
"demos": [
{
"demoId": "base",
"name": {
"zh-CN": "基本用法",
"en-US": "Basic Usage"
},
"desc": {
"zh-CN": "详细用法参考如下示例",
"en-US": "For details, see the following example."
},
"codeFiles": [
"base.vue"
]
},
{
"demoId": "type",
"name": {
"zh-CN": "类型",
"en-US": "Type"
},
"desc": {
"zh-CN": "<p>通过 <code>type</code> 设置不同的类型。可选值success、warning、info、error默认值success 。</p>\n",
"en-US": "<p>Set different types through <code>type</code>. The options are success, warning, info, and error. The default value is success. </p>\n"
},
"codeFiles": [
"type.vue"
]
},
{
"demoId": "size",
"name": {
"zh-CN": "大尺寸",
"en-US": "Large Size"
},
"desc": {
"zh-CN": "<p>通过 <code>size</code> 属性设置不同的尺寸可选值nomal、large默认值nomal 。</p>\n",
"en-US": "<p>Set different sizes through the <code>size</code> attribute. The options are nomal and large. The default value is nomal. </p>\n"
},
"codeFiles": [
"size.vue"
]
},
{
"demoId": "title",
"name": {
"zh-CN": "自定义标题",
"en-US": "Custom Title"
},
"desc": {
"zh-CN": "<p>当 <code>size</code> 为 large 时显示标题,可设置 <code>title</code> 或 <code>slot</code> 自定义标题。默认标题根据设置的 <code>type</code> 显示。</p>\n",
"en-US": "<p>When <code>size</code> is set to large, the title is displayed. You can set <code>title</code> or <code>slot</code> to customize the title. The default title is displayed according to the set <code>type</code>. </p>\n"
},
"codeFiles": [
"title.vue"
]
},
{
"demoId": "center",
"name": {
"zh-CN": "文字居中",
"en-US": "Center text"
},
"desc": {
"zh-CN": "<p>通过 <code>center</code> 属性可使文字显示居中。</p>\n",
"en-US": "<p>You can use the <code>center</code> property to center the text. </p>\n"
},
"codeFiles": [
"center.vue"
]
}
],
"apis": [
{
"name": "alert",
"type": "component",
"properties": [
{
"name": "closable",
"type": "Boolean",
"defaultValue": "该属性的默认值为 true",
"desc": {
"zh-CN": "设置警告是否可以关闭",
"en-US": "Set whether alarms can be disabled."
},
"demoId": "closable"
},
{
"name": "icon",
"type": "String , Object",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的图标,默认会根据 type 值自动使用对应图标",
"en-US": "Set the alarm icon. By default, the corresponding icon is automatically used based on the value of type."
},
"demoId": "icon"
},
{
"name": "size",
"type": "String",
"defaultValue": "该属性的默认值为 normal",
"desc": {
"zh-CN": "设置警告的大小 nomal/large 缺省为 nomal。;该属性的可选值为 nomal / large",
"en-US": "Set the warning size to nomal or large. The default value is nomal. ;The value of this attribute can be nomal or large"
},
"demoId": "size"
},
{
"name": "title",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的标题,在 size 为 large 时有效,默认根据 type 自动设置",
"en-US": "Set the warning title. This parameter is valid only when size is set to large. By default, the alarm title is automatically set based on type."
},
"demoId": "title"
},
{
"name": "type",
"type": "String",
"defaultValue": "该属性的默认值为 success",
"desc": {
"zh-CN": "设置警告的类型;该属性的可选值为 success/warning/info/error",
"en-US": "Set the alarm type. The value of this attribute can be success / warning / info / error"
},
"demoId": "type"
},
{
"name": "description",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的提示内容,默认为空;",
"en-US": "Set the warning prompt content. The default value is null."
},
"demoId": "custom-description"
},
{
"name": "center",
"type": "Boolean",
"defaultValue": "该属性的默认值为 false",
"desc": {
"zh-CN": "文字是否居中",
"en-US": "Whether the text is centered"
},
"demoId": "center"
},
{
"name": "close-text",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "关闭按钮自定义文本",
"en-US": "Customized text of the close button"
},
"demoId": "close-text"
},
{
"name": "show-icon",
"type": "Boolean",
"defaultValue": "该属性的默认值为 true",
"desc": {
"zh-CN": "是否显示图标",
"en-US": "Display icon"
},
"demoId": "show-icon"
}
],
"events": [
{
"name": "close",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "关闭 alert 时触发的事件",
"en-US": "Event triggered when the alert function is disabled"
},
"demoId": "close-events"
}
],
"slots": [
{
"name": "default",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "组件默认插槽",
"en-US": "Default slot of the component"
},
"demoId": "slot-default"
},
{
"name": "title",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "标题的内容",
"en-US": "Title content"
},
"demoId": "title"
},
{
"name": "description",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "提示内容",
"en-US": "Prompt Content"
},
"demoId": "custom-description"
},
{
"name": "close",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "自定义关闭按钮,当 closable 属性为 false 时有效",
"en-US": ""
},
"demoId": "custom-close"
}
]
}
]
}

View File

@ -0,0 +1,17 @@
import { Button as TinyButton} from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyButton>默认按钮</TinyButton>
</App>
)
}
}

View File

@ -0,0 +1,9 @@
<template>
<button-click-demo></button-click-demo>
</template>
<script>
import ButtonClick from "@/webcomps/button/button-click-webcomp.js";
customElements.define("button-click-demo", ButtonClick);
export default {};
</script>

View File

@ -0,0 +1,18 @@
import { Button as TinyButton} from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyButton round type='primary'>主要按钮</TinyButton>
</App>
)
}
}

View File

@ -0,0 +1,8 @@
<template>
<button-round-demo></button-round-demo>
</template>
<script>
import ButtonRound from "@/webcomps/button/button-round-webcomp.js";
customElements.define("button-round-demo", ButtonRound);
export default {};
</script>

View File

@ -0,0 +1,18 @@
import { Button as TinyButton} from '@pe-3/react'
import ReactDOM from 'react-dom/client'
function App(props) {
return (<div>
{props.children}
</div>)
}
export default class extends HTMLElement {
connectedCallback() {
ReactDOM.createRoot(this).render(
<App>
<TinyButton type='success'>成功按钮</TinyButton>
</App>
)
}
}

View File

@ -0,0 +1,8 @@
<template>
<button-type-demo></button-type-demo>
</template>
<script>
import ButtonType from "@/webcomps/button/button-type-webcomp.js";
customElements.define("button-type-demo", ButtonType);
export default {};
</script>

View File

@ -0,0 +1,16 @@
---
title: Button 按钮
---
# Button 按钮
<div>
按钮组件一般用于触发一些操作。
```typescript
import { Button } from '@opentiny/vue';
```
</div>

View File

@ -0,0 +1,8 @@
---
title: Button 按钮
---
# Button 按钮
<div> 按钮组件一般用于触发一些操作。</div>

View File

@ -0,0 +1,71 @@
{
"column": "2",
"demos": [
{
"demoId": "button-type",
"name": {
"zh-CN": "按钮类型",
"en-US": "button type"
},
"desc": {
"zh-CN": "<p>通过属性<code>type</code>配置按钮类型,包含<code>success</code>、<code>info</code>、<code>warning</code>、<code>danger</code>四种类型。",
"en-US": "<p>button type</p>"
},
"codeFiles": ["button-type.vue"]
},
{
"demoId": "button-round",
"name": {
"zh-CN": "圆角按钮",
"en-US": "button round"
},
"desc": {
"zh-CN": "<p>通过<code>round</code>属性设置按钮是否圆角",
"en-US": "<p>button round</p>"
},
"codeFiles": ["button-round.vue"]
},
{
"demoId": "button-click",
"name": {
"zh-CN": "事件",
"en-US": "events"
},
"desc": {
"zh-CN": "<p>按钮点击事件。",
"en-US": "<p>bbutton click</p>"
},
"codeFiles": ["button-click.vue"]
}
],
"apis": [
{
"name": "Button",
"type": "component",
"properties": [
{
"name": "type",
"type": "primary | success | warning",
"defaultValue": "",
"desc": {
"zh-CN": "<p>展示按钮不同的状态</p>",
"en-US": "display different button"
},
"demoId": "button-type"
}
],
"events": [
{
"name": "click",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "<p>点击按钮时触发的回调</p>",
"en-US": "Click"
},
"demoId": "button-click"
}
]
}
]
}

4
examples/react-site/demos/config.js vendored Normal file
View File

@ -0,0 +1,4 @@
export default {
isMobile: false,
initApp: (app) => { }
}

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="125px" height="125px" viewBox="0 0 125 125" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Button按钮</title>
<defs>
<linearGradient x1="50%" y1="45.9685271%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#ECF3FB" offset="0%"></stop>
<stop stop-color="#FFFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50.3956523%" y1="35.9331967%" x2="50%" y2="64.0668033%" id="linearGradient-2">
<stop stop-color="#E3EFFD" stop-opacity="0.00575352382" offset="0%"></stop>
<stop stop-color="#E5F0FD" offset="34.0601199%"></stop>
<stop stop-color="#F0F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="33.3333333%" y1="34.495573%" x2="96.9740837%" y2="65.4421891%" id="linearGradient-3">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#F7FBFF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="90.9912104%" y1="29.4309598%" x2="33.3333333%" y2="67.7472684%" id="linearGradient-4">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#E7F0F9" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-5">
<stop stop-color="#CEE6FE" offset="0%"></stop>
<stop stop-color="#8AB5F2" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-6">
<stop stop-color="#BFD6F9" offset="0%"></stop>
<stop stop-color="#F3F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="89.8473889%" y1="61.7348066%" x2="0%" y2="61.7348066%" id="linearGradient-7">
<stop stop-color="#CAD9F3" offset="0%"></stop>
<stop stop-color="#D5E3F7" offset="100%"></stop>
</linearGradient>
<filter x="-18.5%" y="-60.0%" width="136.9%" height="220.0%" filterUnits="objectBoundingBox" id="filter-8">
<feGaussianBlur stdDeviation="4" in="SourceGraphic"></feGaussianBlur>
</filter>
<linearGradient x1="44.0988019%" y1="53.2030982%" x2="128.792906%" y2="41.8419999%" id="linearGradient-9">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="44.0988019%" y1="54.0931841%" x2="128.792906%" y2="39.5750321%" id="linearGradient-10">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="44.0988019%" y1="54.0931841%" x2="128.792906%" y2="39.5750321%" id="linearGradient-11">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-12">
<stop stop-color="#FFCC00" offset="0%"></stop>
<stop stop-color="#FF9D00" offset="100%"></stop>
</linearGradient>
<circle id="path-13" cx="76" cy="45" r="8"></circle>
<filter x="-43.8%" y="-31.2%" width="187.5%" height="187.5%" filterUnits="objectBoundingBox" id="filter-14">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feMorphology radius="4" operator="erode" in="SourceAlpha" result="shadowInner"></feMorphology>
<feOffset dx="0" dy="2" in="shadowInner" result="shadowInner"></feOffset>
<feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out" result="shadowOffsetOuter1"></feComposite>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.661752894 0 0 0 0 0.324547702 0 0 0 0 0.00489962574 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<filter x="-46.9%" y="-34.4%" width="193.8%" height="193.8%" filterUnits="objectBoundingBox" id="filter-15">
<feGaussianBlur stdDeviation="1.5" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
<feOffset dx="0" dy="-4" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
<feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
<feColorMatrix values="0 0 0 0 0.841553619 0 0 0 0 0.341832308 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
</filter>
<polygon id="path-16" points="75.7129876 43.8022814 74.2754034 57.814413 78.9449685 55.9202277 81.4194729 62.8022814 83.8096817 61.7804537 81.2116343 54.9762941 85.8108161 53.4874666"></polygon>
<filter x="-47.7%" y="-18.4%" width="195.4%" height="157.9%" filterUnits="objectBoundingBox" id="filter-17">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="页面一" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="-TinyUI-ICON-1-【9-2】-无阴影" transform="translate(-697.000000, -327.000000)">
<g id="Button按钮" transform="translate(697.000000, 327.000000)">
<g id="编组">
<g transform="translate(9.000000, 1.000000)" id="多边形">
<polygon fill="url(#linearGradient-1)" opacity="0.54620216" points="53.2605623 0 106.521125 30.75 53.2605623 62 0 30.75"></polygon>
<polygon fill="url(#linearGradient-2)" points="53.2605623 61.5 106.521125 86.75 53.2605623 118 0 86.75"></polygon>
<polygon fill="url(#linearGradient-3)" opacity="0.600606283" points="53.2605623 62 53.2605623 123 7.39138783e-15 92.25 0 30.75"></polygon>
<polygon fill="url(#linearGradient-4)" opacity="0.791265578" points="53.2605623 62 106.521125 30.75 106.521125 92.25 53.2605623 123"></polygon>
<polygon fill="url(#linearGradient-5)" points="53.2605623 118.007802 53.2605623 123 7.39138783e-15 92.25 0 86.9161706"></polygon>
<polygon fill="url(#linearGradient-6)" transform="translate(79.630281, 104.958085) scale(-1, 1) translate(-79.630281, -104.958085) " points="106.260562 118.007802 106.260562 123 53 92.25 53 86.9161706"></polygon>
</g>
<ellipse id="椭圆形" fill="url(#linearGradient-7)" filter="url(#filter-8)" cx="62.5" cy="90" rx="32.5" ry="10"></ellipse>
</g>
<g id="编组" transform="translate(17.000000, 38.000000)">
<rect id="矩形备份" fill="url(#linearGradient-9)" opacity="0.303770519" x="7" y="0" width="78" height="23" rx="4"></rect>
<rect id="矩形" stroke="url(#linearGradient-11)" fill="url(#linearGradient-10)" x="0" y="16" width="90" height="30" rx="4"></rect>
<path d="M14.784,25.576 L14.784,27.176 L18.528,27.176 L18.528,37 L20.4,37 L20.4,27.176 L24.144,27.176 L24.144,25.576 L14.784,25.576 Z M26.576,25.352 C26.224,25.352 25.936,25.464 25.696,25.688 C25.456,25.912 25.344,26.2 25.344,26.552 C25.344,26.904 25.456,27.192 25.696,27.432 C25.936,27.656 26.224,27.768 26.576,27.768 C26.928,27.768 27.216,27.656 27.456,27.432 C27.696,27.208 27.824,26.904 27.824,26.552 C27.824,26.2 27.696,25.912 27.472,25.688 C27.232,25.464 26.928,25.352 26.576,25.352 Z M25.664,28.728 L25.664,37 L27.488,37 L27.488,28.728 L25.664,28.728 Z M33.456,28.504 C32.16,28.504 31.152,28.936 30.432,29.8 C29.76,30.584 29.424,31.608 29.424,32.856 C29.424,34.136 29.76,35.176 30.448,35.976 C31.152,36.808 32.144,37.224 33.424,37.224 C34.496,37.224 35.36,36.952 36,36.424 C36.656,35.88 37.088,35.048 37.28,33.928 L35.472,33.928 C35.328,35.128 34.656,35.736 33.44,35.736 C32.736,35.736 32.208,35.48 31.856,34.984 C31.472,34.472 31.296,33.752 31.296,32.84 C31.296,31.944 31.488,31.24 31.872,30.744 C32.256,30.232 32.784,29.992 33.456,29.992 C34,29.992 34.448,30.12 34.784,30.376 C35.104,30.632 35.328,31.016 35.44,31.544 L37.248,31.544 C37.088,30.504 36.672,29.736 36.016,29.224 C35.376,28.744 34.528,28.504 33.456,28.504 Z M38.72,25.352 L38.72,37 L40.544,37 L40.544,34.104 L41.376,33.32 L44.272,37 L46.608,37 L42.624,32.152 L46.288,28.728 L43.936,28.728 L40.544,32.008 L40.544,25.352 L38.72,25.352 Z M53.056,25.576 L53.056,37 L54.928,37 L54.928,29.128 L54.992,29.128 L58.352,37 L59.968,37 L63.328,29.128 L63.392,29.128 L63.392,37 L65.264,37 L65.264,25.576 L63.072,25.576 L59.2,34.536 L59.136,34.536 L55.248,25.576 L53.056,25.576 Z M70.864,28.504 C69.632,28.504 68.656,28.92 67.952,29.768 C67.216,30.6 66.864,31.624 66.864,32.856 C66.864,34.232 67.248,35.304 68.016,36.088 C68.736,36.84 69.712,37.224 70.944,37.224 C72.048,37.224 72.96,36.904 73.696,36.28 C74.272,35.768 74.656,35.112 74.848,34.344 L73.024,34.344 C72.8,34.808 72.56,35.144 72.288,35.352 C71.936,35.608 71.488,35.736 70.928,35.736 C70.272,35.736 69.76,35.528 69.408,35.128 C69.056,34.728 68.848,34.136 68.784,33.368 L74.976,33.368 C74.976,31.88 74.64,30.712 73.984,29.88 C73.264,28.952 72.224,28.504 70.864,28.504 Z M70.912,29.992 C72.192,29.992 72.912,30.648 73.072,31.992 L68.816,31.992 C68.928,31.336 69.152,30.84 69.488,30.504 C69.84,30.152 70.304,29.992 70.912,29.992 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path>
<g id="椭圆形">
<use fill="black" fill-opacity="1" filter="url(#filter-14)" xlink:href="#path-13"></use>
<use fill="black" fill-opacity="1" filter="url(#filter-15)" xlink:href="#path-13"></use>
<circle stroke="url(#linearGradient-12)" stroke-width="4" stroke-linejoin="square" cx="76" cy="45" r="6"></circle>
</g>
<g id="路径-2">
<use fill="black" fill-opacity="1" filter="url(#filter-17)" xlink:href="#path-16"></use>
<use fill="#000000" fill-rule="evenodd" xlink:href="#path-16"></use>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="130px" height="125px" viewBox="0 0 130 125" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Buttongroup选块组</title>
<defs>
<linearGradient x1="50%" y1="45.9685271%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#ECF3FB" offset="0%"></stop>
<stop stop-color="#FFFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50.3956523%" y1="35.9331967%" x2="50%" y2="64.0668033%" id="linearGradient-2">
<stop stop-color="#E3EFFD" stop-opacity="0.00575352382" offset="0%"></stop>
<stop stop-color="#E5F0FD" offset="34.0601199%"></stop>
<stop stop-color="#F0F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="33.3333333%" y1="34.495573%" x2="96.9740837%" y2="65.4421891%" id="linearGradient-3">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#F7FBFF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="90.9912104%" y1="29.4309598%" x2="33.3333333%" y2="67.7472684%" id="linearGradient-4">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#E7F0F9" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-5">
<stop stop-color="#CEE6FE" offset="0%"></stop>
<stop stop-color="#8AB5F2" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-6">
<stop stop-color="#BFD6F9" offset="0%"></stop>
<stop stop-color="#F3F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="89.8473889%" y1="61.7348066%" x2="0%" y2="61.7348066%" id="linearGradient-7">
<stop stop-color="#CAD9F3" offset="0%"></stop>
<stop stop-color="#D5E3F7" offset="100%"></stop>
</linearGradient>
<filter x="-18.5%" y="-60.0%" width="136.9%" height="220.0%" filterUnits="objectBoundingBox" id="filter-8">
<feGaussianBlur stdDeviation="4" in="SourceGraphic"></feGaussianBlur>
</filter>
<linearGradient x1="44.0988019%" y1="63.2619166%" x2="128.792906%" y2="16.2231039%" id="linearGradient-9">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="44.0988019%" y1="63.2619166%" x2="128.792906%" y2="16.2231039%" id="linearGradient-10">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<text id="text-11" font-family="PingFangSC-Semibold, PingFang SC" font-size="16" font-weight="500" fill="#FFFFFF">
<tspan x="16.72" y="18">1</tspan>
</text>
<filter x="-5.0%" y="-5.3%" width="110.0%" height="121.1%" filterUnits="objectBoundingBox" id="filter-12">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.31372549 0 0 0 0 0.450980392 0 0 0 0 0.898039216 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<text id="text-13" font-family="PingFangSC-Semibold, PingFang SC" font-size="16" font-weight="500" fill="#FFFFFF">
<tspan x="59.2" y="18">2</tspan>
</text>
<filter x="-5.0%" y="-5.3%" width="110.0%" height="121.1%" filterUnits="objectBoundingBox" id="filter-14">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.31372549 0 0 0 0 0.450980392 0 0 0 0 0.898039216 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<text id="text-15" font-family="PingFangSC-Semibold, PingFang SC" font-size="16" font-weight="500" fill="#FFFFFF">
<tspan x="103.2" y="18">3</tspan>
</text>
<filter x="-5.0%" y="-5.3%" width="110.0%" height="121.1%" filterUnits="objectBoundingBox" id="filter-16">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.31372549 0 0 0 0 0.450980392 0 0 0 0 0.898039216 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-17">
<stop stop-color="#FFCC00" offset="0%"></stop>
<stop stop-color="#FF9D00" offset="100%"></stop>
</linearGradient>
<circle id="path-18" cx="77" cy="74" r="8"></circle>
<filter x="-43.8%" y="-31.2%" width="187.5%" height="187.5%" filterUnits="objectBoundingBox" id="filter-19">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feMorphology radius="4" operator="erode" in="SourceAlpha" result="shadowInner"></feMorphology>
<feOffset dx="0" dy="2" in="shadowInner" result="shadowInner"></feOffset>
<feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out" result="shadowOffsetOuter1"></feComposite>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.661752894 0 0 0 0 0.324547702 0 0 0 0 0.00489962574 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<filter x="-46.9%" y="-34.4%" width="193.8%" height="193.8%" filterUnits="objectBoundingBox" id="filter-20">
<feGaussianBlur stdDeviation="1.5" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
<feOffset dx="0" dy="-4" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
<feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
<feColorMatrix values="0 0 0 0 0.841553619 0 0 0 0 0.341832308 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
</filter>
<polygon id="path-21" points="76.7129876 72.8022814 75.2754034 86.814413 79.9449685 84.9202277 82.4194729 91.8022814 84.8096817 90.7804537 82.2116343 83.9762941 86.8108161 82.4874666"></polygon>
<filter x="-47.7%" y="-18.4%" width="195.4%" height="157.9%" filterUnits="objectBoundingBox" id="filter-22">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="页面一" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="-TinyUI-ICON-1-【9-2】-无阴影" transform="translate(-1480.000000, -574.000000)">
<g id="Buttongroup选块组" transform="translate(1481.000000, 574.000000)">
<g id="编组" transform="translate(1.000000, 0.000000)">
<g transform="translate(9.000000, 1.000000)" id="多边形">
<polygon fill="url(#linearGradient-1)" opacity="0.54620216" points="53.2605623 0 106.521125 30.75 53.2605623 62 0 30.75"></polygon>
<polygon fill="url(#linearGradient-2)" points="53.2605623 61.5 106.521125 86.75 53.2605623 118 0 86.75"></polygon>
<polygon fill="url(#linearGradient-3)" opacity="0.600606283" points="53.2605623 62 53.2605623 123 7.39138783e-15 92.25 0 30.75"></polygon>
<polygon fill="url(#linearGradient-4)" opacity="0.791265578" points="53.2605623 62 106.521125 30.75 106.521125 92.25 53.2605623 123"></polygon>
<polygon fill="url(#linearGradient-5)" points="53.2605623 118.007802 53.2605623 123 7.39138783e-15 92.25 0 86.9161706"></polygon>
<polygon fill="url(#linearGradient-6)" transform="translate(79.630281, 104.958085) scale(-1, 1) translate(-79.630281, -104.958085) " points="106.260562 118.007802 106.260562 123 53 92.25 53 86.9161706"></polygon>
</g>
<ellipse id="椭圆形" fill="url(#linearGradient-7)" filter="url(#filter-8)" cx="62.5" cy="90" rx="32.5" ry="10"></ellipse>
</g>
<g id="编组-11" transform="translate(0.000000, 49.000000)">
<rect id="矩形备份" stroke="url(#linearGradient-10)" fill="url(#linearGradient-9)" x="88" y="0" width="40" height="24" rx="2"></rect>
<rect id="矩形" stroke="url(#linearGradient-10)" fill="url(#linearGradient-9)" x="0" y="0" width="40" height="24" rx="2"></rect>
<rect id="矩形" stroke="url(#linearGradient-10)" fill="url(#linearGradient-9)" x="44" y="0" width="40" height="24" rx="2"></rect>
<g id="1" fill="#FFFFFF" fill-opacity="1">
<use filter="url(#filter-12)" xlink:href="#text-11"></use>
<use xlink:href="#text-11"></use>
</g>
<g id="2" fill="#FFFFFF" fill-opacity="1">
<use filter="url(#filter-14)" xlink:href="#text-13"></use>
<use xlink:href="#text-13"></use>
</g>
<g id="3" fill="#FFFFFF" fill-opacity="1">
<use filter="url(#filter-16)" xlink:href="#text-15"></use>
<use xlink:href="#text-15"></use>
</g>
</g>
<g id="椭圆形">
<use fill="black" fill-opacity="1" filter="url(#filter-19)" xlink:href="#path-18"></use>
<use fill="black" fill-opacity="1" filter="url(#filter-20)" xlink:href="#path-18"></use>
<circle stroke="url(#linearGradient-17)" stroke-width="4" stroke-linejoin="square" cx="77" cy="74" r="6"></circle>
</g>
<g id="路径-2">
<use fill="black" fill-opacity="1" filter="url(#filter-22)" xlink:href="#path-21"></use>
<use fill="#000000" fill-rule="evenodd" xlink:href="#path-21"></use>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="125px" height="125px" viewBox="0 0 125 125" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Modal 弹出框</title>
<defs>
<linearGradient x1="50%" y1="45.9685271%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#ECF3FB" offset="0%"></stop>
<stop stop-color="#FFFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50.3956523%" y1="35.9331967%" x2="50%" y2="64.0668033%" id="linearGradient-2">
<stop stop-color="#E3EFFD" stop-opacity="0.00575352382" offset="0%"></stop>
<stop stop-color="#E5F0FD" offset="34.0601199%"></stop>
<stop stop-color="#F0F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="33.3333333%" y1="34.495573%" x2="96.9740837%" y2="65.4421891%" id="linearGradient-3">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#F7FBFF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="90.9912104%" y1="29.4309598%" x2="33.3333333%" y2="67.7472684%" id="linearGradient-4">
<stop stop-color="#D5E6F9" offset="0%"></stop>
<stop stop-color="#E7F0F9" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-5">
<stop stop-color="#CEE6FE" offset="0%"></stop>
<stop stop-color="#8AB5F2" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-5.8027489%" y1="27.0499439%" x2="103.630422%" y2="71.1332543%" id="linearGradient-6">
<stop stop-color="#BFD6F9" offset="0%"></stop>
<stop stop-color="#F3F6FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="89.8473889%" y1="61.7348066%" x2="0%" y2="61.7348066%" id="linearGradient-7">
<stop stop-color="#CAD9F3" offset="0%"></stop>
<stop stop-color="#D5E3F7" offset="100%"></stop>
</linearGradient>
<filter x="-18.5%" y="-60.0%" width="136.9%" height="220.0%" filterUnits="objectBoundingBox" id="filter-8">
<feGaussianBlur stdDeviation="4" in="SourceGraphic"></feGaussianBlur>
</filter>
<linearGradient x1="44.0988019%" y1="76.9198201%" x2="128.792906%" y2="-18.5623347%" id="linearGradient-9">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="44.0988019%" y1="86.8386573%" x2="128.792906%" y2="-43.8247114%" id="linearGradient-10">
<stop stop-color="#5073E5" offset="0%"></stop>
<stop stop-color="#5E7CE0" offset="100%"></stop>
</linearGradient>
</defs>
<g id="页面一" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-17备份" transform="translate(-98.000000, -33.000000)">
<g id="Modal-弹出框" transform="translate(98.000000, 33.000000)">
<g id="编组">
<g transform="translate(9.000000, 1.000000)" id="多边形">
<polygon fill="url(#linearGradient-1)" opacity="0.54620216" points="53.2605623 0 106.521125 30.75 53.2605623 62 0 30.75"></polygon>
<polygon fill="url(#linearGradient-2)" points="53.2605623 61.5 106.521125 86.75 53.2605623 118 0 86.75"></polygon>
<polygon fill="url(#linearGradient-3)" opacity="0.600606283" points="53.2605623 62 53.2605623 123 7.39138783e-15 92.25 0 30.75"></polygon>
<polygon fill="url(#linearGradient-4)" opacity="0.791265578" points="53.2605623 62 106.521125 30.75 106.521125 92.25 53.2605623 123"></polygon>
<polygon fill="url(#linearGradient-5)" points="53.2605623 118.007802 53.2605623 123 7.39138783e-15 92.25 0 86.9161706"></polygon>
<polygon fill="url(#linearGradient-6)" transform="translate(79.630281, 104.958085) scale(-1, 1) translate(-79.630281, -104.958085) " points="106.260562 118.007802 106.260562 123 53 92.25 53 86.9161706"></polygon>
</g>
<ellipse id="椭圆形" fill="url(#linearGradient-7)" filter="url(#filter-8)" cx="62.5" cy="90" rx="32.5" ry="10"></ellipse>
</g>
<g id="编组-2" transform="translate(29.000000, 36.000000)">
<path d="M6.62941176,0 L15.978448,0 L15.978448,0 L60.6294118,0 C62.8385508,3.51840692e-15 64.6294118,1.790861 64.6294118,4 L64.6294118,49 C64.6294118,51.209139 62.8385508,53 60.6294118,53 L6.62941176,53 C4.42027277,53 2.62941176,51.209139 2.62941176,49 L2.62941176,4 C2.62941176,1.790861 4.42027277,4.05812251e-16 6.62941176,0 Z" id="矩形" fill="url(#linearGradient-9)" opacity="0.204287574"></path>
<g id="编组-36" transform="translate(20.000000, 24.000000)" fill="url(#linearGradient-10)" opacity="0.303770519">
<path d="M18.4437368,13.7577425 C18.4437368,13.7577425 15.2259452,14.6049856 12.9881281,18.3439942 C13.1341609,18.3730232 18.9409919,24.2443166 18.9409919,24.2443166 C19.9794472,25.2518945 21.6760641,25.2518945 22.7145194,24.2443166 L24.2211585,22.7837505 C25.2596138,21.7761726 25.2596138,20.1404196 24.2211585,19.1325041 L18.4437368,13.7577425 Z M21.0618476,23.2364011 C20.7985153,23.4844982 20.3746146,23.4844982 20.1258181,23.2364011 L15.2844259,18.5482102 C15.0210936,18.2997755 15.0210936,17.8910061 15.2844259,17.6425714 C15.5477581,17.3944744 15.9716588,17.3944744 16.2204554,17.6425714 L21.0618476,22.3307624 C21.3106442,22.5643449 21.3106442,22.9734519 21.0618476,23.2364011 L21.0618476,23.2364011 Z M23.1827032,21.1770265 C22.919371,21.4251236 22.4954703,21.4251236 22.2466737,21.1770265 L17.3907458,16.4888356 C17.1274136,16.240401 17.1274136,15.8316315 17.3907458,15.5831969 C17.6540781,15.3350998 18.0779788,15.3350998 18.3267754,15.5831969 L23.1681676,20.2717254 C23.4460355,20.5053079 23.4460355,20.9140774 23.1827032,21.1770265 L23.1827032,21.1770265 Z M6.21619612,7.85742013 L10.1506301,11.7716157 L12.0375629,9.93130918 L8.10312889,6.03196571 L9.03915842,5.11181246 L3.7735275,0 L0,3.65124639 L5.28016659,8.7627213 L6.21619612,7.85742013 Z" id="形状"></path>
<path d="M19.1460887,11.1222365 C19.2907188,11.1656758 19.4062892,11.209115 19.5509193,11.2669227 C20.2446759,11.4837848 20.9962177,11.5559608 21.7043371,11.4981532 C23.0193683,11.3825379 24.3200367,10.8331983 25.3174162,9.82106358 C26.5025142,8.64987429 27.0660036,7.04529483 26.9938556,5.46911797 C26.9938556,5.41131034 26.9938556,5.35350271 26.9794928,5.29569508 L24.4072156,5.29569508 L23.3811105,6.32219822 L22.600509,7.10276831 L21.8055448,7.89804093 L19.6664897,7.33433299 L19.0883035,5.19444819 L19.8832678,4.39917557 L20.6635352,3.61827132 L21.6896403,2.59176818 L21.6896403,0.0184932199 C21.6318551,0.0184932199 21.5453443,0.00412484915 21.487225,0.00412484915 C19.941053,-0.0536827822 18.3511245,0.495656789 17.1516637,1.68121445 C16.1399214,2.69334922 15.576432,3.98015378 15.4752244,5.29569508 C15.4174392,6.09096769 15.50395,6.88590616 15.7641505,7.63773952 C15.7641505,7.65210789 15.7785133,7.66647626 15.7785133,7.69554715 C15.8506613,7.95584856 15.8653581,8.27395761 15.5473724,8.60643502 C15.1281791,9.01108844 2.74276963,20.7797866 2.74276963,20.7797866 C1.71666451,21.6619377 1.78881252,23.295588 2.74276963,24.2642836 C3.71108953,25.2186107 5.32974363,25.2764183 6.22591552,24.2499152 C6.22591552,24.2499152 17.8888427,11.9028066 18.3945469,11.3969063 C18.6547474,11.1366049 18.9293107,11.0931656 19.1460887,11.1222365 Z M5.09860276,23.07906 C4.76625426,23.4115375 4.26021609,23.4115375 3.92786759,23.07906 C3.59551909,22.7465826 3.59551909,22.2403482 3.92786759,21.9078707 C4.26021609,21.5753933 4.76625426,21.5753933 5.09860276,21.9078707 C5.40188539,22.2393196 5.40188539,22.7476112 5.09860276,23.07906 L5.09860276,23.07906 Z" id="形状"></path>
</g>
<path d="M3,5 L49,5 C50.1045695,5 51,5.8954305 51,7 L51,20 C51,21.1045695 50.1045695,22 49,22 L0,22 L0,22 L0,8.69218242 L3,5 Z" id="矩形" fill="#5073E5"></path>
<polygon id="矩形备份-32" fill="#3E5DC0" points="0 8.98530819 3 5 3 22 0 24.9853082"></polygon>
<polygon id="矩形备份-33" fill="#243D8C" transform="translate(1.500000, 24.096418) scale(-1, 1) translate(-1.500000, -24.096418) " points="0 26.9957245 3 24.0301261 0 21.1971118"></polygon>
<text id="开发中" font-family="PingFangSC-Semibold, PingFang SC" font-size="12" font-weight="500" fill="#FFFFFF">
<tspan x="10.7588235" y="18">开发中</tspan>
</text>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -0,0 +1,7 @@
---
title: 介绍 | TinyReact
---
# 介绍
TinyReact 简介 md文档

View File

@ -0,0 +1,43 @@
// 注意删除了useFor属性
// title,label增加英文版以应对将来的国际化功能
export const standaloneMenus = [
{
label: '组件总览',
key: 'overview',
},
];
export const docMenus = [
{
label: '使用指南',
labelEn: 'Guide', //***********
key: 'doc_use',
children: [
{
title: '背景简介',
titleEn: 'Introduce',
key: 'introduce',
},
],
},
];
//-------------------------------------------------------------------
export const cmpMenus = [
{
label: '表单选择',
labelEn: 'Form Selection',
key: 'cmp_formselect',
children: [
{ name: 'Button', nameCn: '按钮', key: 'button' }
]
},
{
'label': '提示组件',
'labelEn': 'Tips Components',
'key': 'cmp_tips_components',
'children': [
{ 'nameCn': '警告', 'name': 'Alert', 'key': 'alert' }
]
}
];

2
examples/react-site/env/.env vendored Normal file
View File

@ -0,0 +1,2 @@
# 1、声明一个变量
VITE_CONTEXT=/tiny-react/

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenTiny - TinyVue</title>
<!--问题1.TinyNG打包后静态资源文件在新官网找不到CSS主题样式文件加载不到-->
<!--2.TinyNG打包文件web-components的主题样式加载时机较早编译获取不到PUBLIC_URL和DEPLOY_URL变量从而找不到对应的css文件-->
<!--方案将PUBLIC_URL和DEPLOY_URL变量在header中提前定义保证web-components可以获取到这两个变量从而正确加载对应的主题样式文件-->
<script type="module">
window.PUBLIC_URL = import.meta.env.BASE_URL;
window.DEPLOY_URL = '';
</script>
</head>
<body class="of-hidden">
<div id="header"></div>
<app-root></app-root>
<div id="app" class="wp100 hp100 pt60"></div>
<script id="tinyui-design-common" src="https://res.hc-cdn.com/tinyui-design-common/1.0.5.20230106163838/tinyui-design-common.min.js"></script>
<script type="module" src="./src/main.js"></script>
</body>
</html>

View File

@ -0,0 +1,41 @@
import md_prism from 'markdown-it-prism'; // 高亮
import md_emoji from 'markdown-it-emoji'; // 表情
import md_sub from 'markdown-it-sub'; // 下标 ~ ~
import md_sup from 'markdown-it-sup'; // 上标 ^ ^
import md_mark from 'markdown-it-mark'; // 高亮文字 == ==
import md_container from 'markdown-it-container'; // 提示块
import md_anchor from 'markdown-it-anchor';
export const MdExt = [md_emoji, md_sub, md_sup, md_mark];
// 自定义container
function createContainer(klass) {
return [
md_container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim() || '';
if (token.nesting === 1) {
return `<div class="${klass} custom-block"><p class="custom-block-title">${info}</p>\n`;
} else {
return `</div>\n`;
}
},
},
];
}
export function mdInstall(md) {
md.use(md_prism, { plugins: ['line-highlight'] })
.use(...createContainer('tip'))
.use(...createContainer('info'))
.use(...createContainer('warning'))
.use(...createContainer('danger'))
.use(md_anchor, {
permalink: true,
permalinkBefore: true,
permalinkSymbol: '',
slugify: s => encodeURIComponent(s),
});
}

View File

@ -0,0 +1,67 @@
{
"name": "@opentiny/react-site",
"private": true,
"version": "0.1.0",
"scripts": {
"start": "node ./scripts/copy.js && node ./scripts/build-react.mjs && vite",
"build:react": "node ./scripts/build-react.mjs",
"build": "node ./scripts/copy.js && node ./scripts/build-react.mjs && vite build",
"prettier": "npx prettier --write ./**/*.{ts,tsx,css,less,scss}",
"stylelint": "npx stylelint ./src/**/*.scss ./src/**/*.less ./src/**/*.css --fix"
},
"dependencies": {
"@babel/preset-env": "^7.22.20",
"@opentiny/vue": "^3.10.1",
"@pe-3/react": "^1.0.15",
"@rollup/plugin-babel": "^6.0.3",
"@unocss/reset": "0.38.2",
"@vitejs/plugin-react": "^4.0.4",
"@vueuse/head": "0.7.13",
"dompurify": "^3.0.1",
"github-markdown-css": "^5.1.0",
"highlight.js": "^11.5.1",
"marked": "^4.3.0",
"prismjs": "^1.28.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite4": "npm:vite@4",
"vue": "^3.2.37",
"vue-i18n": "^9.1.10",
"vue-router": "4.1.5"
},
"devDependencies": {
"@types/markdown-it": "^12.2.3",
"@types/node": "^17.0.45",
"@unocss/preset-icons": "^0.61.9",
"@vitejs/plugin-vue": "^2.3.3",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/compiler-sfc": "^3.2.37",
"chalk": "4.1.2",
"cross-spawn": "^7.0.3",
"fast-glob": "^3.2.12",
"fs-extra": "^10.1.0",
"less": "^4.1.3",
"markdown-it": "^13.0.1",
"markdown-it-anchor": "^8.6.4",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.2",
"markdown-it-mark": "^3.0.1",
"markdown-it-prism": "^2.2.4",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-table-of-contents": "^0.6.0",
"markdown-it-toc-done-right": "^4.2.0",
"naive-ui": "~2.30.6",
"prettier": "^2.7.1",
"stylelint": "^14.9.1",
"stylelint-config-standard": "^26.0.0",
"unocss": "^0.61.9",
"unplugin-auto-import": "0.8.7",
"unplugin-vue-components": "^0.19.9",
"uslug": "^1.0.4",
"vite": "^4.3.8",
"vite-plugin-html": "^2.0.0",
"vite-plugin-inspect": "^0.5.0",
"vite-plugin-md": "0.13.1"
}
}

View File

@ -0,0 +1,15 @@
<template>
<div>
<alert-base-demo></alert-base-demo>
</div>
</template>
<script>
import AlertBase from '@/webcomps/alert/base.js'
customElements.define(
'alert-base-demo',
AlertBase
)
export default {
}
</script>

View File

@ -0,0 +1,9 @@
<template>
<alert-center-demo></alert-center-demo>
</template>
<script lang="jsx">
import AlertCenter from "@/webcomps/alert/center.js";
customElements.define("alert-center-demo", AlertCenter);
export default {};
</script>

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-size-demo></alert-size-demo>
</div>
</template>
<script>
import AlertSize from "@/webcomps/alert/size.js";
customElements.define("alert-size-demo", AlertSize);
export default {};
</script>

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-title-demo></alert-title-demo>
</div>
</template>
<script lang="jsx">
import AlertTitle from "@/webcomps/alert/title.js";
customElements.define("alert-title-demo", AlertTitle);
export default {};
</script>

View File

@ -0,0 +1,11 @@
<template>
<div>
<alert-type-demo></alert-type-demo>
</div>
</template>
<script lang="jsx">
import AlertType from "@/webcomps/alert/type.js";
customElements.define("alert-type-demo", AlertType);
export default {};
</script>

View File

@ -0,0 +1,7 @@
---
title: Alert 警告
---
# Alert 警告
<div>Alert 警告,提供 warning、error、info、success 四种类型显示不同类别的信息。</div>

View File

@ -0,0 +1,7 @@
---
title: Alert
---
# Alert
<div>Alert alarms, including warning, error, info, and success.</div>

View File

@ -0,0 +1,228 @@
{
"column": "2",
"owner": "",
"demos": [
{
"demoId": "base",
"name": {
"zh-CN": "基本用法",
"en-US": "Basic Usage"
},
"desc": {
"zh-CN": "详细用法参考如下示例",
"en-US": "For details, see the following example."
},
"codeFiles": [
"base.vue"
]
},
{
"demoId": "type",
"name": {
"zh-CN": "类型",
"en-US": "Type"
},
"desc": {
"zh-CN": "<p>通过 <code>type</code> 设置不同的类型。可选值success、warning、info、error默认值success 。</p>\n",
"en-US": "<p>Set different types through <code>type</code>. The options are success, warning, info, and error. The default value is success. </p>\n"
},
"codeFiles": [
"type.vue"
]
},
{
"demoId": "size",
"name": {
"zh-CN": "大尺寸",
"en-US": "Large Size"
},
"desc": {
"zh-CN": "<p>通过 <code>size</code> 属性设置不同的尺寸可选值nomal、large默认值nomal 。</p>\n",
"en-US": "<p>Set different sizes through the <code>size</code> attribute. The options are nomal and large. The default value is nomal. </p>\n"
},
"codeFiles": [
"size.vue"
]
},
{
"demoId": "title",
"name": {
"zh-CN": "自定义标题",
"en-US": "Custom Title"
},
"desc": {
"zh-CN": "<p>当 <code>size</code> 为 large 时显示标题,可设置 <code>title</code> 或 <code>slot</code> 自定义标题。默认标题根据设置的 <code>type</code> 显示。</p>\n",
"en-US": "<p>When <code>size</code> is set to large, the title is displayed. You can set <code>title</code> or <code>slot</code> to customize the title. The default title is displayed according to the set <code>type</code>. </p>\n"
},
"codeFiles": [
"title.vue"
]
},
{
"demoId": "center",
"name": {
"zh-CN": "文字居中",
"en-US": "Center text"
},
"desc": {
"zh-CN": "<p>通过 <code>center</code> 属性可使文字显示居中。</p>\n",
"en-US": "<p>You can use the <code>center</code> property to center the text. </p>\n"
},
"codeFiles": [
"center.vue"
]
}
],
"apis": [
{
"name": "alert",
"type": "component",
"properties": [
{
"name": "closable",
"type": "Boolean",
"defaultValue": "该属性的默认值为 true",
"desc": {
"zh-CN": "设置警告是否可以关闭",
"en-US": "Set whether alarms can be disabled."
},
"demoId": "closable"
},
{
"name": "icon",
"type": "String , Object",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的图标,默认会根据 type 值自动使用对应图标",
"en-US": "Set the alarm icon. By default, the corresponding icon is automatically used based on the value of type."
},
"demoId": "icon"
},
{
"name": "size",
"type": "String",
"defaultValue": "该属性的默认值为 normal",
"desc": {
"zh-CN": "设置警告的大小 nomal/large 缺省为 nomal。;该属性的可选值为 nomal / large",
"en-US": "Set the warning size to nomal or large. The default value is nomal. ;The value of this attribute can be nomal or large"
},
"demoId": "size"
},
{
"name": "title",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的标题,在 size 为 large 时有效,默认根据 type 自动设置",
"en-US": "Set the warning title. This parameter is valid only when size is set to large. By default, the alarm title is automatically set based on type."
},
"demoId": "title"
},
{
"name": "type",
"type": "String",
"defaultValue": "该属性的默认值为 success",
"desc": {
"zh-CN": "设置警告的类型;该属性的可选值为 success/warning/info/error",
"en-US": "Set the alarm type. The value of this attribute can be success / warning / info / error"
},
"demoId": "type"
},
{
"name": "description",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "设置警告的提示内容,默认为空;",
"en-US": "Set the warning prompt content. The default value is null."
},
"demoId": "custom-description"
},
{
"name": "center",
"type": "Boolean",
"defaultValue": "该属性的默认值为 false",
"desc": {
"zh-CN": "文字是否居中",
"en-US": "Whether the text is centered"
},
"demoId": "center"
},
{
"name": "close-text",
"type": "String",
"defaultValue": "",
"desc": {
"zh-CN": "关闭按钮自定义文本",
"en-US": "Customized text of the close button"
},
"demoId": "close-text"
},
{
"name": "show-icon",
"type": "Boolean",
"defaultValue": "该属性的默认值为 true",
"desc": {
"zh-CN": "是否显示图标",
"en-US": "Display icon"
},
"demoId": "show-icon"
}
],
"events": [
{
"name": "close",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "关闭 alert 时触发的事件",
"en-US": "Event triggered when the alert function is disabled"
},
"demoId": "close-events"
}
],
"slots": [
{
"name": "default",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "组件默认插槽",
"en-US": "Default slot of the component"
},
"demoId": "slot-default"
},
{
"name": "title",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "标题的内容",
"en-US": "Title content"
},
"demoId": "title"
},
{
"name": "description",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "提示内容",
"en-US": "Prompt Content"
},
"demoId": "custom-description"
},
{
"name": "close",
"type": "",
"defaultValue": "",
"desc": {
"zh-CN": "自定义关闭按钮,当 closable 属性为 false 时有效",
"en-US": ""
},
"demoId": "custom-close"
}
]
}
]
}

View File

@ -0,0 +1,9 @@
<template>
<button-click-demo></button-click-demo>
</template>
<script>
import ButtonClick from "@/webcomps/button/button-click-webcomp.js";
customElements.define("button-click-demo", ButtonClick);
export default {};
</script>

View File

@ -0,0 +1,8 @@
<template>
<button-round-demo></button-round-demo>
</template>
<script>
import ButtonRound from "@/webcomps/button/button-round-webcomp.js";
customElements.define("button-round-demo", ButtonRound);
export default {};
</script>

View File

@ -0,0 +1,8 @@
<template>
<button-type-demo></button-type-demo>
</template>
<script>
import ButtonType from "@/webcomps/button/button-type-webcomp.js";
customElements.define("button-type-demo", ButtonType);
export default {};
</script>

Some files were not shown because too many files have changed in this diff Show More