forked from opentiny/tiny-vue
build(theme): [theme] Theme package structure optimization (#949)
* build(theme): [theme] Theme package structure optimization * build(theme): [theme] Fix according to review comments
This commit is contained in:
parent
61eaf29bc4
commit
0580c292a8
|
@ -10,11 +10,42 @@ Design website: [Administrative side specification design variable] (https://rnd
|
|||
|
||||
Basic style variable `npm` Repository path: `@opentiny/vue-theme/theme`
|
||||
|
||||
### Using Predefined Topics and Dynamically Switching Topics
|
||||
### Using predefined themes and dynamically switching themes
|
||||
|
||||
At present, two sets of themes are officially provided: default theme and unlimited theme.
|
||||
Currently, the official offers 4 sets of themes:
|
||||
|
||||
Topic initialization and dynamic theme switching are described as follows:
|
||||
-Default Theme
|
||||
-Infinity Theme ` tinyInfinityTheme`
|
||||
-Aurora Theme ` tinyAuroraTheme`
|
||||
-XDesign Theme ` tinySmbTheme`
|
||||
|
||||
#### Using predefined themes through alias [Currently only supported: Eurora theme and XDesign theme]
|
||||
|
||||
vue.config.js define
|
||||
|
||||
```js
|
||||
chainWebpack: (config) => {
|
||||
// XDesign Theme
|
||||
config.resolve.alias.set('@opentiny/vue-theme', '@opentiny/vue-theme/smb-theme')
|
||||
// Aurora Theme : The aurora theme is to replace all the 'smb' characters in the above SMB themes with 'aurora'
|
||||
}
|
||||
```
|
||||
|
||||
vite.config.js define
|
||||
|
||||
```js
|
||||
resolve: {
|
||||
alias: [
|
||||
// XDesign Theme
|
||||
{
|
||||
find: /\@opentiny\/vue-theme\/(?!(smb))/,
|
||||
replacement: '@opentiny/vue-theme/smb-theme/'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### The specific usage of theme initialization and dynamic theme switching is shown below, and the following code is added to the main.ts file.
|
||||
|
||||
```js
|
||||
import TinyThemeTool from' @opentiny/vue-theme/theme-tool.js'
|
||||
|
|
|
@ -17,7 +17,33 @@
|
|||
- 欧若拉主题 `tinyAuroraTheme`
|
||||
- XDesign 主题 `tinySmbTheme`
|
||||
|
||||
主题初始化和动态切换主题的具体使用方式如下文所示,在 main.ts 文件中增加以下代码。
|
||||
#### 通过 alias 使用预定义主题【目前仅支持:欧若拉主题 和 XDesign 主题】
|
||||
|
||||
vue.config.js 定义
|
||||
|
||||
```js
|
||||
chainWebpack: (config) => {
|
||||
// XDesign 主题
|
||||
config.resolve.alias.set('@opentiny/vue-theme', '@opentiny/vue-theme/smb-theme')
|
||||
// aurora 主题 则是将以上smb主题中的'smb'字符全替换成 'aurora'即可
|
||||
}
|
||||
```
|
||||
|
||||
vite.config.js 定义
|
||||
|
||||
```js
|
||||
resolve: {
|
||||
alias: [
|
||||
// XDesign 主题
|
||||
{
|
||||
find: /\@opentiny\/vue-theme\/(?!(smb))/,
|
||||
replacement: '@opentiny/vue-theme/smb-theme/'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 主题初始化和动态切换主题的具体使用方式如下文所示,在 main.ts 文件中增加以下代码。
|
||||
|
||||
```js
|
||||
import TinyThemeTool from '@opentiny/vue-theme/theme-tool'
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
const fs = require('fs')
|
||||
const fsExtra = require('fs-extra')
|
||||
const indexLessPath = 'index.less'
|
||||
const indexJsPath = 'index.js'
|
||||
const smbThemeName = 'smb-theme'
|
||||
const auroraThemeName = 'aurora-theme'
|
||||
const originRootPath = '../src/'
|
||||
const originThemeRootPath = `${originRootPath}theme/`
|
||||
const basePath = '/base/'
|
||||
|
||||
const emptyThemeContent = `@import '../../{{}}/index.less';`
|
||||
|
||||
const baseContent = `@import '../../base/index.less';
|
||||
html:root`
|
||||
|
||||
const scopedTitle = `@import '../../custom.less';
|
||||
@import '../../{{}}/index.less';
|
||||
`
|
||||
|
||||
const scopedContent = `
|
||||
@{compName}-prefix-cls: ~'@{css-prefix}{compName}';
|
||||
|
||||
.@{{compName}-prefix-cls}[class*=tiny] {
|
||||
{var}
|
||||
}`
|
||||
|
||||
const buildThemePathMap = {
|
||||
[auroraThemeName]: `${originRootPath}${auroraThemeName}${basePath}`,
|
||||
[smbThemeName]: `${originRootPath}${smbThemeName}${basePath}`
|
||||
}
|
||||
|
||||
const cssScopedMap = {
|
||||
'anchor': 'anchor__wrapper',
|
||||
'badge': 'badge__wrapper',
|
||||
'crop': 'crop__wrapper',
|
||||
'date-panel': 'picker-panel',
|
||||
'date-range': 'date-range-picker',
|
||||
'detail-page': 'grid-modal__box',
|
||||
'dialog-box': 'dialog-box__wrapper',
|
||||
'error-page': 'errortips__box',
|
||||
'floatbar': 'float-bar',
|
||||
'flowchart': 'flow-chart',
|
||||
'grid': 'grid__wrapper',
|
||||
'input': ['input', 'input-group'],
|
||||
'option': 'select-dropdown',
|
||||
'pager': ['pager', 'pager__selector'],
|
||||
'picker': 'date-editor',
|
||||
'pop-upload': ['popupload__modal', 'popupload'],
|
||||
'popconfirm': ['popconfirm', 'popconfirm-popover'],
|
||||
'popeditor': ['dialog-box', 'popeditor'],
|
||||
'scroll-text': 'scroll-text__wrapper',
|
||||
'slider': 'slider-container',
|
||||
'tabs': ['tabs__more-dropdown', 'tabs'],
|
||||
'time-range': 'time-range-picker',
|
||||
'tip': 'tips',
|
||||
'tree': ['tree', 'tree__del-popover'],
|
||||
'upload': 'file-upload',
|
||||
'upload-dragger': 'file-upload',
|
||||
'upload-list': 'file-upload',
|
||||
'user-account': 'user-contact'
|
||||
}
|
||||
|
||||
const createTheme = (callbackFn) => {
|
||||
const createDir = (path, fn = null) => {
|
||||
fs.mkdir(path, (err) => {
|
||||
if (err) {
|
||||
console.log(path, err)
|
||||
}
|
||||
fn && fn()
|
||||
})
|
||||
}
|
||||
|
||||
let timer = null
|
||||
const readerDirStart = () => {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
timer = setTimeout(() => {
|
||||
readDir(originRootPath, 'less')
|
||||
readDir(originThemeRootPath, 'js')
|
||||
}, 10)
|
||||
}
|
||||
|
||||
const beginCreateDir = () => {
|
||||
for (let k in buildThemePathMap) {
|
||||
createDir(originRootPath + k, readerDirStart)
|
||||
}
|
||||
}
|
||||
|
||||
const readDir = (originPath, type) => {
|
||||
fs.readdir(originPath, (err, data) => {
|
||||
if (err) {
|
||||
console.log('readDir', err)
|
||||
return
|
||||
}
|
||||
|
||||
data.forEach((fileDir) => {
|
||||
mkStat(originPath, fileDir, type)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let isFinalTimer = null
|
||||
|
||||
const isFinalFn = () => {
|
||||
clearTimeout(isFinalTimer)
|
||||
isFinalTimer = null
|
||||
isFinalTimer = setTimeout(() => {
|
||||
callbackFn()
|
||||
}, 20)
|
||||
}
|
||||
|
||||
const mkStat = (originPath, fileDir, type) => {
|
||||
const statPath = `${originPath}/${fileDir}`
|
||||
fs.stat(statPath, (err, data) => {
|
||||
if (err) {
|
||||
console.log('mkStat', err)
|
||||
return
|
||||
}
|
||||
if (data.isDirectory()) {
|
||||
if (fileDir !== 'base' && fileDir !== 'theme') {
|
||||
if (fileDir === 'images') {
|
||||
fsExtra.copy(statPath, `${originPath}/smb-theme/${fileDir}`, (subErr) => {
|
||||
if (subErr) {
|
||||
console.log(subErr)
|
||||
return
|
||||
}
|
||||
})
|
||||
fsExtra.copy(statPath, `${originPath}/aurora-theme/${fileDir}`, (subErr) => {
|
||||
if (subErr) {
|
||||
console.log(subErr)
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
isFileExist(originPath, fileDir, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const isFileExist = (originPath, fileDir, type) => {
|
||||
const parentPath = `${originPath}${fileDir}`
|
||||
const path = `${parentPath}/index.${type}`
|
||||
fs.exists(path, (exist) => {
|
||||
if (exist) {
|
||||
if (type === 'less') {
|
||||
readComponentsFile(fileDir)
|
||||
} else if (type === 'js') {
|
||||
readThemeFile(fileDir)
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const writeThemeIndexLess = (path, fileDir, themeName) => {
|
||||
fs.stat(path, (err, data) => {
|
||||
const parentPath = `${originRootPath}${themeName}/${fileDir}`
|
||||
const writeTheme = () => {
|
||||
if (err) {
|
||||
writeFile(parentPath + '/index.less', emptyThemeContent.replace('{{}}', fileDir))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!data.isDirectory()) {
|
||||
fs.readFile(path, 'utf8', (subErr, dataStr) => {
|
||||
if (subErr) {
|
||||
console.log(subErr)
|
||||
return
|
||||
}
|
||||
const startIndex = dataStr.indexOf('{') + 4
|
||||
const endIndex = dataStr.indexOf('}')
|
||||
const newDataStr =
|
||||
dataStr
|
||||
.slice(startIndex, endIndex)
|
||||
.replace(/\'ti-/g, '--ti-')
|
||||
.replace(/\'/g, '')
|
||||
.replace(/\,\n/g, ';\n')
|
||||
.replace(/\, \/\//g, '; //')
|
||||
.slice(0, -1) + ';'
|
||||
|
||||
let scropedData = scopedTitle.replace('{{}}', fileDir)
|
||||
|
||||
if (cssScopedMap[fileDir]) {
|
||||
if (Array.isArray(cssScopedMap[fileDir])) {
|
||||
cssScopedMap[fileDir].forEach((item) => {
|
||||
scropedData += scopedContent.replace(/\{compName\}/g, item).replace(/\{var\}/g, newDataStr)
|
||||
})
|
||||
} else {
|
||||
scropedData += scopedContent
|
||||
.replace(/\{compName\}/g, cssScopedMap[fileDir])
|
||||
.replace(/\{var\}/g, newDataStr)
|
||||
}
|
||||
} else {
|
||||
scropedData += scopedContent.replace(/\{compName\}/g, fileDir).replace(/\{var\}/g, newDataStr)
|
||||
}
|
||||
|
||||
writeFile(parentPath + '/index.less', scropedData)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
createDir(parentPath, writeTheme)
|
||||
})
|
||||
}
|
||||
|
||||
const readComponentsFile = (fileDir) => {
|
||||
const indexPath = `${originRootPath}/${fileDir}/${indexLessPath}`
|
||||
const smbPath = `${originRootPath}/${fileDir}/${smbThemeName}.js`
|
||||
const auroraPath = `${originRootPath}/${fileDir}/${auroraThemeName}.js`
|
||||
fs.readFile(indexPath, 'utf8', (err, dataStr) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
// 写入smb-theme/**/index.less
|
||||
writeThemeIndexLess(smbPath, fileDir, smbThemeName)
|
||||
|
||||
// 写入aurora-theme/**/index.less
|
||||
writeThemeIndexLess(auroraPath, fileDir, auroraThemeName)
|
||||
})
|
||||
}
|
||||
|
||||
const readThemeFile = (fileDir) => {
|
||||
const indexPath = `${originThemeRootPath}/${fileDir}/${indexJsPath}`
|
||||
|
||||
if (!buildThemePathMap[fileDir]) {
|
||||
return
|
||||
}
|
||||
|
||||
fs.readFile(indexPath, 'utf8', (err, dataStr) => {
|
||||
createDir(buildThemePathMap[fileDir])
|
||||
|
||||
if (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
const startIndex = dataStr.indexOf('{') - 1
|
||||
const endIndex = dataStr.indexOf('}')
|
||||
let newDataStr = dataStr.slice(startIndex, endIndex)
|
||||
const lastIndex = newDataStr.lastIndexOf("'")
|
||||
newDataStr =
|
||||
baseContent +
|
||||
newDataStr
|
||||
.slice(0, lastIndex)
|
||||
.replace(/\'ti-/g, '--ti-')
|
||||
.replace(/\'/g, '')
|
||||
.replace(/\,\n/g, ';\n')
|
||||
.replace(/\, \/\//g, '; //') +
|
||||
';\n}'
|
||||
|
||||
writeFile(buildThemePathMap[fileDir] + '/index.less', newDataStr)
|
||||
})
|
||||
}
|
||||
|
||||
const writeFile = (filePath, data) => {
|
||||
fs.writeFile(filePath, data, 'utf8', (err) => {
|
||||
if (err) {
|
||||
console.log('writeFile', err)
|
||||
}
|
||||
isFinalFn()
|
||||
})
|
||||
}
|
||||
|
||||
beginCreateDir()
|
||||
}
|
||||
|
||||
const removeDir = (callbackFn) => {
|
||||
for (let k in buildThemePathMap) {
|
||||
fsExtra.remove(`${originRootPath}${k}`, (err) => {
|
||||
if (err) {
|
||||
console.log('removeDir', err)
|
||||
}
|
||||
callbackFn()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { createTheme, removeDir }
|
|
@ -9,9 +9,12 @@ const svgInline = require('gulp-svg-inline')
|
|||
const prefixer = require('gulp-autoprefixer')
|
||||
const fg = require('fast-glob')
|
||||
const fs = require('node:fs')
|
||||
const { createTheme, removeDir } = require('./edit‐dir‐theme.js')
|
||||
|
||||
const source = '../src'
|
||||
const dist = '../dist'
|
||||
const distSmb = '../dist/smb-theme'
|
||||
const distAurora = '../dist/aurora-theme'
|
||||
const svgInlineOption = {
|
||||
maxImageSize: 1 * 1024 * 1024,
|
||||
extensions: [/\.svg/gi]
|
||||
|
@ -26,9 +29,16 @@ const importStr = fileList
|
|||
const note = fs.readFileSync('../src/index.less', { encoding: 'utf-8' }).match(/(^\/\*\*.+?\*\/)/s)[0]
|
||||
fs.writeFileSync('../src/index.less', `${note}\n\n${importStr}`)
|
||||
|
||||
gulp.task('build-dir', createTheme)
|
||||
|
||||
gulp.task('compile', () => {
|
||||
return gulp
|
||||
.src([`${source}/**/index.less`, `${source}/index.less`])
|
||||
.src([
|
||||
`${source}/**/index.less`,
|
||||
`${source}/aurora-theme/**/index.less`,
|
||||
`${source}/smb-theme/**/index.less`,
|
||||
`${source}/index.less`
|
||||
])
|
||||
.pipe(svgInline(svgInlineOption))
|
||||
.pipe(less())
|
||||
.pipe(
|
||||
|
@ -57,4 +67,26 @@ gulp.task('copyimage', () => {
|
|||
return gulp.src([`${source}/images/**`]).pipe(gulp.dest(`${dist}/images`))
|
||||
})
|
||||
|
||||
gulp.task('build', gulp.series('compile', 'copycssvar', 'copysvgs', 'copyimage'))
|
||||
gulp.task('copyimage-aurora', () => {
|
||||
return gulp.src([`${source}/aurora-theme/images/**`]).pipe(gulp.dest(`${distAurora}/images`))
|
||||
})
|
||||
|
||||
gulp.task('copyimage-smb', () => {
|
||||
return gulp.src([`${source}/smb-theme/images/**`]).pipe(gulp.dest(`${distSmb}/images`))
|
||||
})
|
||||
|
||||
gulp.task('remove-dir', removeDir)
|
||||
|
||||
gulp.task(
|
||||
'build',
|
||||
gulp.series(
|
||||
'build-dir',
|
||||
'compile',
|
||||
'copycssvar',
|
||||
'copysvgs',
|
||||
'copyimage',
|
||||
'copyimage-aurora',
|
||||
'copyimage-smb',
|
||||
'remove-dir'
|
||||
)
|
||||
)
|
||||
|
|
|
@ -307,7 +307,7 @@ export const infinityTheme = {
|
|||
'ti-notify-close-icon-color': 'var(--ti-base-color-common-1)',
|
||||
'ti-notify-title-text-color': 'var(--ti-base-color-common-1)',
|
||||
'ti-notify-title-margin-top': '0',
|
||||
'ti-notify-title-margin-horizontal': '',
|
||||
'ti-notify-title-margin-horizontal': '0',
|
||||
'ti-notify-title-margin-bottom': '8px',
|
||||
'ti-notify-title-height': '25px',
|
||||
'ti-notify-title-line-height': '25px',
|
||||
|
|
Loading…
Reference in New Issue