├── index.js ├── bin └── cutheme.js ├── lib ├── postcss-copy.js ├── postcss-filter-rules.js ├── postcss-code-snippets.js ├── postcss-colorui-theme.js ├── postcss-colorui-lite.js ├── postcss-colorui-new-color.js ├── colorui-modules.js ├── cutheme.js └── tools.js ├── package.json ├── .vscode └── launch.json ├── LICENSE ├── test ├── config.json ├── test.js └── main.css ├── .gitignore └── README.md /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = require('./lib/cutheme') 4 | 5 | -------------------------------------------------------------------------------- /bin/cutheme.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const package = require('../package.json') 3 | const { program } = require('commander'); 4 | const cutheme = require('../lib/cutheme') 5 | const path = require('path') 6 | 7 | program 8 | .version(package.version) 9 | .requiredOption('-c, --config ', 'set config path') 10 | .parse(process.argv) 11 | 12 | 13 | 14 | let cfgPath = path.isAbsolute(program.config) ? program.config : path.join(process.cwd(), program.config) 15 | const cfg = require(cfgPath) 16 | 17 | cutheme.doAll(cfg).then((dest) => { 18 | console.log('导出完成!! 导出目录:', dest) 19 | }) -------------------------------------------------------------------------------- /lib/postcss-copy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss'); 3 | 4 | 5 | module.exports = postcss.plugin('postcss-copy', opts => { 6 | let copy = opts.copy 7 | let prefix = opts.prefix || '' 8 | if (!Array.isArray(copy)) throw new Error('参数 copy 类型错误') 9 | if (!Array.isArray(copy[0])) copy = [copy] 10 | 11 | copy = copy.map(([search, newSubStr, flags]) => [new RegExp(search, flags), newSubStr]) 12 | 13 | return (root, result) => { 14 | root.each(node => { 15 | if (node.type != 'rule') return void node.remove() 16 | let rule = node 17 | let selectors = [] 18 | rule.selectors.forEach(s => { 19 | for (const [search, newSubStr] of copy) { 20 | if (search.test(s)) selectors.push(prefix + s.replace(search, newSubStr)) 21 | } 22 | }) 23 | 24 | if (selectors.length == 0) rule.remove() 25 | else rule.selector = selectors.join(',\n') 26 | }) 27 | } 28 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "colorui-theme", 3 | "version": "1.0.14", 4 | "description": "这个从 ColorUi 生成不同颜色主题的工具", 5 | "main": "index.js", 6 | "bin": { 7 | "cutheme": "bin/cutheme.js" 8 | }, 9 | "scripts": { 10 | "test": "nyc --reporter=html --reporter=text mocha --timeout=10000 --slow=5000 test/test.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/zero0-1one/colorui-theme.git" 15 | }, 16 | "keywords": [ 17 | "colorui", 18 | "theme" 19 | ], 20 | "author": "zero0-1one", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/zero0-1one/colorui-theme/issues" 24 | }, 25 | "homepage": "https://github.com/zero0-1one/colorui-theme#readme", 26 | "dependencies": { 27 | "commander": "^5.0.0", 28 | "postcss": "^7.0.27", 29 | "uncss": "^0.17.3" 30 | }, 31 | "devDependencies": { 32 | "chai": "^4.2.0", 33 | "mocha": "^5.2.0", 34 | "nyc": "^15.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Mocha Tests", 11 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 12 | "outputCapture": "std", 13 | "args": [ 14 | "-u", 15 | "tdd", 16 | "--timeout", 17 | "999999", 18 | "--colors", 19 | "${workspaceFolder}/test" 20 | ], 21 | "internalConsoleOptions": "openOnSessionStart", 22 | "skipFiles": [ 23 | "/**" 24 | ] 25 | }, 26 | { 27 | "type": "node", 28 | "request": "launch", 29 | "name": "启动程序", 30 | "args": [ 31 | "-c", 32 | "./test/config" 33 | ], 34 | "skipFiles": [ 35 | "/**" 36 | ], 37 | "program": "${workspaceFolder}\\bin\\cutheme.js" 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /lib/postcss-filter-rules.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss'); 3 | 4 | 5 | 6 | module.exports = postcss.plugin('postcss-filter-rules', opts => { 7 | let filters = opts.filter 8 | let isRemove = !!opts.isRemove 9 | if (!Array.isArray(filters)) filters = [filters] 10 | 11 | filters = filters.map(filter => { 12 | if (filter instanceof RegExp) return filter 13 | if (typeof filter == 'string') { 14 | return new RegExp(filter) 15 | } else { 16 | throw new Error('filter 类型错误, 只支持 regExp格式, 或 regExp的字符串表达') 17 | } 18 | }) 19 | 20 | return (root, result) => { 21 | root.walkRules(rule => { 22 | let selectors = [] 23 | rule.selectors.forEach(s => { 24 | for (const f of filters) { 25 | if (f.test(s)) { 26 | if (!isRemove) selectors.push(s) 27 | return 28 | } 29 | } 30 | //都不满足 31 | if (isRemove) selectors.push(s) 32 | }) 33 | if (selectors.length == 0) rule.remove() 34 | else rule.selector = selectors.join(',\n') 35 | }) 36 | } 37 | }) 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GuangYuan Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/postcss-code-snippets.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss'); 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | module.exports = postcss.plugin('postcss-code-snippets', opts => { 7 | let prefix = opts.prefix || '' 8 | return (root, result) => { 9 | let snippets = {} 10 | root.walkRules(rule => { 11 | let keywords = rule.selector.match(/\.[a-z]+([_\-][a-z]+)*/g) 12 | if (!keywords) return 13 | for (let word of keywords) { 14 | word = word.slice(1) 15 | if (snippets[word]) continue 16 | let key = word.startsWith(prefix) ? word : prefix + word 17 | snippets[word] = { 18 | body: [word], 19 | prefix: key, 20 | scope: "css,vue-html,javascript", 21 | } 22 | } 23 | }) 24 | result.codeSnippets = snippets 25 | if (opts.fileName !== false) { 26 | let dir = opts.dir || './' 27 | let fileName = opts.fileName || `./${prefix}css.code-snippets` 28 | if (!fileName.endsWith('.code-snippets')) fileName += '.code-snippets' 29 | fs.writeFileSync(path.join(dir, fileName), JSON.stringify(snippets, null, 2)) 30 | } 31 | } 32 | }) -------------------------------------------------------------------------------- /test/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": "./test", 3 | "dest": "./test/css/bin", 4 | "fileName": "main.css", 5 | "copyFiles": "", 6 | "addHoverRules": true, 7 | "newColors": [ 8 | { 9 | "name": "newblue", 10 | "main": "#0081ff", 11 | "inverse": "#ffffff", 12 | "light": "#cce6ff", 13 | "shadow": "rgba(0, 102, 204, 0.2);", 14 | "gradual": "#1cbbb4", 15 | "lightInverse": "#0081ff" 16 | } 17 | ], 18 | "themes": { 19 | "fileName": "themes.css", 20 | "jsonFileName": "colors.json", 21 | "scssFileName": "colors.scss", 22 | "themes": [ 23 | { 24 | "name": "default", 25 | "fileName": "", 26 | "namespace": "", 27 | "colorMap": { 28 | "activated": "blue", 29 | "disabled": "grey", 30 | "newColor": "newblue" 31 | } 32 | } 33 | ] 34 | }, 35 | "codeSnippets": { 36 | "prefix": "cu-" 37 | }, 38 | "lite": { 39 | "fileName": "main-lite.css", 40 | "modules": [ 41 | "color", 42 | "^color-red" 43 | ], 44 | "isRemove": true 45 | }, 46 | "uncss": { 47 | "projectDir": "", 48 | "fileFilter": [ 49 | ".html", 50 | ".vue" 51 | ], 52 | "liteName": "" 53 | } 54 | } -------------------------------------------------------------------------------- /lib/postcss-colorui-theme.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss'); 3 | const postcssCopy = require('./postcss-copy') 4 | const tools = require('./tools') 5 | const title = ` 6 | /* 7 | 该文件由 colorui-theme 导出, 工具地址:https://github.com/zero0-1one/colorui-theme 8 | */ 9 | ` 10 | 11 | module.exports = postcss.plugin('postcss-colorui-theme', opts => { 12 | let colorMap = opts.colorMap || {} 13 | let themeName = opts.name || 'default' 14 | let namespace = typeof opts.namespace == 'string' ? opts.namespace : `.theme-${themeName} ` 15 | return async (root, result) => { 16 | let copyOpts = [] 17 | let allColors = {} 18 | let colorsByName = {} 19 | for (const ele in colorMap) { 20 | let color = colorMap[ele] 21 | copyOpts.push([`-${color}([^a-zA-Z0-9]|$)`, `-${ele}$1`, 'g']) 22 | copyOpts.push([`\\.${color}([^a-zA-Z0-9]|$)`, `.${ele}$1`, 'g']) 23 | 24 | let colors = colorsByName[color] || tools.getColors(color, root) 25 | colorsByName[color] = colors 26 | for (const type in colors) { 27 | let key = type == "main" ? ele : `${ele}-${type}` 28 | allColors[key] = colors[type] 29 | } 30 | } 31 | postcssCopy({ copy: copyOpts, prefix: namespace })(root, result) 32 | root.prepend(title) 33 | result.themeColors = allColors 34 | } 35 | }) 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | /test/css 106 | -------------------------------------------------------------------------------- /lib/postcss-colorui-lite.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss') 3 | const postcssFilterRules = require('./postcss-filter-rules') 4 | const cuModules = require('./colorui-modules') 5 | 6 | function getTitle(opts) { 7 | return ` 8 | /* 9 | 该文件由 colorui-theme 导出, 工具地址:https://github.com/zero0-1one/colorui-theme 10 | ${opts.isRemove ? '已删除' : '保留'}模块:${opts.modules.join(', ')} 11 | */ 12 | ` 13 | } 14 | 15 | module.exports = postcss.plugin('postcss-colorui-lite', opts => { 16 | let { subModules, allModules } = cuModules(opts.newColors || []) 17 | let isRemove = opts.isRemove === undefined ? true : !!opts.isRemove 18 | let all = [] 19 | let subNot = [] 20 | for (let name of opts.modules) { 21 | if (name.startsWith('^')) { 22 | name = name.slice(1) 23 | let group = name.split('-')[0] 24 | if (!(subModules.hasOwnProperty(group) && subModules[group].includes(name))) { 25 | throw new Error('只有子模块能使用 ^ 符合') 26 | } 27 | subNot.push(name) 28 | } else { 29 | if (subModules.hasOwnProperty(name)) { 30 | all.push(...subModules[name]) 31 | } else { 32 | all.push(name) 33 | } 34 | } 35 | } 36 | 37 | let allSet = new Set(all) 38 | for (const sub of subNot) { 39 | allSet.delete(sub) 40 | } 41 | all = [...allSet] //去重 42 | 43 | let filter = [] 44 | let typeFilter = new Set() 45 | for (const name of all) { 46 | if (!allModules.hasOwnProperty(name)) { 47 | console.warn(`不存在模块:${name}`) 48 | continue 49 | } 50 | let m = allModules[name] 51 | if (m.type == 'rule') { 52 | if (Array.isArray(m.filter)) filter.push(...m.filter) 53 | else filter.push(m.filter) 54 | } else if (m.type == 'type') { 55 | typeFilter.add(m.filter) 56 | } 57 | } 58 | 59 | if (!isRemove) typeFilter.add('rule') 60 | 61 | return async (root, result) => { 62 | root.each(node => { 63 | if (isRemove) { 64 | if (typeFilter.has(node.type)) node.remove() 65 | } else { 66 | if (!typeFilter.has(node.type)) node.remove() 67 | } 68 | }) 69 | postcssFilterRules({ filter, isRemove })(root, result) 70 | root.prepend(getTitle(opts)) 71 | } 72 | }) 73 | -------------------------------------------------------------------------------- /lib/postcss-colorui-new-color.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss') 3 | const tools = require('./tools') 4 | 5 | function createNewColor(colors) { 6 | let name = colors.name 7 | console.log(JSON.stringify(colors)) 8 | let hoverStr = tools.createHoverRules(name, colors) 9 | 10 | let str = ` 11 | 12 | /* -- 新颜色:${name} -- */ 13 | 14 | switch.${name}[checked] .wx-switch-input, 15 | checkbox.${name}[checked] .wx-checkbox-input, 16 | radio.${name}[checked] .wx-radio-input, 17 | switch.${name}.checked .uni-switch-input, 18 | checkbox.${name}.checked .uni-checkbox-input, 19 | radio.${name}.checked .uni-radio-input { 20 | background-color: ${colors.main} !important; 21 | border-color: ${colors.main} !important; 22 | color: ${colors.inverse} !important; 23 | } 24 | 25 | 26 | .line-${name}::after, 27 | .lines-${name}::after { 28 | border-color: ${colors.main}; 29 | } 30 | 31 | 32 | 33 | .bg-${name} { 34 | color: ${colors.inverse}; 35 | background-color: ${colors.main}; 36 | } 37 | ` 38 | if (colors.light) 39 | str += ` 40 | 41 | .bg-${name}.light { 42 | color: ${colors['light-inverse']}; 43 | background-color: ${colors.light}; 44 | } 45 | ` 46 | str += ` 47 | ${hoverStr} 48 | ` 49 | if (colors.gradual) 50 | str += ` 51 | 52 | .bg-gradual-${name} { 53 | background-image: linear-gradient(45deg, ${colors.gradual[0]}, ${colors.gradual[1]}); 54 | color: ${colors.inverse}; 55 | } 56 | ` 57 | if (colors.shadow) 58 | str += ` 59 | 60 | .shadow[class*='-${name}'] { 61 | box-shadow: 6upx 6upx 8upx ${colors.shadow}; 62 | } 63 | 64 | 65 | 66 | .text-shadow[class*='-${name}'] { 67 | text-shadow: 6upx 6upx 8upx ${colors.shadow}; 68 | } 69 | ` 70 | str += ` 71 | 72 | .text-${name}, 73 | .line-${name}, 74 | .lines-${name} { 75 | color: ${colors.main}; 76 | } 77 | ` 78 | return str 79 | } 80 | 81 | const comment = ` 82 | 83 | /* ================== 84 | 新颜色 85 | ==================== */ 86 | ` 87 | module.exports = postcss.plugin('postcss-colorui-new-color', newColors => { 88 | newColors = JSON.parse(JSON.stringify(newColors)) 89 | for (const colors of newColors) { 90 | let msg = [] 91 | if (!colors.name) throw new Error('缺少颜色名') 92 | if (!colors.main) msg.push('主色(main)') 93 | if (!colors.inverse) msg.push('反色(inverse)') 94 | if (colors.light && !colors.lightInverse) colors.lightInverse = colors.main 95 | if (msg.length > 0) throw new Error(`未定义新颜色(${colors.name})的 ${msg.join(',')}`) 96 | 97 | if (colors.gradual && !Array.isArray(colors.gradual)) colors.gradual = [colors.main, colors.gradual] //只指定了一个颜色值 98 | 99 | //转换名字 100 | colors['light-inverse'] = colors.lightInverse 101 | colors['light-hover'] = colors.lightHover 102 | } 103 | return async (root, result) => { 104 | if (Object.keys(newColors).length > 0) { 105 | root.nodes.push(...postcss.parse(comment).nodes) 106 | for (const color of newColors) { 107 | root.append(createNewColor(color)) 108 | } 109 | } 110 | } 111 | }) 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # colorui-theme 2 | 3 | 这个是从`ColorUi`生成不同颜色主题的工具. 4 | `ColorUi`是款优秀的 css 框架, 在此非常感谢 weilanwl 将它开源. 5 | 关于`ColorUi`更多信息,请前往 6 | 7 | ## 功能 8 | 9 | - 将`ColorUi`中不颜色映射成多组主题. 10 | - 轻松的为`ColorUi`增加或替换颜色规则. 11 | - 按模块导出的`main-lite.css`,减少 css 文件大小 12 | 13 | ## TODO 14 | 15 | - 通过`uncss`过滤没用的`css`规则 16 | 17 | ## 使用方法 18 | 19 | ``` 20 | npm install colorui-theme -g 21 | 或 22 | npm install colorui-theme --save-dev 23 | 24 | cutheme ./config.json 25 | ``` 26 | 27 | ## 配置文件 28 | 29 | 可以为 `.js` 或 `.json` 文件 30 | 31 | ```js 32 | //config.js 33 | { 34 | // 指定 colorui 中 main.css 所在的目录 35 | src:'~/colorui', 36 | // 指定生成文件保存的目录 37 | dest:'~/projectDir/css', 38 | 39 | // src下的main.css 会导出一份到 dest中,如果指定 newColors 会在文件末尾追加新的颜色规则 40 | // 如果 fileName === false 则不会导出该文件, 其他空值默认 'main-new.css' 41 | fileName:'main-new.css', 42 | //需要从 src 目录拷贝到 dest 的文件, 默认包含: icon.css, animation.css 43 | copyFiles:['icon.css', 'animation.css'], 44 | //是否追加 hover 规则 45 | addHoverRules:true, 46 | //指定需要添加的新颜色 47 | newColors:[{ 48 | name:'newblue', //新颜色的名字 49 | main: '#0081ff', //主色 50 | inverse: '#ffffff', //反色 51 | light: '#cce6ff', //亮色 52 | shadow: 'rgba(0, 102, 204, 0.2);',//阴影色 53 | gradual: '#1cbbb4',//渐变色 也可以指定两个颜色 如: ['#0081ff', '#1cbbb4'] 54 | lightInverse:'#0081ff', //亮色的反色, 默认与 main 相同 55 | hover:'',//默认通过计算 main 加深 56 | lightHover:'',//默认通过计算 light 加深 57 | }], 58 | 59 | 60 | //多主题配置 61 | themes:{ 62 | // 合并所有 theme 文件到同一个文件 63 | // 如果 fileName === false 则不会导出该文件, 其他空值默认 'themes.css' 64 | fileName:'themes.css', 65 | //颜色值 如果 fileName === false 则不会导出该文件, 其他空值默认 'colors.json' 66 | jsonFileName: false, 67 | themes:[{ 68 | //主题名称 默认:'default' 69 | name:'default', 70 | // 如果 fileName === false 则不会导出该文件, 其他空值默认`theme-${name}.css` 71 | fileName:'cutheme-default.css', 72 | // 如果 fileName === false 则不会导出该文件, 其他空值默认 `${name}-colors.json` 73 | jsonFileName: false, 74 | //每个选择器追加的命名空间, 默认为`.theme-${name} ` 注意:通常后面有空格 75 | namespace:'.theme-default ', 76 | //指定主题中每种元素映射 colorui 中颜, 也可指定 newColors 中的颜色 77 | colorMap:{ 78 | 'activated':'blue', 79 | 'disabled':'grey', 80 | 'newColor':'newblue',//newColors 中的颜色 81 | }, 82 | }, 83 | //... 更多主题 84 | ], 85 | }, 86 | 87 | 88 | //根据指定模块来导出 css 89 | lite:{ 90 | // 如果 fileName === false 则不会导出该文件, 其他空值默认 `main-lite.css` 91 | fileName:'main-lite.css', 92 | //指定的modules 是删除 还是保留模式, 默认删除模式 93 | isRemove:true 94 | //自带模块 95 | modules:[ 96 | 'color', //删除 color 模块 97 | '^color-red', //保留 color-red. 子模块可以使用 ^ 运算符合 98 | 'chat',//删除 chat 模块 99 | ], 100 | } 101 | } 102 | ``` 103 | 104 | ## 模块 105 | 106 | 中间有 "`-`" 的为子模块 107 | 108 | ``` 109 | comment 110 | image 111 | switch 112 | switch-switch 113 | switch-checkbox 114 | switch-radio 115 | border 116 | button 117 | tag 118 | avatar 119 | progress 120 | load 121 | list 122 | bar 123 | nav 124 | chat 125 | card 126 | form 127 | modal 128 | swiper 129 | steps 130 | timeline 131 | layout 132 | layout-flex 133 | layout-grid 134 | layout-margin 135 | layout-padding 136 | layout-float 137 | text 138 | color 139 | color-red 140 | color-orange 141 | color-yellow 142 | color-olive 143 | color-green 144 | color-cyan 145 | color-blue 146 | color-purple 147 | color-mauve 148 | color-pink 149 | color-brown 150 | color-grey 151 | color-gray 152 | color-black 153 | color-white 154 | ``` 155 | -------------------------------------------------------------------------------- /lib/colorui-modules.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function nameModule(names) { 4 | if (!Array.isArray(names)) names = [names] 5 | let filter = [] 6 | for (const name of names) { 7 | filter.push(`-${name}([^a-zA-Z0-9]|$)`) 8 | filter.push(`\\.${name}([^a-zA-Z0-9]|$)`) 9 | } 10 | return { type: 'rule', filter } 11 | } 12 | 13 | function classModule(names, prefix = true) { 14 | if (!Array.isArray(names)) names = [names] 15 | return { 16 | type: 'rule', 17 | filter: names.map(name => { 18 | if (prefix) name = 'cu-' + name 19 | if (name.endsWith('-')) { 20 | return `\\.${name}[a-zA-Z]` 21 | } else { 22 | return `\\.${name}([^a-zA-Z0-9]|$)` 23 | } 24 | }), 25 | } 26 | } 27 | 28 | function tagModule(names) { 29 | if (!Array.isArray(names)) names = [names] 30 | return { type: 'rule', filter: names.map(name => `(^|[^a-zA-Z0-9])${name}([^a-zA-Z0-9]|$)`) } 31 | } 32 | 33 | module.exports = function (newColors=[]) { 34 | const rawModules = { 35 | comment: { type: 'type', filter: 'comment' }, 36 | image: tagModule('image'), 37 | switch: { 38 | switch: tagModule('switch'), 39 | checkbox: tagModule('checkbox'), 40 | radio: tagModule('radio'), 41 | }, 42 | border: classModule(['solid', 'dashed']), 43 | button: classModule('btn'), 44 | tag: classModule('tag'), 45 | avatar: classModule('avatar'), 46 | progress: classModule('progress'), 47 | load: classModule('load'), 48 | list: classModule(['list', 'item']), 49 | bar: classModule('bar'), 50 | nav: classModule('nav'), 51 | chat: classModule('chat'), 52 | card: classModule('card'), 53 | form: classModule('form-group'), 54 | modal: classModule('modal'), 55 | swiper: nameModule('swiper'), 56 | steps: classModule('steps'), 57 | timeline: classModule('timeline'), 58 | layout: { 59 | flex: classModule(['flex', 'basis-', 'align-', 'justify-', 'self-'], false), 60 | grid: classModule('grid', false), 61 | margin: classModule('margin', false), 62 | padding: classModule('padding', false), 63 | float: classModule(['cf', 'fl', 'fr'], false), 64 | }, 65 | text: classModule(['text'], false), 66 | color: { 67 | red: nameModule('red'), 68 | orange: nameModule('orange'), 69 | yellow: nameModule('yellow'), 70 | olive: nameModule('olive'), 71 | green: nameModule('green'), 72 | cyan: nameModule('cyan'), 73 | blue: nameModule('blue'), 74 | purple: nameModule('purple'), 75 | mauve: nameModule('mauve'), 76 | pink: nameModule('pink'), 77 | brown: nameModule('brown'), 78 | grey: nameModule('grey'), 79 | gray: nameModule('gray'), 80 | black: nameModule('black'), 81 | white: nameModule('white'), 82 | }, 83 | } 84 | for (const { name } of newColors) { 85 | rawModules.color[name] = nameModule(name) 86 | } 87 | 88 | let subModules = {} 89 | let allModules = {} 90 | let moduleList = [] 91 | for (const m in rawModules) { 92 | moduleList.push(m) 93 | if (rawModules[m].hasOwnProperty('type') && rawModules[m].hasOwnProperty('filter')) { 94 | allModules[m] = rawModules[m] 95 | } else { 96 | //包含子模块 97 | subModules[m] = [] 98 | for (const sub in rawModules[m]) { 99 | let subName = m + '-' + sub 100 | moduleList.push(subName) 101 | subModules[m].push(subName) 102 | allModules[subName] = rawModules[m][sub] 103 | } 104 | } 105 | } 106 | return { subModules, allModules, moduleList, rawModules } 107 | } 108 | -------------------------------------------------------------------------------- /lib/cutheme.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const postcss = require('postcss') 3 | const postcssNewColor = require('./postcss-colorui-new-color') 4 | const postcssTheme = require('./postcss-colorui-theme') 5 | const postcssLite = require('./postcss-colorui-lite') 6 | const postcssCodeSnippets = require('./postcss-code-snippets') 7 | const { rawModules } = require('./colorui-modules')() 8 | const tools = require('./tools') 9 | const fs = require('fs') 10 | const path = require('path') 11 | 12 | const title = ` 13 | /* 14 | 该文件由 colorui-theme 导出, 工具地址:https://github.com/zero0-1one/colorui-theme 15 | */ 16 | ` 17 | 18 | module.exports = { 19 | async doAll(options) { 20 | let { src, dest } = options 21 | if (src == dest) { 22 | console.warn('导出目录与导入目录相同,可能会覆盖源文件') 23 | } else { 24 | let copyFiles = options.copyFiles || ['icon.css', 'animation.css'] 25 | for (const file of copyFiles) { 26 | if (!fs.existsSync(path.join(src, file))) continue 27 | fs.writeFileSync(path.join(dest, file), fs.readFileSync(path.join(src, file))) 28 | } 29 | } 30 | 31 | let cuCss = fs.readFileSync(path.join(src, 'main.css')) 32 | if (options.addHoverRules) cuCss = await this.addHoverRules(cuCss) 33 | if (options.newColors) cuCss = await this.dumpNewColor(options, cuCss) 34 | if (options.themes) this.dumpTheme(options, cuCss) 35 | if (options.lite) this.dumpLite(options, cuCss, options.newColors) 36 | if (options.codeSnippets) this.dumpCodeSnippets(options, cuCss) 37 | 38 | if (options.fileName !== false) { 39 | let fileName = options.fileName || 'main-new.css' 40 | fs.writeFileSync(path.join(dest, fileName), cuCss) 41 | } 42 | 43 | return path.resolve(options.dest) 44 | // if (options.uncss) this.dumpUncss(options, cuCss) 45 | }, 46 | 47 | async addHoverRules(cuCss) { 48 | let root = postcss.parse(cuCss) 49 | for (const color in rawModules.color) { 50 | let colors = tools.getColors(color, root) 51 | cuCss += tools.createHoverRules(color, colors) 52 | } 53 | return cuCss 54 | }, 55 | 56 | async dumpNewColor(options, cuCss) { 57 | let { src, newColors } = options 58 | cuCss = cuCss || fs.readFileSync(path.join(src, 'main.css')) 59 | let result = await postcss([postcssNewColor(newColors)]).process(cuCss, { from: undefined }) 60 | return result.css 61 | }, 62 | 63 | //根据配置导出主题 css 64 | async dumpTheme(options, cuCss) { 65 | let { src, dest, themes } = options 66 | 67 | cuCss = cuCss || fs.readFileSync(path.join(src, 'main.css')) 68 | 69 | let themesCss = '' 70 | let themesColors = {} 71 | if (!Array.isArray(themes.themes)) themes.themes = [themes.themes] 72 | for (const theme of themes.themes) { 73 | let result = await postcss([postcssTheme(theme)]).process(cuCss, { from: undefined }) 74 | if (theme.fileName !== false) { 75 | let fileName = theme.fileName || `theme-${theme.name}.css` 76 | fs.writeFileSync(path.join(dest, fileName), result.css) 77 | } 78 | if (theme.jsonFileName !== false) { 79 | let jsonFileName = theme.jsonFileName || `${theme.name}-colors.json` 80 | fs.writeFileSync(path.join(dest, jsonFileName), JSON.stringify(result.themeColors, null, 2)) 81 | } 82 | 83 | if (themesCss == '') { 84 | themesCss += result.css 85 | } else { 86 | let index = result.css.indexOf('*/') //去掉注释 87 | themesCss += result.css.slice(index + 2) 88 | } 89 | themesColors[theme.name || 'default'] = result.themeColors 90 | } 91 | 92 | if (themes.fileName !== false) { 93 | let themesFileName = themes.fileName || 'themes.css' 94 | fs.writeFileSync(path.join(dest, themesFileName), themesCss) 95 | } 96 | if (themes.jsonFileName !== false) { 97 | let jsonFileName = themes.jsonFileName || 'themes.json' 98 | fs.writeFileSync(path.join(dest, jsonFileName), JSON.stringify(themesColors, null, 2)) 99 | } 100 | // if (themes.scssFileName !== false) { 101 | // let scssFileName = themes.scssFileName || 'themes.scss' 102 | // fs.writeFileSync(path.join(dest, jsonFileName), JSON.stringify(themesColors, null, 2)) 103 | // } 104 | }, 105 | 106 | //根据指定模块来导出使用的 css 107 | async dumpLite(options, cuCss, newColors) { 108 | let { src, dest, lite } = options 109 | cuCss = cuCss || fs.readFileSync(path.join(src, 'main.css')) 110 | let result = await postcss([postcssLite({ ...lite, newColors })]).process(cuCss, { from: undefined }) 111 | 112 | if (lite.fileName !== false) { 113 | let fileName = lite.fileName || `main-lite.css` 114 | fs.writeFileSync(path.join(dest, fileName), result.css) 115 | } 116 | }, 117 | 118 | //使用 uncss 移除未使用的 css 119 | async dumpUncss(options) { 120 | let { src, dest, uncss, cuCss } = options 121 | cuCss = cuCss || fs.readFileSync(path.join(src, 'main.css')) 122 | throw new Error('尚未实现') 123 | }, 124 | 125 | async dumpCodeSnippets(options, cuCss) { 126 | let { src, dest, codeSnippets } = options 127 | cuCss = cuCss || fs.readFileSync(path.join(src, 'main.css')) 128 | if (!codeSnippets.dir) codeSnippets.dir = dest 129 | if (codeSnippets.prefix !== false) codeSnippets.prefix = codeSnippets.prefix || 'cu-' 130 | await postcss([postcssCodeSnippets(codeSnippets)]).process(cuCss, { from: undefined }) 131 | }, 132 | } 133 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai') 2 | const postcss = require('postcss') 3 | const postcssFilterRules = require('../lib/postcss-filter-rules') 4 | const postcssCopy = require('../lib/postcss-copy') 5 | const postcssTheme = require('../lib/postcss-colorui-theme') 6 | const postcssLite = require('../lib/postcss-colorui-lite') 7 | const postcssCodeSnippets = require('../lib/postcss-code-snippets') 8 | const cutheme = require('../lib/cutheme') 9 | const fs = require('fs') 10 | const path = require('path') 11 | 12 | for (const dir of ['css', 'css/lib', 'css/bin', 'css/plugin']) { 13 | if (!fs.existsSync(path.join(__dirname, dir))) fs.mkdirSync(path.join(__dirname, dir)) 14 | } 15 | 16 | let css1 = ` 17 | .a{ 18 | color:red; 19 | } 20 | 21 | .abc{ 22 | color:red; 23 | } 24 | 25 | .c, 26 | .b{ 27 | color:red; 28 | } 29 | 30 | .bd{ 31 | color:red; 32 | }` 33 | 34 | let css_retain_b = ` 35 | .abc{ 36 | color:red; 37 | } 38 | 39 | .b{ 40 | color:red; 41 | } 42 | 43 | .bd{ 44 | color:red; 45 | }` 46 | 47 | let css_retain_ac = ` 48 | .a{ 49 | color:red; 50 | } 51 | 52 | .abc{ 53 | color:red; 54 | } 55 | 56 | .c{ 57 | color:red; 58 | }` 59 | 60 | let css_remove_b = ` 61 | .a{ 62 | color:red; 63 | } 64 | 65 | .c{ 66 | color:red; 67 | }` 68 | 69 | let css_remove_ac = ` 70 | .b{ 71 | color:red; 72 | } 73 | 74 | .bd{ 75 | color:red; 76 | }` 77 | 78 | 79 | let css_copy_b2x = ` 80 | .axc{ 81 | color:red; 82 | } 83 | 84 | .x{ 85 | color:red; 86 | } 87 | 88 | .xd{ 89 | color:red; 90 | }` 91 | 92 | 93 | let css_copy_b2x_c2y = ` 94 | .axc, 95 | .aby{ 96 | color:red; 97 | } 98 | 99 | .y, 100 | .x{ 101 | color:red; 102 | } 103 | 104 | .xd{ 105 | color:red; 106 | }` 107 | 108 | 109 | let css1_copy_ab2abb = ` 110 | .abbc{ 111 | color:red; 112 | }` 113 | 114 | let css1_copy_ab2abb_prefix = ` 115 | .p .abbc{ 116 | color:red; 117 | }` 118 | 119 | 120 | describe('postcss-filter-rules', function () { 121 | it('retain string', async function () { 122 | let opts = { filter: 'b', isRemove: false } 123 | let result = await postcss([postcssFilterRules(opts)]).process(css1, { from: undefined }) 124 | expect(result.css).equal(css_retain_b) 125 | expect(result.warnings().length).equal(0) 126 | }) 127 | 128 | it('retain array', async function () { 129 | let opts = { filter: ['a', 'c'], isRemove: false } 130 | let result = await postcss([postcssFilterRules(opts)]).process(css1, { from: undefined }) 131 | expect(result.css).equal(css_retain_ac) 132 | expect(result.warnings().length).equal(0) 133 | }) 134 | 135 | it('remove string', async function () { 136 | let opts = { filter: 'b', isRemove: true } 137 | let result = await postcss([postcssFilterRules(opts)]).process(css1, { from: undefined }) 138 | expect(result.css).equal(css_remove_b) 139 | expect(result.warnings().length).equal(0) 140 | }) 141 | 142 | it('remove array', async function () { 143 | let opts = { filter: ['a', 'c'], isRemove: true } 144 | let result = await postcss([postcssFilterRules(opts)]).process(css1, { from: undefined }) 145 | expect(result.css).equal(css_remove_ac) 146 | expect(result.warnings().length).equal(0) 147 | }) 148 | }) 149 | 150 | 151 | describe('postcss-copy', function () { 152 | it('copy one', async function () { 153 | let opts = { copy: ['b', 'x'] } 154 | let result = await postcss([postcssCopy(opts)]).process(css1, { from: undefined }) 155 | expect(result.css).equal(css_copy_b2x) 156 | expect(result.warnings().length).equal(0) 157 | }) 158 | 159 | it('copy many', async function () { 160 | let opts = { copy: [['b', 'x'], ['c', 'y']] } 161 | let result = await postcss([postcssCopy(opts)]).process(css1, { from: undefined }) 162 | expect(result.css).equal(css_copy_b2x_c2y) 163 | expect(result.warnings().length).equal(0) 164 | }) 165 | 166 | 167 | it('copy with capture', async function () { 168 | let opts = { copy: ['a(b)', 'a$1$1'] } 169 | let result = await postcss([postcssCopy(opts)]).process(css1, { from: undefined }) 170 | expect(result.css).equal(css1_copy_ab2abb) 171 | expect(result.warnings().length).equal(0) 172 | }) 173 | 174 | 175 | it('copy with prefix', async function () { 176 | let opts = { copy: ['a(b)', 'a$1$1'], prefix: '.p ' } 177 | let result = await postcss([postcssCopy(opts)]).process(css1, { from: undefined }) 178 | expect(result.css).equal(css1_copy_ab2abb_prefix) 179 | expect(result.warnings().length).equal(0) 180 | }) 181 | }) 182 | 183 | 184 | 185 | // describe('postcss-code-snippets', function () { 186 | // it('copy one', async function () { 187 | // let opts = { filePath: "", prefix: 'pre-' } 188 | // let result = await postcss([postcssCodeSnippets(opts)]).process(css1, { from: undefined }) 189 | // let prefix = Object.keys(result.codeSnippets).map(k => result.codeSnippets[k].prefix).sort() 190 | // expect(prefix).to.deep.equal(['pre-a', 'pre-abc', 'pre-b', 'pre-c', 'pre-bd'].sort()) 191 | // expect(result.codeSnippets).to.have.all.keys('a', 'abc', 'b', 'c', 'bd') 192 | // }) 193 | // }) 194 | 195 | 196 | describe('postcss-colorui-theme', function () { 197 | it('theme', async function () { 198 | let opts = { 199 | theme: 'blue', 200 | colorMap: { 'activated': 'blue' } 201 | } 202 | let cuCss = fs.readFileSync(path.join(__dirname, 'main.css')) 203 | let result = await postcss([postcssTheme(opts)]).process(cuCss, { from: undefined }) 204 | fs.writeFileSync(path.join(__dirname, `css/plugin/cutheme-${opts.theme}.css`), result.css) 205 | expect(result.warnings().length).equal(0) 206 | }) 207 | 208 | it('theme new color', async function () { 209 | let opts = { 210 | theme: 'newColor', 211 | newColor: { //定义新颜色 212 | newblue: { 213 | main: '#0081ff', 214 | inverse: '#ffffff', 215 | light: '#cce6ff', 216 | shadow: 'rgba(0, 102, 204, 0.2);', 217 | gradual: '#1cbbb4', 218 | } 219 | }, 220 | colorMap: { 'activated': 'newblue' } 221 | } 222 | let cuCss = fs.readFileSync(path.join(__dirname, 'main.css')) 223 | let result = await postcss([postcssTheme(opts)]).process(cuCss, { from: undefined }) 224 | fs.writeFileSync(path.join(__dirname, `css/plugin/cutheme-${opts.theme}.css`), result.css) 225 | expect(result.warnings().length).equal(0) 226 | }) 227 | }) 228 | 229 | 230 | 231 | describe('postcss-colorui-lite', function () { 232 | it('theme', async function () { 233 | let opts = { 234 | modules: [ 235 | // 'color', 236 | 'color' 237 | ], 238 | isRemove: false //指定的modules 是删除 还是保留模式, 默认删除模式 239 | } 240 | let cuCss = fs.readFileSync(path.join(__dirname, 'main.css')) 241 | let result = await postcss([postcssLite(opts)]).process(cuCss, { from: undefined }) 242 | fs.writeFileSync(path.join(__dirname, `css/plugin/main-lite.css`), result.css) 243 | expect(result.warnings().length).equal(0) 244 | }) 245 | }) 246 | 247 | describe('lib', function () { 248 | it('dumpTheme', async function () { 249 | await cutheme.dumpTheme({ 250 | src: path.join(__dirname), // 指定 colorui 中 main.css 所在的目录 251 | dest: path.join(__dirname, 'css/lib'), // 指定生成文件保存的目录 252 | 253 | //多主题配置 254 | themes: { 255 | themes: [{ 256 | name: 'test', //主题名称 默认:'default', 257 | fileName: '', //导出的文件名默认 `theme-${theme.name}.css` 258 | namespace: '', //每个选择器追加的命名空间, 默认未 `.theme-${theme.name} ` 注意:通常后面有空格 259 | newColor: { //定义新颜色 260 | newblue: { 261 | main: '#0081ff', 262 | inverse: '#ffffff', 263 | light: '#cce6ff', 264 | shadow: 'rgba(0, 102, 204, 0.2);', 265 | gradual: '#1cbbb4', 266 | lightInverse: '#0081ff', //可不填, 默认与 main 相同 267 | } 268 | }, 269 | colorMap: {//指定主题中每种元素映射 colorui 中颜 270 | 'activated': 'blue', 271 | 'disabled': 'grey', 272 | 'newColor': 'newblue', 273 | }, 274 | }] 275 | } 276 | }) 277 | }) 278 | 279 | it('dumpLite', async function () { 280 | await cutheme.dumpLite({ 281 | src: path.join(__dirname), // 指定 colorui 中 main.css 所在的目录 282 | dest: path.join(__dirname, 'css/lib'), // 指定生成文件保存的目录 283 | lite: { 284 | modules: ['color-red'], 285 | isRemove: false, 286 | } 287 | }) 288 | }) 289 | 290 | it('doAll', async function () { 291 | await cutheme.doAll(require('./config.json')) 292 | }) 293 | }) 294 | 295 | 296 | -------------------------------------------------------------------------------- /lib/tools.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | //将颜色字符串 解析为rgb数组, 支持 'rgb(234, 200, 190)' '#ffffff' '#fff' 式样 4 | colorParse(color) { 5 | color = color.trim().toLowerCase() 6 | let data = [] 7 | if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/.test(color)) { 8 | if (color.length == 4) { 9 | // !!函数内重名 i, c 在非node 环境 会有问题, 这里使用 var 10 | for (var i = 1; i < 4; i += 1) { 11 | var c = color.slice(i, i + 1) 12 | data.push(parseInt('0x' + c + c)) 13 | } 14 | } else { 15 | for (var i = 1; i < 7; i += 2) { 16 | var c = color.slice(i, i + 2) 17 | data.push(parseInt('0x' + c)) 18 | } 19 | } 20 | return data 21 | } 22 | color = color.replace(/\s/g, '') 23 | let matches = color.match(/^rgb\((\d+)\,(\d+)\,(\d+)\)$/) 24 | if (matches) { 25 | for (var i = 1; i < 4; i++) { 26 | var v = parseInt(matches[i]) 27 | if (v < 0 || v > 255) return 28 | data.push(v) 29 | } 30 | return data 31 | } 32 | }, 33 | 34 | colorRgb(data) { 35 | return 'rgb(' + data.join(',') + ')' 36 | }, 37 | 38 | colorHex(data) { 39 | return '#' + data.map(v => v.toString(16).padStart(2, '0')).join('') 40 | }, 41 | 42 | // r,g,b范围:[0,255] 43 | // h范围:[0,360] s,l范围:[0,100] 44 | rgb2hsl([r, g, b], round = true) { 45 | r = r / 255 46 | g = g / 255 47 | b = b / 255 48 | 49 | let min = Math.min(r, g, b) 50 | let max = Math.max(r, g, b) 51 | 52 | let h, s, l 53 | l = (min + max) / 2 54 | let difference = max - min 55 | if (max == min) { 56 | h = 0 57 | s = 0 58 | } else { 59 | s = l > 0.5 ? difference / (2.0 - max - min) : difference / (max + min) 60 | switch (max) { 61 | case r: 62 | h = (g - b) / difference + (g < b ? 6 : 0) 63 | break 64 | case g: 65 | h = 2.0 + (b - r) / difference 66 | break 67 | case b: 68 | h = 4.0 + (r - g) / difference 69 | break 70 | } 71 | h = h * 60 72 | } 73 | s = s * 100 //转换成百分比的形式 74 | l = l * 100 75 | return round ? [h, s, l].map(v => Math.round(v)) : [h, s, l] 76 | }, 77 | 78 | // r,g,b范围:[0,255] 79 | // h范围:[0,360] s,v范围:[0,100] 80 | rgb2hsv([r, g, b], round = true) { 81 | r = r / 255 82 | g = g / 255 83 | b = b / 255 84 | let h, s, v 85 | let min = Math.min(r, g, b) 86 | let max = (v = Math.max(r, g, b)) 87 | let difference = max - min 88 | 89 | if (max == min) { 90 | h = 0 91 | } else { 92 | switch (max) { 93 | case r: 94 | h = (g - b) / difference + (g < b ? 6 : 0) 95 | break 96 | case g: 97 | h = 2.0 + (b - r) / difference 98 | break 99 | case b: 100 | h = 4.0 + (r - g) / difference 101 | break 102 | } 103 | h = h * 60 104 | } 105 | if (max == 0) { 106 | s = 0 107 | } else { 108 | s = 1 - min / max 109 | } 110 | s = s * 100 111 | v = v * 100 112 | return round ? [h, s, v].map(v => Math.round(v)) : [h, s, v] 113 | }, 114 | 115 | // r,g,b范围:[0,255] 116 | // h范围:[0,360] s,l范围:[0,100] 117 | hsl2rgb([h, s, l], round = true) { 118 | h = h / 360 119 | s = s / 100 120 | l = l / 100 121 | let rgb = [] 122 | 123 | if (s == 0) { 124 | rgb = [l * 255, l * 255, l * 255] 125 | } else { 126 | let q = l >= 0.5 ? l + s - l * s : l * (1 + s) 127 | let p = 2 * l - q 128 | rgb[0] = h + 1 / 3 129 | rgb[1] = h 130 | rgb[2] = h - 1 / 3 131 | for (let i = 0; i < rgb.length; i++) { 132 | let tc = rgb[i] 133 | if (tc < 0) { 134 | tc = tc + 1 135 | } else if (tc > 1) { 136 | tc = tc - 1 137 | } 138 | switch (true) { 139 | case tc < 1 / 6: 140 | tc = p + (q - p) * 6 * tc 141 | break 142 | case 1 / 6 <= tc && tc < 0.5: 143 | tc = q 144 | break 145 | case 0.5 <= tc && tc < 2 / 3: 146 | tc = p + (q - p) * (4 - 6 * tc) 147 | break 148 | default: 149 | tc = p 150 | break 151 | } 152 | rgb[i] = tc * 255 153 | } 154 | } 155 | return round ? rgb.map(v => Math.round(v)) : rgb 156 | }, 157 | 158 | // r,g,b范围:[0,255] 159 | // h范围:[0,360] s,v范围:[0,100] 160 | hsv2rgb([h, s, v], round = true) { 161 | s = s / 100 162 | v = v / 100 163 | let h1 = Math.floor(h / 60) % 6 164 | let f = h / 60 - h1 165 | let p = v * (1 - s) 166 | let q = v * (1 - f * s) 167 | let t = v * (1 - (1 - f) * s) 168 | let r, g, b 169 | switch (h1) { 170 | case 0: 171 | r = v 172 | g = t 173 | b = p 174 | break 175 | case 1: 176 | r = q 177 | g = v 178 | b = p 179 | break 180 | case 2: 181 | r = p 182 | g = v 183 | b = t 184 | break 185 | case 3: 186 | r = p 187 | g = q 188 | b = v 189 | break 190 | case 4: 191 | r = t 192 | g = p 193 | b = v 194 | break 195 | case 5: 196 | r = v 197 | g = p 198 | b = q 199 | break 200 | } 201 | let rgb = [r * 255, g * 255, b * 255] 202 | return round ? rgb.map(v => Math.round(v)) : rgb 203 | }, 204 | 205 | interColor(color1, color2, ratio) { 206 | let color = [] 207 | let ratio2 = 1 - ratio 208 | for (let i = 0; i < 3; i++) { 209 | color.push(Math.round(color1[i] * ratio + color2[i] * ratio2)) 210 | } 211 | return color 212 | }, 213 | 214 | difficultyColor(difficulty, forget, vague, know) { 215 | if (difficulty > 50) { 216 | forget = this.colorParse(forget) 217 | vague = this.colorParse(vague) 218 | return this.colorHex(this.interColor(forget, vague, (difficulty - 50) / 50)) 219 | } else { 220 | vague = this.colorParse(vague) 221 | know = this.colorParse(know) 222 | return this.colorHex(this.interColor(vague, know, difficulty / 50)) 223 | } 224 | }, 225 | 226 | deepenColor(color, rate = 0.8) { 227 | let isStr = typeof color == 'string' 228 | let rgb = isStr ? this.colorParse(color) : color 229 | let hsl = this.rgb2hsl(rgb, false) 230 | hsl[2] *= rate 231 | rgb = this.hsl2rgb(hsl) 232 | return isStr ? this.colorHex(rgb) : rgb 233 | }, 234 | 235 | createHoverRules(name, colors) { 236 | let colorsHover = colors.hover || this.deepenColor(colors.main) 237 | let hoverStr = ` 238 | 239 | .bg-${name}.button-hover, 240 | .bg-${name}.hover { 241 | color: ${colors.inverse}; 242 | background-color: ${colorsHover}; 243 | }` 244 | if (colors.light && colors['light-inverse']) { 245 | let lightHover = colors['light-hover'] || this.deepenColor(colors.light) 246 | hoverStr += ` 247 | 248 | .bg-${name}.light.button-hover, 249 | .bg-${name}.light.hover { 250 | color: ${colors['light-inverse']}; 251 | background-color: ${lightHover}; 252 | }` 253 | } 254 | return hoverStr 255 | }, 256 | 257 | // root: colorui 的 postcss root 258 | getColors(name, root) { 259 | let colorRules = [] 260 | root.walkRules(new RegExp(`-${name}([^a-zA-Z0-9]|$)`), rule => { 261 | colorRules.push(rule) 262 | }) 263 | const colorReg = /(rgba?\s*\(\s*\d+\s*(\,\s*[0-9\.]+\s*){2,3}\))|(#[0-9a-f]{3,6})/gi 264 | let findColors = function (selector, propName, count = 1) { 265 | let color = null 266 | for (const rule of colorRules) { 267 | if (rule.selector.includes(selector)) { 268 | rule.walkDecls(propName, decl => { 269 | let rt = decl.value.match(colorReg) 270 | if (rt && rt.length >= count) { 271 | rt = rt.map(c => c.replace(/\s+/g, '')) 272 | color = count == 1 ? rt[0] : rt.slice(0, count) 273 | } 274 | return color === null 275 | }) 276 | if (color !== null) break 277 | } 278 | } 279 | return color 280 | } 281 | 282 | let colors = { 283 | 'main': findColors(`.text-${name}`, 'color'), 284 | 'inverse': findColors(`.bg-${name}`, 'color'), 285 | 'hover': findColors(`.bg-${name}.hover`, 'background-color'), 286 | 'light': findColors(`.bg-${name}.light`, 'background-color'), 287 | 'light-hover': findColors(`.bg-${name}.light.hover`, 'background-color'), 288 | 'shadow': findColors(`.text-shadow[class*='-${name}']`, 'text-shadow'), 289 | 'gradual': findColors(`.bg-gradual-${name}`, 'background-image', 2), 290 | 'light-inverse': findColors(`.bg-${name}.light`, 'color'), 291 | } 292 | return colors 293 | }, 294 | } 295 | -------------------------------------------------------------------------------- /test/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | ColorUi for uniApp v2.1.6 | by 文晓港 2019-05-31 10:44:24 3 | 仅供学习交流,如作它用所承受的法律责任一概与作者无关 4 | 5 | *使用ColorUi开发扩展与插件时,请注明基于ColorUi开发 6 | 7 | (QQ交流群:240787041) 8 | */ 9 | 10 | /* ================== 11 | 初始化 12 | ==================== */ 13 | body { 14 | background-color: #f1f1f1; 15 | font-size: 28upx; 16 | color: #333333; 17 | font-family: Helvetica Neue, Helvetica, sans-serif; 18 | } 19 | 20 | view, 21 | scroll-view, 22 | swiper, 23 | button, 24 | input, 25 | textarea, 26 | label, 27 | navigator, 28 | image { 29 | box-sizing: border-box; 30 | } 31 | 32 | .round { 33 | border-radius: 5000upx; 34 | } 35 | 36 | .radius { 37 | border-radius: 6upx; 38 | } 39 | 40 | /* ================== 41 | 图片 42 | ==================== */ 43 | 44 | image { 45 | max-width: 100%; 46 | display: inline-block; 47 | position: relative; 48 | z-index: 0; 49 | } 50 | 51 | image.loading::before { 52 | content: ''; 53 | background-color: #f5f5f5; 54 | display: block; 55 | position: absolute; 56 | width: 100%; 57 | height: 100%; 58 | z-index: -2; 59 | } 60 | 61 | image.loading::after { 62 | content: '\e7f1'; 63 | font-family: 'cuIcon'; 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | width: 32upx; 68 | height: 32upx; 69 | line-height: 32upx; 70 | right: 0; 71 | bottom: 0; 72 | z-index: -1; 73 | font-size: 32upx; 74 | margin: auto; 75 | color: #ccc; 76 | -webkit-animation: cuIcon-spin 2s infinite linear; 77 | animation: cuIcon-spin 2s infinite linear; 78 | display: block; 79 | } 80 | 81 | .response { 82 | width: 100%; 83 | } 84 | 85 | /* ================== 86 | 开关 87 | ==================== */ 88 | 89 | switch, 90 | checkbox, 91 | radio { 92 | position: relative; 93 | } 94 | 95 | switch::after, 96 | switch::before { 97 | font-family: 'cuIcon'; 98 | content: '\e645'; 99 | position: absolute; 100 | color: #ffffff !important; 101 | top: 0%; 102 | left: 0upx; 103 | font-size: 26upx; 104 | line-height: 26px; 105 | width: 50%; 106 | text-align: center; 107 | pointer-events: none; 108 | transform: scale(0, 0); 109 | transition: all 0.3s ease-in-out 0s; 110 | z-index: 9; 111 | bottom: 0; 112 | height: 26px; 113 | margin: auto; 114 | } 115 | 116 | switch::before { 117 | content: '\e646'; 118 | right: 0; 119 | transform: scale(1, 1); 120 | left: auto; 121 | } 122 | 123 | switch[checked]::after, 124 | switch.checked::after { 125 | transform: scale(1, 1); 126 | } 127 | 128 | switch[checked]::before, 129 | switch.checked::before { 130 | transform: scale(0, 0); 131 | } 132 | 133 | /* #ifndef MP-ALIPAY */ 134 | radio::before, 135 | checkbox::before { 136 | font-family: 'cuIcon'; 137 | content: '\e645'; 138 | position: absolute; 139 | color: #ffffff !important; 140 | top: 50%; 141 | margin-top: -8px; 142 | right: 5px; 143 | font-size: 32upx; 144 | line-height: 16px; 145 | pointer-events: none; 146 | transform: scale(1, 1); 147 | transition: all 0.3s ease-in-out 0s; 148 | z-index: 9; 149 | } 150 | 151 | radio .wx-radio-input, 152 | checkbox .wx-checkbox-input, 153 | radio .uni-radio-input, 154 | checkbox .uni-checkbox-input { 155 | margin: 0; 156 | width: 24px; 157 | height: 24px; 158 | } 159 | 160 | checkbox.round .wx-checkbox-input, 161 | checkbox.round .uni-checkbox-input { 162 | border-radius: 100upx; 163 | } 164 | 165 | /* #endif */ 166 | 167 | switch[checked]::before { 168 | transform: scale(0, 0); 169 | } 170 | 171 | switch .wx-switch-input, 172 | switch .uni-switch-input { 173 | border: none; 174 | padding: 0 24px; 175 | width: 48px; 176 | height: 26px; 177 | margin: 0; 178 | border-radius: 100upx; 179 | } 180 | 181 | switch .wx-switch-input:not([class*='bg-']), 182 | switch .uni-switch-input:not([class*='bg-']) { 183 | background: #8799a3 !important; 184 | } 185 | 186 | switch .wx-switch-input::after, 187 | switch .uni-switch-input::after { 188 | margin: auto; 189 | width: 26px; 190 | height: 26px; 191 | border-radius: 100upx; 192 | left: 0upx; 193 | top: 0upx; 194 | bottom: 0upx; 195 | position: absolute; 196 | transform: scale(0.9, 0.9); 197 | transition: all 0.1s ease-in-out 0s; 198 | } 199 | 200 | switch .wx-switch-input.wx-switch-input-checked::after, 201 | switch .uni-switch-input.uni-switch-input-checked::after { 202 | margin: auto; 203 | left: 22px; 204 | box-shadow: none; 205 | transform: scale(0.9, 0.9); 206 | } 207 | 208 | radio-group { 209 | display: inline-block; 210 | } 211 | 212 | switch.radius .wx-switch-input::after, 213 | switch.radius .wx-switch-input, 214 | switch.radius .wx-switch-input::before, 215 | switch.radius .uni-switch-input::after, 216 | switch.radius .uni-switch-input, 217 | switch.radius .uni-switch-input::before { 218 | border-radius: 10upx; 219 | } 220 | 221 | switch .wx-switch-input::before, 222 | radio.radio::before, 223 | checkbox .wx-checkbox-input::before, 224 | radio .wx-radio-input::before, 225 | switch .uni-switch-input::before, 226 | radio.radio::before, 227 | checkbox .uni-checkbox-input::before, 228 | radio .uni-radio-input::before { 229 | display: none; 230 | } 231 | 232 | radio.radio[checked]::after, 233 | radio.radio .uni-radio-input-checked::after { 234 | content: ''; 235 | background-color: transparent; 236 | display: block; 237 | position: absolute; 238 | width: 8px; 239 | height: 8px; 240 | z-index: 999; 241 | top: 0upx; 242 | left: 0upx; 243 | right: 0; 244 | bottom: 0; 245 | margin: auto; 246 | border-radius: 200upx; 247 | /* #ifndef MP */ 248 | border: 7px solid #ffffff !important; 249 | /* #endif */ 250 | 251 | /* #ifdef MP */ 252 | border: 8px solid #ffffff !important; 253 | /* #endif */ 254 | } 255 | 256 | .switch-sex::after { 257 | content: '\e71c'; 258 | } 259 | 260 | .switch-sex::before { 261 | content: '\e71a'; 262 | } 263 | 264 | .switch-sex .wx-switch-input, 265 | .switch-sex .uni-switch-input { 266 | background: #e54d42 !important; 267 | border-color: #e54d42 !important; 268 | } 269 | 270 | .switch-sex[checked] .wx-switch-input, 271 | .switch-sex.checked .uni-switch-input { 272 | background: #0081ff !important; 273 | border-color: #0081ff !important; 274 | } 275 | 276 | switch.red[checked] .wx-switch-input.wx-switch-input-checked, 277 | checkbox.red[checked] .wx-checkbox-input, 278 | radio.red[checked] .wx-radio-input, 279 | switch.red.checked .uni-switch-input.uni-switch-input-checked, 280 | checkbox.red.checked .uni-checkbox-input, 281 | radio.red.checked .uni-radio-input { 282 | background-color: #e54d42 !important; 283 | border-color: #e54d42 !important; 284 | color: #ffffff !important; 285 | } 286 | 287 | switch.orange[checked] .wx-switch-input, 288 | checkbox.orange[checked] .wx-checkbox-input, 289 | radio.orange[checked] .wx-radio-input, 290 | switch.orange.checked .uni-switch-input, 291 | checkbox.orange.checked .uni-checkbox-input, 292 | radio.orange.checked .uni-radio-input { 293 | background-color: #f37b1d !important; 294 | border-color: #f37b1d !important; 295 | color: #ffffff !important; 296 | } 297 | 298 | switch.yellow[checked] .wx-switch-input, 299 | checkbox.yellow[checked] .wx-checkbox-input, 300 | radio.yellow[checked] .wx-radio-input, 301 | switch.yellow.checked .uni-switch-input, 302 | checkbox.yellow.checked .uni-checkbox-input, 303 | radio.yellow.checked .uni-radio-input { 304 | background-color: #fbbd08 !important; 305 | border-color: #fbbd08 !important; 306 | color: #333333 !important; 307 | } 308 | 309 | switch.olive[checked] .wx-switch-input, 310 | checkbox.olive[checked] .wx-checkbox-input, 311 | radio.olive[checked] .wx-radio-input, 312 | switch.olive.checked .uni-switch-input, 313 | checkbox.olive.checked .uni-checkbox-input, 314 | radio.olive.checked .uni-radio-input { 315 | background-color: #8dc63f !important; 316 | border-color: #8dc63f !important; 317 | color: #ffffff !important; 318 | } 319 | 320 | switch.green[checked] .wx-switch-input, 321 | switch[checked] .wx-switch-input, 322 | checkbox.green[checked] .wx-checkbox-input, 323 | checkbox[checked] .wx-checkbox-input, 324 | radio.green[checked] .wx-radio-input, 325 | radio[checked] .wx-radio-input, 326 | switch.green.checked .uni-switch-input, 327 | switch.checked .uni-switch-input, 328 | checkbox.green.checked .uni-checkbox-input, 329 | checkbox.checked .uni-checkbox-input, 330 | radio.green.checked .uni-radio-input, 331 | radio.checked .uni-radio-input { 332 | background-color: #39b54a !important; 333 | border-color: #39b54a !important; 334 | color: #ffffff !important; 335 | border-color: #39b54a !important; 336 | } 337 | 338 | switch.cyan[checked] .wx-switch-input, 339 | checkbox.cyan[checked] .wx-checkbox-input, 340 | radio.cyan[checked] .wx-radio-input, 341 | switch.cyan.checked .uni-switch-input, 342 | checkbox.cyan.checked .uni-checkbox-input, 343 | radio.cyan.checked .uni-radio-input { 344 | background-color: #1cbbb4 !important; 345 | border-color: #1cbbb4 !important; 346 | color: #ffffff !important; 347 | } 348 | 349 | switch.blue[checked] .wx-switch-input, 350 | checkbox.blue[checked] .wx-checkbox-input, 351 | radio.blue[checked] .wx-radio-input, 352 | switch.blue.checked .uni-switch-input, 353 | checkbox.blue.checked .uni-checkbox-input, 354 | radio.blue.checked .uni-radio-input { 355 | background-color: #0081ff !important; 356 | border-color: #0081ff !important; 357 | color: #ffffff !important; 358 | } 359 | 360 | switch.purple[checked] .wx-switch-input, 361 | checkbox.purple[checked] .wx-checkbox-input, 362 | radio.purple[checked] .wx-radio-input, 363 | switch.purple.checked .uni-switch-input, 364 | checkbox.purple.checked .uni-checkbox-input, 365 | radio.purple.checked .uni-radio-input { 366 | background-color: #6739b6 !important; 367 | border-color: #6739b6 !important; 368 | color: #ffffff !important; 369 | } 370 | 371 | switch.mauve[checked] .wx-switch-input, 372 | checkbox.mauve[checked] .wx-checkbox-input, 373 | radio.mauve[checked] .wx-radio-input, 374 | switch.mauve.checked .uni-switch-input, 375 | checkbox.mauve.checked .uni-checkbox-input, 376 | radio.mauve.checked .uni-radio-input { 377 | background-color: #9c26b0 !important; 378 | border-color: #9c26b0 !important; 379 | color: #ffffff !important; 380 | } 381 | 382 | switch.pink[checked] .wx-switch-input, 383 | checkbox.pink[checked] .wx-checkbox-input, 384 | radio.pink[checked] .wx-radio-input, 385 | switch.pink.checked .uni-switch-input, 386 | checkbox.pink.checked .uni-checkbox-input, 387 | radio.pink.checked .uni-radio-input { 388 | background-color: #e03997 !important; 389 | border-color: #e03997 !important; 390 | color: #ffffff !important; 391 | } 392 | 393 | switch.brown[checked] .wx-switch-input, 394 | checkbox.brown[checked] .wx-checkbox-input, 395 | radio.brown[checked] .wx-radio-input, 396 | switch.brown.checked .uni-switch-input, 397 | checkbox.brown.checked .uni-checkbox-input, 398 | radio.brown.checked .uni-radio-input { 399 | background-color: #a5673f !important; 400 | border-color: #a5673f !important; 401 | color: #ffffff !important; 402 | } 403 | 404 | switch.grey[checked] .wx-switch-input, 405 | checkbox.grey[checked] .wx-checkbox-input, 406 | radio.grey[checked] .wx-radio-input, 407 | switch.grey.checked .uni-switch-input, 408 | checkbox.grey.checked .uni-checkbox-input, 409 | radio.grey.checked .uni-radio-input { 410 | background-color: #8799a3 !important; 411 | border-color: #8799a3 !important; 412 | color: #ffffff !important; 413 | } 414 | 415 | switch.gray[checked] .wx-switch-input, 416 | checkbox.gray[checked] .wx-checkbox-input, 417 | radio.gray[checked] .wx-radio-input, 418 | switch.gray.checked .uni-switch-input, 419 | checkbox.gray.checked .uni-checkbox-input, 420 | radio.gray.checked .uni-radio-input { 421 | background-color: #f0f0f0 !important; 422 | border-color: #f0f0f0 !important; 423 | color: #333333 !important; 424 | } 425 | 426 | switch.black[checked] .wx-switch-input, 427 | checkbox.black[checked] .wx-checkbox-input, 428 | radio.black[checked] .wx-radio-input, 429 | switch.black.checked .uni-switch-input, 430 | checkbox.black.checked .uni-checkbox-input, 431 | radio.black.checked .uni-radio-input { 432 | background-color: #333333 !important; 433 | border-color: #333333 !important; 434 | color: #ffffff !important; 435 | } 436 | 437 | switch.white[checked] .wx-switch-input, 438 | checkbox.white[checked] .wx-checkbox-input, 439 | radio.white[checked] .wx-radio-input, 440 | switch.white.checked .uni-switch-input, 441 | checkbox.white.checked .uni-checkbox-input, 442 | radio.white.checked .uni-radio-input { 443 | background-color: #ffffff !important; 444 | border-color: #ffffff !important; 445 | color: #333333 !important; 446 | } 447 | 448 | /* ================== 449 | 边框 450 | ==================== */ 451 | 452 | /* -- 实线 -- */ 453 | 454 | .solid, 455 | .solid-top, 456 | .solid-right, 457 | .solid-bottom, 458 | .solid-left, 459 | .solids, 460 | .solids-top, 461 | .solids-right, 462 | .solids-bottom, 463 | .solids-left, 464 | .dashed, 465 | .dashed-top, 466 | .dashed-right, 467 | .dashed-bottom, 468 | .dashed-left { 469 | position: relative; 470 | } 471 | 472 | .solid::after, 473 | .solid-top::after, 474 | .solid-right::after, 475 | .solid-bottom::after, 476 | .solid-left::after, 477 | .solids::after, 478 | .solids-top::after, 479 | .solids-right::after, 480 | .solids-bottom::after, 481 | .solids-left::after, 482 | .dashed::after, 483 | .dashed-top::after, 484 | .dashed-right::after, 485 | .dashed-bottom::after, 486 | .dashed-left::after { 487 | content: ' '; 488 | width: 200%; 489 | height: 200%; 490 | position: absolute; 491 | top: 0; 492 | left: 0; 493 | border-radius: inherit; 494 | transform: scale(0.5); 495 | transform-origin: 0 0; 496 | pointer-events: none; 497 | box-sizing: border-box; 498 | } 499 | 500 | .solid::after { 501 | border: 1upx solid rgba(0, 0, 0, 0.1); 502 | } 503 | 504 | .solid-top::after { 505 | border-top: 1upx solid rgba(0, 0, 0, 0.1); 506 | } 507 | 508 | .solid-right::after { 509 | border-right: 1upx solid rgba(0, 0, 0, 0.1); 510 | } 511 | 512 | .solid-bottom::after { 513 | border-bottom: 1upx solid rgba(0, 0, 0, 0.1); 514 | } 515 | 516 | .solid-left::after { 517 | border-left: 1upx solid rgba(0, 0, 0, 0.1); 518 | } 519 | 520 | .solids::after { 521 | border: 8upx solid #eee; 522 | } 523 | 524 | .solids-top::after { 525 | border-top: 8upx solid #eee; 526 | } 527 | 528 | .solids-right::after { 529 | border-right: 8upx solid #eee; 530 | } 531 | 532 | .solids-bottom::after { 533 | border-bottom: 8upx solid #eee; 534 | } 535 | 536 | .solids-left::after { 537 | border-left: 8upx solid #eee; 538 | } 539 | 540 | /* -- 虚线 -- */ 541 | 542 | .dashed::after { 543 | border: 1upx dashed #ddd; 544 | } 545 | 546 | .dashed-top::after { 547 | border-top: 1upx dashed #ddd; 548 | } 549 | 550 | .dashed-right::after { 551 | border-right: 1upx dashed #ddd; 552 | } 553 | 554 | .dashed-bottom::after { 555 | border-bottom: 1upx dashed #ddd; 556 | } 557 | 558 | .dashed-left::after { 559 | border-left: 1upx dashed #ddd; 560 | } 561 | 562 | /* -- 阴影 -- */ 563 | 564 | .shadow[class*='white'] { 565 | --ShadowSize: 0 1upx 6upx; 566 | } 567 | 568 | .shadow-lg { 569 | --ShadowSize: 0upx 40upx 100upx 0upx; 570 | } 571 | 572 | .shadow-warp { 573 | position: relative; 574 | box-shadow: 0 0 10upx rgba(0, 0, 0, 0.1); 575 | } 576 | 577 | .shadow-warp:before, 578 | .shadow-warp:after { 579 | position: absolute; 580 | content: ''; 581 | top: 20upx; 582 | bottom: 30upx; 583 | left: 20upx; 584 | width: 50%; 585 | box-shadow: 0 30upx 20upx rgba(0, 0, 0, 0.2); 586 | transform: rotate(-3deg); 587 | z-index: -1; 588 | } 589 | 590 | .shadow-warp:after { 591 | right: 20upx; 592 | left: auto; 593 | transform: rotate(3deg); 594 | } 595 | 596 | .shadow-blur { 597 | position: relative; 598 | } 599 | 600 | .shadow-blur::before { 601 | content: ''; 602 | display: block; 603 | background: inherit; 604 | filter: blur(10upx); 605 | position: absolute; 606 | width: 100%; 607 | height: 100%; 608 | top: 10upx; 609 | left: 10upx; 610 | z-index: -1; 611 | opacity: 0.4; 612 | transform-origin: 0 0; 613 | border-radius: inherit; 614 | transform: scale(1, 1); 615 | } 616 | 617 | /* ================== 618 | 按钮 619 | ==================== */ 620 | 621 | .cu-btn { 622 | position: relative; 623 | border: 0upx; 624 | display: inline-flex; 625 | align-items: center; 626 | justify-content: center; 627 | box-sizing: border-box; 628 | padding: 0 30upx; 629 | font-size: 28upx; 630 | height: 64upx; 631 | line-height: 1; 632 | text-align: center; 633 | text-decoration: none; 634 | overflow: visible; 635 | margin-left: initial; 636 | transform: translate(0upx, 0upx); 637 | margin-right: initial; 638 | } 639 | 640 | .cu-btn::after { 641 | display: none; 642 | } 643 | 644 | .cu-btn:not([class*='bg-']) { 645 | background-color: #f0f0f0; 646 | } 647 | 648 | .cu-btn[class*='line'] { 649 | background-color: transparent; 650 | } 651 | 652 | .cu-btn[class*='line']::after { 653 | content: ' '; 654 | display: block; 655 | width: 200%; 656 | height: 200%; 657 | position: absolute; 658 | top: 0; 659 | left: 0; 660 | border: 1upx solid currentColor; 661 | transform: scale(0.5); 662 | transform-origin: 0 0; 663 | box-sizing: border-box; 664 | border-radius: 12upx; 665 | z-index: 1; 666 | pointer-events: none; 667 | } 668 | 669 | .cu-btn.round[class*='line']::after { 670 | border-radius: 1000upx; 671 | } 672 | 673 | .cu-btn[class*='lines']::after { 674 | border: 6upx solid currentColor; 675 | } 676 | 677 | .cu-btn[class*='bg-']::after { 678 | display: none; 679 | } 680 | 681 | .cu-btn.sm { 682 | padding: 0 20upx; 683 | font-size: 20upx; 684 | height: 48upx; 685 | } 686 | 687 | .cu-btn.lg { 688 | padding: 0 40upx; 689 | font-size: 32upx; 690 | height: 80upx; 691 | } 692 | 693 | .cu-btn.cuIcon.sm { 694 | width: 48upx; 695 | height: 48upx; 696 | } 697 | 698 | .cu-btn.cuIcon { 699 | width: 64upx; 700 | height: 64upx; 701 | border-radius: 500upx; 702 | padding: 0; 703 | } 704 | 705 | button.cuIcon.lg { 706 | width: 80upx; 707 | height: 80upx; 708 | } 709 | 710 | .cu-btn.shadow-blur::before { 711 | top: 4upx; 712 | left: 4upx; 713 | filter: blur(6upx); 714 | opacity: 0.6; 715 | } 716 | 717 | .cu-btn.button-hover { 718 | transform: translate(1upx, 1upx); 719 | } 720 | 721 | .block { 722 | display: block; 723 | } 724 | 725 | .cu-btn.block { 726 | display: flex; 727 | } 728 | 729 | .cu-btn[disabled] { 730 | opacity: 0.6; 731 | color: #ffffff; 732 | } 733 | 734 | /* ================== 735 | 徽章 736 | ==================== */ 737 | 738 | .cu-tag { 739 | font-size: 24upx; 740 | vertical-align: middle; 741 | position: relative; 742 | display: inline-flex; 743 | align-items: center; 744 | justify-content: center; 745 | box-sizing: border-box; 746 | padding: 0upx 16upx; 747 | height: 48upx; 748 | font-family: Helvetica Neue, Helvetica, sans-serif; 749 | white-space: nowrap; 750 | } 751 | 752 | .cu-tag:not([class*='bg']):not([class*='line']) { 753 | background-color: #f1f1f1; 754 | } 755 | 756 | .cu-tag[class*='line-']::after { 757 | content: ' '; 758 | width: 200%; 759 | height: 200%; 760 | position: absolute; 761 | top: 0; 762 | left: 0; 763 | border: 1upx solid currentColor; 764 | transform: scale(0.5); 765 | transform-origin: 0 0; 766 | box-sizing: border-box; 767 | border-radius: inherit; 768 | z-index: 1; 769 | pointer-events: none; 770 | } 771 | 772 | .cu-tag.radius[class*='line']::after { 773 | border-radius: 12upx; 774 | } 775 | 776 | .cu-tag.round[class*='line']::after { 777 | border-radius: 1000upx; 778 | } 779 | 780 | .cu-tag[class*='line-']::after { 781 | border-radius: 0; 782 | } 783 | 784 | .cu-tag + .cu-tag { 785 | margin-left: 10upx; 786 | } 787 | 788 | .cu-tag.sm { 789 | font-size: 20upx; 790 | padding: 0upx 12upx; 791 | height: 32upx; 792 | } 793 | 794 | .cu-capsule { 795 | display: inline-flex; 796 | vertical-align: middle; 797 | } 798 | 799 | .cu-capsule + .cu-capsule { 800 | margin-left: 10upx; 801 | } 802 | 803 | .cu-capsule .cu-tag { 804 | margin: 0; 805 | } 806 | 807 | .cu-capsule .cu-tag[class*='line-']:last-child::after { 808 | border-left: 0upx solid transparent; 809 | } 810 | 811 | .cu-capsule .cu-tag[class*='line-']:first-child::after { 812 | border-right: 0upx solid transparent; 813 | } 814 | 815 | .cu-capsule.radius .cu-tag:first-child { 816 | border-top-left-radius: 6upx; 817 | border-bottom-left-radius: 6upx; 818 | } 819 | 820 | .cu-capsule.radius .cu-tag:last-child::after, 821 | .cu-capsule.radius .cu-tag[class*='line-'] { 822 | border-top-right-radius: 12upx; 823 | border-bottom-right-radius: 12upx; 824 | } 825 | 826 | .cu-capsule.round .cu-tag:first-child { 827 | border-top-left-radius: 200upx; 828 | border-bottom-left-radius: 200upx; 829 | text-indent: 4upx; 830 | } 831 | 832 | .cu-capsule.round .cu-tag:last-child::after, 833 | .cu-capsule.round .cu-tag:last-child { 834 | border-top-right-radius: 200upx; 835 | border-bottom-right-radius: 200upx; 836 | text-indent: -4upx; 837 | } 838 | 839 | .cu-tag.badge { 840 | border-radius: 200upx; 841 | position: absolute; 842 | top: -10upx; 843 | right: -10upx; 844 | font-size: 20upx; 845 | padding: 0upx 10upx; 846 | height: 28upx; 847 | color: #ffffff; 848 | } 849 | 850 | .cu-tag.badge:not([class*='bg-']) { 851 | background-color: #dd514c; 852 | } 853 | 854 | .cu-tag:empty:not([class*='cuIcon-']) { 855 | padding: 0upx; 856 | width: 16upx; 857 | height: 16upx; 858 | top: -4upx; 859 | right: -4upx; 860 | } 861 | 862 | .cu-tag[class*='cuIcon-'] { 863 | width: 32upx; 864 | height: 32upx; 865 | top: -4upx; 866 | right: -4upx; 867 | } 868 | 869 | /* ================== 870 | 头像 871 | ==================== */ 872 | 873 | .cu-avatar { 874 | font-variant: small-caps; 875 | margin: 0; 876 | padding: 0; 877 | display: inline-flex; 878 | text-align: center; 879 | justify-content: center; 880 | align-items: center; 881 | background-color: #ccc; 882 | color: #ffffff; 883 | white-space: nowrap; 884 | position: relative; 885 | width: 64upx; 886 | height: 64upx; 887 | background-size: cover; 888 | background-position: center; 889 | vertical-align: middle; 890 | font-size: 1.5em; 891 | } 892 | 893 | .cu-avatar.sm { 894 | width: 48upx; 895 | height: 48upx; 896 | font-size: 1em; 897 | } 898 | 899 | .cu-avatar.lg { 900 | width: 96upx; 901 | height: 96upx; 902 | font-size: 2em; 903 | } 904 | 905 | .cu-avatar.xl { 906 | width: 128upx; 907 | height: 128upx; 908 | font-size: 2.5em; 909 | } 910 | 911 | .cu-avatar .avatar-text { 912 | font-size: 0.4em; 913 | } 914 | 915 | .cu-avatar-group { 916 | direction: rtl; 917 | unicode-bidi: bidi-override; 918 | padding: 0 10upx 0 40upx; 919 | display: inline-block; 920 | } 921 | 922 | .cu-avatar-group .cu-avatar { 923 | margin-left: -30upx; 924 | border: 4upx solid #f1f1f1; 925 | vertical-align: middle; 926 | } 927 | 928 | .cu-avatar-group .cu-avatar.sm { 929 | margin-left: -20upx; 930 | border: 1upx solid #f1f1f1; 931 | } 932 | 933 | /* ================== 934 | 进度条 935 | ==================== */ 936 | 937 | .cu-progress { 938 | overflow: hidden; 939 | height: 28upx; 940 | background-color: #ebeef5; 941 | display: inline-flex; 942 | align-items: center; 943 | width: 100%; 944 | } 945 | 946 | .cu-progress + view, 947 | .cu-progress + text { 948 | line-height: 1; 949 | } 950 | 951 | .cu-progress.xs { 952 | height: 10upx; 953 | } 954 | 955 | .cu-progress.sm { 956 | height: 20upx; 957 | } 958 | 959 | .cu-progress view { 960 | width: 0; 961 | height: 100%; 962 | align-items: center; 963 | display: flex; 964 | justify-items: flex-end; 965 | justify-content: space-around; 966 | font-size: 20upx; 967 | color: #ffffff; 968 | transition: width 0.6s ease; 969 | } 970 | 971 | .cu-progress text { 972 | align-items: center; 973 | display: flex; 974 | font-size: 20upx; 975 | color: #333333; 976 | text-indent: 10upx; 977 | } 978 | 979 | .cu-progress.text-progress { 980 | padding-right: 60upx; 981 | } 982 | 983 | .cu-progress.striped view { 984 | background-image: linear-gradient( 985 | 45deg, 986 | rgba(255, 255, 255, 0.15) 25%, 987 | transparent 25%, 988 | transparent 50%, 989 | rgba(255, 255, 255, 0.15) 50%, 990 | rgba(255, 255, 255, 0.15) 75%, 991 | transparent 75%, 992 | transparent 993 | ); 994 | background-size: 72upx 72upx; 995 | } 996 | 997 | .cu-progress.active view { 998 | animation: progress-stripes 2s linear infinite; 999 | } 1000 | 1001 | @keyframes progress-stripes { 1002 | from { 1003 | background-position: 72upx 0; 1004 | } 1005 | 1006 | to { 1007 | background-position: 0 0; 1008 | } 1009 | } 1010 | 1011 | /* ================== 1012 | 加载 1013 | ==================== */ 1014 | 1015 | .cu-load { 1016 | display: block; 1017 | line-height: 3em; 1018 | text-align: center; 1019 | } 1020 | 1021 | .cu-load::before { 1022 | font-family: 'cuIcon'; 1023 | display: inline-block; 1024 | margin-right: 6upx; 1025 | } 1026 | 1027 | .cu-load.loading::before { 1028 | content: '\e67a'; 1029 | animation: cuIcon-spin 2s infinite linear; 1030 | } 1031 | 1032 | .cu-load.loading::after { 1033 | content: '加载中...'; 1034 | } 1035 | 1036 | .cu-load.over::before { 1037 | content: '\e64a'; 1038 | } 1039 | 1040 | .cu-load.over::after { 1041 | content: '没有更多了'; 1042 | } 1043 | 1044 | .cu-load.erro::before { 1045 | content: '\e658'; 1046 | } 1047 | 1048 | .cu-load.erro::after { 1049 | content: '加载失败'; 1050 | } 1051 | 1052 | .cu-load.load-cuIcon::before { 1053 | font-size: 32upx; 1054 | } 1055 | 1056 | .cu-load.load-cuIcon::after { 1057 | display: none; 1058 | } 1059 | 1060 | .cu-load.load-cuIcon.over { 1061 | display: none; 1062 | } 1063 | 1064 | .cu-load.load-modal { 1065 | position: fixed; 1066 | top: 0; 1067 | right: 0; 1068 | bottom: 140upx; 1069 | left: 0; 1070 | margin: auto; 1071 | width: 260upx; 1072 | height: 260upx; 1073 | background-color: #ffffff; 1074 | border-radius: 10upx; 1075 | box-shadow: 0 0 0upx 2000upx rgba(0, 0, 0, 0.5); 1076 | display: flex; 1077 | align-items: center; 1078 | flex-direction: column; 1079 | justify-content: center; 1080 | font-size: 28upx; 1081 | z-index: 9999; 1082 | line-height: 2.4em; 1083 | } 1084 | 1085 | .cu-load.load-modal [class*='cuIcon-'] { 1086 | font-size: 60upx; 1087 | } 1088 | 1089 | .cu-load.load-modal image { 1090 | width: 70upx; 1091 | height: 70upx; 1092 | } 1093 | 1094 | .cu-load.load-modal::after { 1095 | content: ''; 1096 | position: absolute; 1097 | background-color: #ffffff; 1098 | border-radius: 50%; 1099 | width: 200upx; 1100 | height: 200upx; 1101 | font-size: 10px; 1102 | border-top: 6upx solid rgba(0, 0, 0, 0.05); 1103 | border-right: 6upx solid rgba(0, 0, 0, 0.05); 1104 | border-bottom: 6upx solid rgba(0, 0, 0, 0.05); 1105 | border-left: 6upx solid #f37b1d; 1106 | animation: cuIcon-spin 1s infinite linear; 1107 | z-index: -1; 1108 | } 1109 | 1110 | .load-progress { 1111 | pointer-events: none; 1112 | top: 0; 1113 | position: fixed; 1114 | width: 100%; 1115 | left: 0; 1116 | z-index: 2000; 1117 | } 1118 | 1119 | .load-progress.hide { 1120 | display: none; 1121 | } 1122 | 1123 | .load-progress .load-progress-bar { 1124 | position: relative; 1125 | width: 100%; 1126 | height: 4upx; 1127 | overflow: hidden; 1128 | transition: all 200ms ease 0s; 1129 | } 1130 | 1131 | .load-progress .load-progress-spinner { 1132 | position: absolute; 1133 | top: 10upx; 1134 | right: 10upx; 1135 | z-index: 2000; 1136 | display: block; 1137 | } 1138 | 1139 | .load-progress .load-progress-spinner::after { 1140 | content: ''; 1141 | display: block; 1142 | width: 24upx; 1143 | height: 24upx; 1144 | -webkit-box-sizing: border-box; 1145 | box-sizing: border-box; 1146 | border: solid 4upx transparent; 1147 | border-top-color: inherit; 1148 | border-left-color: inherit; 1149 | border-radius: 50%; 1150 | -webkit-animation: load-progress-spinner 0.4s linear infinite; 1151 | animation: load-progress-spinner 0.4s linear infinite; 1152 | } 1153 | 1154 | @-webkit-keyframes load-progress-spinner { 1155 | 0% { 1156 | -webkit-transform: rotate(0); 1157 | transform: rotate(0); 1158 | } 1159 | 1160 | 100% { 1161 | -webkit-transform: rotate(360deg); 1162 | transform: rotate(360deg); 1163 | } 1164 | } 1165 | 1166 | @keyframes load-progress-spinner { 1167 | 0% { 1168 | -webkit-transform: rotate(0); 1169 | transform: rotate(0); 1170 | } 1171 | 1172 | 100% { 1173 | -webkit-transform: rotate(360deg); 1174 | transform: rotate(360deg); 1175 | } 1176 | } 1177 | 1178 | /* ================== 1179 | 列表 1180 | ==================== */ 1181 | .grayscale { 1182 | filter: grayscale(1); 1183 | } 1184 | 1185 | .cu-list + .cu-list { 1186 | margin-top: 30upx; 1187 | } 1188 | 1189 | .cu-list > .cu-item { 1190 | transition: all 0.6s ease-in-out 0s; 1191 | transform: translateX(0upx); 1192 | } 1193 | 1194 | .cu-list > .cu-item.move-cur { 1195 | transform: translateX(-260upx); 1196 | } 1197 | 1198 | .cu-list > .cu-item .move { 1199 | position: absolute; 1200 | right: 0; 1201 | display: flex; 1202 | width: 260upx; 1203 | height: 100%; 1204 | transform: translateX(100%); 1205 | } 1206 | 1207 | .cu-list > .cu-item .move view { 1208 | display: flex; 1209 | flex: 1; 1210 | justify-content: center; 1211 | align-items: center; 1212 | } 1213 | 1214 | .cu-list.menu-avatar { 1215 | overflow: hidden; 1216 | } 1217 | 1218 | .cu-list.menu-avatar > .cu-item { 1219 | position: relative; 1220 | display: flex; 1221 | padding-right: 10upx; 1222 | height: 140upx; 1223 | background-color: #ffffff; 1224 | justify-content: flex-end; 1225 | align-items: center; 1226 | } 1227 | 1228 | .cu-list.menu-avatar > .cu-item > .cu-avatar { 1229 | position: absolute; 1230 | left: 30upx; 1231 | } 1232 | 1233 | .cu-list.menu-avatar > .cu-item .flex .text-cut { 1234 | max-width: 510upx; 1235 | } 1236 | 1237 | .cu-list.menu-avatar > .cu-item .content { 1238 | position: absolute; 1239 | left: 146upx; 1240 | width: calc(100% - 96upx - 60upx - 120upx - 20upx); 1241 | line-height: 1.6em; 1242 | } 1243 | 1244 | .cu-list.menu-avatar > .cu-item .content.flex-sub { 1245 | width: calc(100% - 96upx - 60upx - 20upx); 1246 | } 1247 | 1248 | .cu-list.menu-avatar > .cu-item .content > view:first-child { 1249 | font-size: 30upx; 1250 | display: flex; 1251 | align-items: center; 1252 | } 1253 | 1254 | .cu-list.menu-avatar > .cu-item .content .cu-tag.sm { 1255 | display: inline-block; 1256 | margin-left: 10upx; 1257 | height: 28upx; 1258 | font-size: 16upx; 1259 | line-height: 32upx; 1260 | } 1261 | 1262 | .cu-list.menu-avatar > .cu-item .action { 1263 | width: 100upx; 1264 | text-align: center; 1265 | } 1266 | 1267 | .cu-list.menu-avatar > .cu-item .action view + view { 1268 | margin-top: 10upx; 1269 | } 1270 | 1271 | .cu-list.menu-avatar.comment > .cu-item .content { 1272 | position: relative; 1273 | left: 0; 1274 | width: auto; 1275 | flex: 1; 1276 | } 1277 | 1278 | .cu-list.menu-avatar.comment > .cu-item { 1279 | padding: 30upx 30upx 30upx 120upx; 1280 | height: auto; 1281 | } 1282 | 1283 | .cu-list.menu-avatar.comment .cu-avatar { 1284 | align-self: flex-start; 1285 | } 1286 | 1287 | .cu-list.menu > .cu-item { 1288 | position: relative; 1289 | display: flex; 1290 | padding: 0 30upx; 1291 | min-height: 100upx; 1292 | background-color: #ffffff; 1293 | justify-content: space-between; 1294 | align-items: center; 1295 | } 1296 | 1297 | .cu-list.menu > .cu-item:last-child:after { 1298 | border: none; 1299 | } 1300 | 1301 | .cu-list.menu-avatar > .cu-item:after, 1302 | .cu-list.menu > .cu-item:after { 1303 | position: absolute; 1304 | top: 0; 1305 | left: 0; 1306 | box-sizing: border-box; 1307 | width: 200%; 1308 | height: 200%; 1309 | border-bottom: 1upx solid #ddd; 1310 | border-radius: inherit; 1311 | content: ' '; 1312 | transform: scale(0.5); 1313 | transform-origin: 0 0; 1314 | pointer-events: none; 1315 | } 1316 | 1317 | .cu-list.menu > .cu-item.grayscale { 1318 | background-color: #f5f5f5; 1319 | } 1320 | 1321 | .cu-list.menu > .cu-item.cur { 1322 | background-color: #fcf7e9; 1323 | } 1324 | 1325 | .cu-list.menu > .cu-item.arrow { 1326 | padding-right: 90upx; 1327 | } 1328 | 1329 | .cu-list.menu > .cu-item.arrow:before { 1330 | position: absolute; 1331 | top: 0; 1332 | right: 30upx; 1333 | bottom: 0; 1334 | display: block; 1335 | margin: auto; 1336 | width: 30upx; 1337 | height: 30upx; 1338 | color: #8799a3; 1339 | content: '\e6a3'; 1340 | text-align: center; 1341 | font-size: 34upx; 1342 | font-family: cuIcon; 1343 | line-height: 30upx; 1344 | } 1345 | 1346 | .cu-list.menu > .cu-item button.content { 1347 | padding: 0; 1348 | background-color: transparent; 1349 | justify-content: flex-start; 1350 | } 1351 | 1352 | .cu-list.menu > .cu-item button.content:after { 1353 | display: none; 1354 | } 1355 | 1356 | .cu-list.menu > .cu-item .cu-avatar-group .cu-avatar { 1357 | border-color: #ffffff; 1358 | } 1359 | 1360 | .cu-list.menu > .cu-item .content > view:first-child { 1361 | display: flex; 1362 | align-items: center; 1363 | } 1364 | 1365 | .cu-list.menu > .cu-item .content > text[class*='cuIcon'] { 1366 | display: inline-block; 1367 | margin-right: 10upx; 1368 | width: 1.6em; 1369 | text-align: center; 1370 | } 1371 | 1372 | .cu-list.menu > .cu-item .content > image { 1373 | display: inline-block; 1374 | margin-right: 10upx; 1375 | width: 1.6em; 1376 | height: 1.6em; 1377 | vertical-align: middle; 1378 | } 1379 | 1380 | .cu-list.menu > .cu-item .content { 1381 | font-size: 30upx; 1382 | line-height: 1.6em; 1383 | flex: 1; 1384 | } 1385 | 1386 | .cu-list.menu > .cu-item .content .cu-tag.sm { 1387 | display: inline-block; 1388 | margin-left: 10upx; 1389 | height: 28upx; 1390 | font-size: 16upx; 1391 | line-height: 32upx; 1392 | } 1393 | 1394 | .cu-list.menu > .cu-item .action .cu-tag:empty { 1395 | right: 10upx; 1396 | } 1397 | 1398 | .cu-list.menu { 1399 | display: block; 1400 | overflow: hidden; 1401 | } 1402 | 1403 | .cu-list.menu.sm-border > .cu-item:after { 1404 | left: 30upx; 1405 | width: calc(200% - 120upx); 1406 | } 1407 | 1408 | .cu-list.grid > .cu-item { 1409 | position: relative; 1410 | display: flex; 1411 | padding: 20upx 0 30upx; 1412 | transition-duration: 0s; 1413 | flex-direction: column; 1414 | } 1415 | 1416 | .cu-list.grid > .cu-item:after { 1417 | position: absolute; 1418 | top: 0; 1419 | left: 0; 1420 | box-sizing: border-box; 1421 | width: 200%; 1422 | height: 200%; 1423 | border-right: 1px solid rgba(0, 0, 0, 0.1); 1424 | border-bottom: 1px solid rgba(0, 0, 0, 0.1); 1425 | border-radius: inherit; 1426 | content: ' '; 1427 | transform: scale(0.5); 1428 | transform-origin: 0 0; 1429 | pointer-events: none; 1430 | } 1431 | 1432 | .cu-list.grid > .cu-item text { 1433 | display: block; 1434 | margin-top: 10upx; 1435 | color: #888; 1436 | font-size: 26upx; 1437 | line-height: 40upx; 1438 | } 1439 | 1440 | .cu-list.grid > .cu-item [class*='cuIcon'] { 1441 | position: relative; 1442 | display: block; 1443 | margin-top: 20upx; 1444 | width: 100%; 1445 | font-size: 48upx; 1446 | } 1447 | 1448 | .cu-list.grid > .cu-item .cu-tag { 1449 | right: auto; 1450 | left: 50%; 1451 | margin-left: 20upx; 1452 | } 1453 | 1454 | .cu-list.grid { 1455 | background-color: #ffffff; 1456 | text-align: center; 1457 | } 1458 | 1459 | .cu-list.grid.no-border > .cu-item { 1460 | padding-top: 10upx; 1461 | padding-bottom: 20upx; 1462 | } 1463 | 1464 | .cu-list.grid.no-border > .cu-item:after { 1465 | border: none; 1466 | } 1467 | 1468 | .cu-list.grid.no-border { 1469 | padding: 20upx 10upx; 1470 | } 1471 | 1472 | .cu-list.grid.col-3 > .cu-item:nth-child(3n):after, 1473 | .cu-list.grid.col-4 > .cu-item:nth-child(4n):after, 1474 | .cu-list.grid.col-5 > .cu-item:nth-child(5n):after { 1475 | border-right-width: 0; 1476 | } 1477 | 1478 | .cu-list.card-menu { 1479 | overflow: hidden; 1480 | margin-right: 30upx; 1481 | margin-left: 30upx; 1482 | border-radius: 20upx; 1483 | } 1484 | 1485 | /* ================== 1486 | 操作条 1487 | ==================== */ 1488 | 1489 | .cu-bar { 1490 | display: flex; 1491 | position: relative; 1492 | align-items: center; 1493 | min-height: 100upx; 1494 | justify-content: space-between; 1495 | } 1496 | 1497 | .cu-bar .action { 1498 | display: flex; 1499 | align-items: center; 1500 | height: 100%; 1501 | justify-content: center; 1502 | max-width: 100%; 1503 | } 1504 | 1505 | .cu-bar .action.border-title { 1506 | position: relative; 1507 | top: -10upx; 1508 | } 1509 | 1510 | .cu-bar .action.border-title text[class*='bg-']:last-child { 1511 | position: absolute; 1512 | bottom: -0.5rem; 1513 | min-width: 2rem; 1514 | height: 6upx; 1515 | left: 0; 1516 | } 1517 | 1518 | .cu-bar .action.sub-title { 1519 | position: relative; 1520 | top: -0.2rem; 1521 | } 1522 | 1523 | .cu-bar .action.sub-title text { 1524 | position: relative; 1525 | z-index: 1; 1526 | } 1527 | 1528 | .cu-bar .action.sub-title text[class*='bg-']:last-child { 1529 | position: absolute; 1530 | display: inline-block; 1531 | bottom: -0.2rem; 1532 | border-radius: 6upx; 1533 | width: 100%; 1534 | height: 0.6rem; 1535 | left: 0.6rem; 1536 | opacity: 0.3; 1537 | z-index: 0; 1538 | } 1539 | 1540 | .cu-bar .action.sub-title text[class*='text-']:last-child { 1541 | position: absolute; 1542 | display: inline-block; 1543 | bottom: -0.7rem; 1544 | left: 0.5rem; 1545 | opacity: 0.2; 1546 | z-index: 0; 1547 | text-align: right; 1548 | font-weight: 900; 1549 | font-size: 36upx; 1550 | } 1551 | 1552 | .cu-bar.justify-center .action.border-title text:last-child, 1553 | .cu-bar.justify-center .action.sub-title text:last-child { 1554 | left: 0; 1555 | right: 0; 1556 | margin: auto; 1557 | text-align: center; 1558 | } 1559 | 1560 | .cu-bar .action:first-child { 1561 | margin-left: 30upx; 1562 | font-size: 30upx; 1563 | } 1564 | 1565 | .cu-bar .action text.text-cut { 1566 | text-align: left; 1567 | width: 100%; 1568 | } 1569 | 1570 | .cu-bar .cu-avatar:first-child { 1571 | margin-left: 20upx; 1572 | } 1573 | 1574 | .cu-bar .action:first-child > text[class*='cuIcon-'] { 1575 | margin-left: -0.3em; 1576 | margin-right: 0.3em; 1577 | } 1578 | 1579 | .cu-bar .action:last-child { 1580 | margin-right: 30upx; 1581 | } 1582 | 1583 | .cu-bar .action > text[class*='cuIcon-'], 1584 | .cu-bar .action > view[class*='cuIcon-'] { 1585 | font-size: 36upx; 1586 | } 1587 | 1588 | .cu-bar .action > text[class*='cuIcon-'] + text[class*='cuIcon-'] { 1589 | margin-left: 0.5em; 1590 | } 1591 | 1592 | .cu-bar .content { 1593 | position: absolute; 1594 | text-align: center; 1595 | width: calc(100% - 340upx); 1596 | left: 0; 1597 | right: 0; 1598 | bottom: 0; 1599 | top: 0; 1600 | margin: auto; 1601 | height: 60upx; 1602 | font-size: 32upx; 1603 | line-height: 60upx; 1604 | cursor: none; 1605 | pointer-events: none; 1606 | text-overflow: ellipsis; 1607 | white-space: nowrap; 1608 | overflow: hidden; 1609 | } 1610 | 1611 | .cu-bar.ios .content { 1612 | bottom: 7px; 1613 | height: 30px; 1614 | font-size: 32upx; 1615 | line-height: 30px; 1616 | } 1617 | 1618 | .cu-bar.btn-group { 1619 | justify-content: space-around; 1620 | } 1621 | 1622 | .cu-bar.btn-group button { 1623 | padding: 20upx 32upx; 1624 | } 1625 | 1626 | .cu-bar.btn-group button { 1627 | flex: 1; 1628 | margin: 0 20upx; 1629 | max-width: 50%; 1630 | } 1631 | 1632 | .cu-bar .search-form { 1633 | background-color: #f5f5f5; 1634 | line-height: 64upx; 1635 | height: 64upx; 1636 | font-size: 24upx; 1637 | color: #333333; 1638 | flex: 1; 1639 | display: flex; 1640 | align-items: center; 1641 | margin: 0 30upx; 1642 | } 1643 | 1644 | .cu-bar .search-form + .action { 1645 | margin-right: 30upx; 1646 | } 1647 | 1648 | .cu-bar .search-form input { 1649 | flex: 1; 1650 | padding-right: 30upx; 1651 | height: 64upx; 1652 | line-height: 64upx; 1653 | font-size: 26upx; 1654 | background-color: transparent; 1655 | } 1656 | 1657 | .cu-bar .search-form [class*='cuIcon-'] { 1658 | margin: 0 0.5em 0 0.8em; 1659 | } 1660 | 1661 | .cu-bar .search-form [class*='cuIcon-']::before { 1662 | top: 0upx; 1663 | } 1664 | 1665 | .cu-bar.fixed, 1666 | .nav.fixed { 1667 | position: fixed; 1668 | width: 100%; 1669 | top: 0; 1670 | z-index: 1024; 1671 | box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1); 1672 | } 1673 | 1674 | .cu-bar.foot { 1675 | position: fixed; 1676 | width: 100%; 1677 | bottom: 0; 1678 | z-index: 1024; 1679 | box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1); 1680 | } 1681 | 1682 | .cu-bar.tabbar { 1683 | padding: 0; 1684 | height: calc(100upx + env(safe-area-inset-bottom) / 2); 1685 | padding-bottom: calc(env(safe-area-inset-bottom) / 2); 1686 | } 1687 | 1688 | .cu-tabbar-height { 1689 | min-height: 100upx; 1690 | height: calc(100upx + env(safe-area-inset-bottom) / 2); 1691 | } 1692 | 1693 | .cu-bar.tabbar.shadow { 1694 | box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1); 1695 | } 1696 | 1697 | .cu-bar.tabbar .action { 1698 | font-size: 22upx; 1699 | position: relative; 1700 | flex: 1; 1701 | text-align: center; 1702 | padding: 0; 1703 | display: block; 1704 | height: auto; 1705 | line-height: 1; 1706 | margin: 0; 1707 | background-color: inherit; 1708 | overflow: initial; 1709 | } 1710 | 1711 | .cu-bar.tabbar.shop .action { 1712 | width: 140upx; 1713 | flex: initial; 1714 | } 1715 | 1716 | .cu-bar.tabbar .action.add-action { 1717 | position: relative; 1718 | z-index: 2; 1719 | padding-top: 50upx; 1720 | } 1721 | 1722 | .cu-bar.tabbar .action.add-action [class*='cuIcon-'] { 1723 | position: absolute; 1724 | width: 70upx; 1725 | z-index: 2; 1726 | height: 70upx; 1727 | border-radius: 50%; 1728 | line-height: 70upx; 1729 | font-size: 50upx; 1730 | top: -35upx; 1731 | left: 0; 1732 | right: 0; 1733 | margin: auto; 1734 | padding: 0; 1735 | } 1736 | 1737 | .cu-bar.tabbar .action.add-action::after { 1738 | content: ''; 1739 | position: absolute; 1740 | width: 100upx; 1741 | height: 100upx; 1742 | top: -50upx; 1743 | left: 0; 1744 | right: 0; 1745 | margin: auto; 1746 | box-shadow: 0 -3upx 8upx rgba(0, 0, 0, 0.08); 1747 | border-radius: 50upx; 1748 | background-color: inherit; 1749 | z-index: 0; 1750 | } 1751 | 1752 | .cu-bar.tabbar .action.add-action::before { 1753 | content: ''; 1754 | position: absolute; 1755 | width: 100upx; 1756 | height: 30upx; 1757 | bottom: 30upx; 1758 | left: 0; 1759 | right: 0; 1760 | margin: auto; 1761 | background-color: inherit; 1762 | z-index: 1; 1763 | } 1764 | 1765 | .cu-bar.tabbar .btn-group { 1766 | flex: 1; 1767 | display: flex; 1768 | justify-content: space-around; 1769 | align-items: center; 1770 | padding: 0 10upx; 1771 | } 1772 | 1773 | .cu-bar.tabbar button.action::after { 1774 | border: 0; 1775 | } 1776 | 1777 | .cu-bar.tabbar .action [class*='cuIcon-'] { 1778 | width: 100upx; 1779 | position: relative; 1780 | display: block; 1781 | height: auto; 1782 | margin: 0 auto 10upx; 1783 | text-align: center; 1784 | font-size: 40upx; 1785 | } 1786 | 1787 | .cu-bar.tabbar .action .cuIcon-cu-image { 1788 | margin: 0 auto; 1789 | } 1790 | 1791 | .cu-bar.tabbar .action .cuIcon-cu-image image { 1792 | width: 50upx; 1793 | height: 50upx; 1794 | display: inline-block; 1795 | } 1796 | 1797 | .cu-bar.tabbar .submit { 1798 | align-items: center; 1799 | display: flex; 1800 | justify-content: center; 1801 | text-align: center; 1802 | position: relative; 1803 | flex: 2; 1804 | align-self: stretch; 1805 | } 1806 | 1807 | .cu-bar.tabbar .submit:last-child { 1808 | flex: 2.6; 1809 | } 1810 | 1811 | .cu-bar.tabbar .submit + .submit { 1812 | flex: 2; 1813 | } 1814 | 1815 | .cu-bar.tabbar.border .action::before { 1816 | content: ' '; 1817 | width: 200%; 1818 | height: 200%; 1819 | position: absolute; 1820 | top: 0; 1821 | left: 0; 1822 | transform: scale(0.5); 1823 | transform-origin: 0 0; 1824 | border-right: 1upx solid rgba(0, 0, 0, 0.1); 1825 | z-index: 3; 1826 | } 1827 | 1828 | .cu-bar.tabbar.border .action:last-child:before { 1829 | display: none; 1830 | } 1831 | 1832 | .cu-bar.input { 1833 | padding-right: 20upx; 1834 | background-color: #ffffff; 1835 | } 1836 | 1837 | .cu-bar.input input { 1838 | overflow: initial; 1839 | line-height: 64upx; 1840 | height: 64upx; 1841 | min-height: 64upx; 1842 | flex: 1; 1843 | font-size: 30upx; 1844 | margin: 0 20upx; 1845 | } 1846 | 1847 | .cu-bar.input .action { 1848 | margin-left: 20upx; 1849 | } 1850 | 1851 | .cu-bar.input .action [class*='cuIcon-'] { 1852 | font-size: 48upx; 1853 | } 1854 | 1855 | .cu-bar.input input + .action { 1856 | margin-right: 20upx; 1857 | margin-left: 0upx; 1858 | } 1859 | 1860 | .cu-bar.input .action:first-child [class*='cuIcon-'] { 1861 | margin-left: 0upx; 1862 | } 1863 | 1864 | .cu-custom { 1865 | display: block; 1866 | position: relative; 1867 | } 1868 | 1869 | .cu-custom .cu-bar .content { 1870 | width: calc(100% - 440upx); 1871 | } 1872 | 1873 | /* #ifdef MP-ALIPAY */ 1874 | .cu-custom .cu-bar .action .cuIcon-back { 1875 | opacity: 0; 1876 | } 1877 | 1878 | /* #endif */ 1879 | 1880 | .cu-custom .cu-bar .content image { 1881 | height: 60upx; 1882 | width: 240upx; 1883 | } 1884 | 1885 | .cu-custom .cu-bar { 1886 | min-height: 0px; 1887 | /* #ifdef MP-WEIXIN */ 1888 | padding-right: 220upx; 1889 | /* #endif */ 1890 | /* #ifdef MP-ALIPAY */ 1891 | padding-right: 150upx; 1892 | /* #endif */ 1893 | box-shadow: 0upx 0upx 0upx; 1894 | z-index: 9999; 1895 | } 1896 | 1897 | .cu-custom .cu-bar .border-custom { 1898 | position: relative; 1899 | background: rgba(0, 0, 0, 0.15); 1900 | border-radius: 1000upx; 1901 | height: 30px; 1902 | } 1903 | 1904 | .cu-custom .cu-bar .border-custom::after { 1905 | content: ' '; 1906 | width: 200%; 1907 | height: 200%; 1908 | position: absolute; 1909 | top: 0; 1910 | left: 0; 1911 | border-radius: inherit; 1912 | transform: scale(0.5); 1913 | transform-origin: 0 0; 1914 | pointer-events: none; 1915 | box-sizing: border-box; 1916 | border: 1upx solid #ffffff; 1917 | opacity: 0.5; 1918 | } 1919 | 1920 | .cu-custom .cu-bar .border-custom::before { 1921 | content: ' '; 1922 | width: 1upx; 1923 | height: 110%; 1924 | position: absolute; 1925 | top: 22.5%; 1926 | left: 0; 1927 | right: 0; 1928 | margin: auto; 1929 | transform: scale(0.5); 1930 | transform-origin: 0 0; 1931 | pointer-events: none; 1932 | box-sizing: border-box; 1933 | opacity: 0.6; 1934 | background-color: #ffffff; 1935 | } 1936 | 1937 | .cu-custom .cu-bar .border-custom text { 1938 | display: block; 1939 | flex: 1; 1940 | margin: auto !important; 1941 | text-align: center; 1942 | font-size: 34upx; 1943 | } 1944 | 1945 | /* ================== 1946 | 导航栏 1947 | ==================== */ 1948 | 1949 | .nav { 1950 | white-space: nowrap; 1951 | } 1952 | 1953 | ::-webkit-scrollbar { 1954 | display: none; 1955 | } 1956 | 1957 | .nav .cu-item { 1958 | height: 90upx; 1959 | display: inline-block; 1960 | line-height: 90upx; 1961 | margin: 0 10upx; 1962 | padding: 0 20upx; 1963 | } 1964 | 1965 | .nav .cu-item.cur { 1966 | border-bottom: 4upx solid; 1967 | } 1968 | 1969 | /* ================== 1970 | 时间轴 1971 | ==================== */ 1972 | 1973 | .cu-timeline { 1974 | display: block; 1975 | background-color: #ffffff; 1976 | } 1977 | 1978 | .cu-timeline .cu-time { 1979 | width: 120upx; 1980 | text-align: center; 1981 | padding: 20upx 0; 1982 | font-size: 26upx; 1983 | color: #888; 1984 | display: block; 1985 | } 1986 | 1987 | .cu-timeline > .cu-item { 1988 | padding: 30upx 30upx 30upx 120upx; 1989 | position: relative; 1990 | display: block; 1991 | z-index: 0; 1992 | } 1993 | 1994 | .cu-timeline > .cu-item:not([class*='text-']) { 1995 | color: #ccc; 1996 | } 1997 | 1998 | .cu-timeline > .cu-item::after { 1999 | content: ''; 2000 | display: block; 2001 | position: absolute; 2002 | width: 1upx; 2003 | background-color: #ddd; 2004 | left: 60upx; 2005 | height: 100%; 2006 | top: 0; 2007 | z-index: 8; 2008 | } 2009 | 2010 | .cu-timeline > .cu-item::before { 2011 | font-family: 'cuIcon'; 2012 | display: block; 2013 | position: absolute; 2014 | top: 36upx; 2015 | z-index: 9; 2016 | background-color: #ffffff; 2017 | width: 50upx; 2018 | height: 50upx; 2019 | text-align: center; 2020 | border: none; 2021 | line-height: 50upx; 2022 | left: 36upx; 2023 | } 2024 | 2025 | .cu-timeline > .cu-item:not([class*='cuIcon-'])::before { 2026 | content: '\e763'; 2027 | } 2028 | 2029 | .cu-timeline > .cu-item[class*='cuIcon-']::before { 2030 | background-color: #ffffff; 2031 | width: 50upx; 2032 | height: 50upx; 2033 | text-align: center; 2034 | border: none; 2035 | line-height: 50upx; 2036 | left: 36upx; 2037 | } 2038 | 2039 | .cu-timeline > .cu-item > .content { 2040 | padding: 30upx; 2041 | border-radius: 6upx; 2042 | display: block; 2043 | line-height: 1.6; 2044 | } 2045 | 2046 | .cu-timeline > .cu-item > .content:not([class*='bg-']) { 2047 | background-color: #f1f1f1; 2048 | color: #333333; 2049 | } 2050 | 2051 | .cu-timeline > .cu-item > .content + .content { 2052 | margin-top: 20upx; 2053 | } 2054 | 2055 | /* ================== 2056 | 聊天 2057 | ==================== */ 2058 | 2059 | .cu-chat { 2060 | display: flex; 2061 | flex-direction: column; 2062 | } 2063 | 2064 | .cu-chat .cu-item { 2065 | display: flex; 2066 | padding: 30upx 30upx 70upx; 2067 | position: relative; 2068 | } 2069 | 2070 | .cu-chat .cu-item > .cu-avatar { 2071 | width: 80upx; 2072 | height: 80upx; 2073 | } 2074 | 2075 | .cu-chat .cu-item > .main { 2076 | max-width: calc(100% - 260upx); 2077 | margin: 0 40upx; 2078 | display: flex; 2079 | align-items: center; 2080 | } 2081 | 2082 | .cu-chat .cu-item > image { 2083 | height: 320upx; 2084 | } 2085 | 2086 | .cu-chat .cu-item > .main .content { 2087 | padding: 20upx; 2088 | border-radius: 6upx; 2089 | display: inline-flex; 2090 | max-width: 100%; 2091 | align-items: center; 2092 | font-size: 30upx; 2093 | position: relative; 2094 | min-height: 80upx; 2095 | line-height: 40upx; 2096 | text-align: left; 2097 | } 2098 | 2099 | .cu-chat .cu-item > .main .content:not([class*='bg-']) { 2100 | background-color: #ffffff; 2101 | color: #333333; 2102 | } 2103 | 2104 | .cu-chat .cu-item .date { 2105 | position: absolute; 2106 | font-size: 24upx; 2107 | color: #8799a3; 2108 | width: calc(100% - 320upx); 2109 | bottom: 20upx; 2110 | left: 160upx; 2111 | } 2112 | 2113 | .cu-chat .cu-item .action { 2114 | padding: 0 30upx; 2115 | display: flex; 2116 | align-items: center; 2117 | } 2118 | 2119 | .cu-chat .cu-item > .main .content::after { 2120 | content: ''; 2121 | top: 27upx; 2122 | transform: rotate(45deg); 2123 | position: absolute; 2124 | z-index: 100; 2125 | display: inline-block; 2126 | overflow: hidden; 2127 | width: 24upx; 2128 | height: 24upx; 2129 | left: -12upx; 2130 | right: initial; 2131 | background-color: inherit; 2132 | } 2133 | 2134 | .cu-chat .cu-item.self > .main .content::after { 2135 | left: auto; 2136 | right: -12upx; 2137 | } 2138 | 2139 | .cu-chat .cu-item > .main .content::before { 2140 | content: ''; 2141 | top: 30upx; 2142 | transform: rotate(45deg); 2143 | position: absolute; 2144 | z-index: -1; 2145 | display: inline-block; 2146 | overflow: hidden; 2147 | width: 24upx; 2148 | height: 24upx; 2149 | left: -12upx; 2150 | right: initial; 2151 | background-color: inherit; 2152 | filter: blur(5upx); 2153 | opacity: 0.3; 2154 | } 2155 | 2156 | .cu-chat .cu-item > .main .content:not([class*='bg-'])::before { 2157 | background-color: #333333; 2158 | opacity: 0.1; 2159 | } 2160 | 2161 | .cu-chat .cu-item.self > .main .content::before { 2162 | left: auto; 2163 | right: -12upx; 2164 | } 2165 | 2166 | .cu-chat .cu-item.self { 2167 | justify-content: flex-end; 2168 | text-align: right; 2169 | } 2170 | 2171 | .cu-chat .cu-info { 2172 | display: inline-block; 2173 | margin: 20upx auto; 2174 | font-size: 24upx; 2175 | padding: 8upx 12upx; 2176 | background-color: rgba(0, 0, 0, 0.2); 2177 | border-radius: 6upx; 2178 | color: #ffffff; 2179 | max-width: 400upx; 2180 | line-height: 1.4; 2181 | } 2182 | 2183 | /* ================== 2184 | 卡片 2185 | ==================== */ 2186 | 2187 | .cu-card { 2188 | display: block; 2189 | overflow: hidden; 2190 | } 2191 | 2192 | .cu-card > .cu-item { 2193 | display: block; 2194 | background-color: #ffffff; 2195 | overflow: hidden; 2196 | border-radius: 10upx; 2197 | margin: 30upx; 2198 | } 2199 | 2200 | .cu-card > .cu-item.shadow-blur { 2201 | overflow: initial; 2202 | } 2203 | 2204 | .cu-card.no-card > .cu-item { 2205 | margin: 0upx; 2206 | border-radius: 0upx; 2207 | } 2208 | 2209 | .cu-card .grid.grid-square { 2210 | margin-bottom: -20upx; 2211 | } 2212 | 2213 | .cu-card.case .image { 2214 | position: relative; 2215 | } 2216 | 2217 | .cu-card.case .image image { 2218 | width: 100%; 2219 | } 2220 | 2221 | .cu-card.case .image .cu-tag { 2222 | position: absolute; 2223 | right: 0; 2224 | top: 0; 2225 | } 2226 | 2227 | .cu-card.case .image .cu-bar { 2228 | position: absolute; 2229 | bottom: 0; 2230 | width: 100%; 2231 | background-color: transparent; 2232 | padding: 0upx 30upx; 2233 | } 2234 | 2235 | .cu-card.case.no-card .image { 2236 | margin: 30upx 30upx 0; 2237 | overflow: hidden; 2238 | border-radius: 10upx; 2239 | } 2240 | 2241 | .cu-card.dynamic { 2242 | display: block; 2243 | } 2244 | 2245 | .cu-card.dynamic > .cu-item { 2246 | display: block; 2247 | background-color: #ffffff; 2248 | overflow: hidden; 2249 | } 2250 | 2251 | .cu-card.dynamic > .cu-item > .text-content { 2252 | padding: 0 30upx 0; 2253 | max-height: 6.4em; 2254 | overflow: hidden; 2255 | font-size: 30upx; 2256 | margin-bottom: 20upx; 2257 | } 2258 | 2259 | .cu-card.dynamic > .cu-item .square-img { 2260 | width: 100%; 2261 | height: 200upx; 2262 | border-radius: 6upx; 2263 | } 2264 | 2265 | .cu-card.dynamic > .cu-item .only-img { 2266 | width: 100%; 2267 | height: 320upx; 2268 | border-radius: 6upx; 2269 | } 2270 | 2271 | /* card.dynamic>.cu-item .comment { 2272 | padding: 20upx; 2273 | background-color: #f1f1f1; 2274 | margin: 0 30upx 30upx; 2275 | border-radius: 6upx; 2276 | } */ 2277 | 2278 | .cu-card.article { 2279 | display: block; 2280 | } 2281 | 2282 | .cu-card.article > .cu-item { 2283 | padding-bottom: 30upx; 2284 | } 2285 | 2286 | .cu-card.article > .cu-item .title { 2287 | font-size: 30upx; 2288 | font-weight: 900; 2289 | color: #333333; 2290 | line-height: 100upx; 2291 | padding: 0 30upx; 2292 | } 2293 | 2294 | .cu-card.article > .cu-item .content { 2295 | display: flex; 2296 | padding: 0 30upx; 2297 | } 2298 | 2299 | .cu-card.article > .cu-item .content > image { 2300 | width: 240upx; 2301 | height: 6.4em; 2302 | margin-right: 20upx; 2303 | border-radius: 6upx; 2304 | } 2305 | 2306 | .cu-card.article > .cu-item .content .desc { 2307 | flex: 1; 2308 | display: flex; 2309 | flex-direction: column; 2310 | justify-content: space-between; 2311 | } 2312 | 2313 | .cu-card.article > .cu-item .content .text-content { 2314 | font-size: 28upx; 2315 | color: #888; 2316 | height: 4.8em; 2317 | overflow: hidden; 2318 | } 2319 | 2320 | /* ================== 2321 | 表单 2322 | ==================== */ 2323 | 2324 | .cu-form-group { 2325 | background-color: #ffffff; 2326 | padding: 1upx 30upx; 2327 | display: flex; 2328 | align-items: center; 2329 | min-height: 100upx; 2330 | justify-content: space-between; 2331 | } 2332 | 2333 | .cu-form-group + .cu-form-group { 2334 | border-top: 1upx solid #eee; 2335 | } 2336 | 2337 | .cu-form-group .title { 2338 | text-align: justify; 2339 | padding-right: 30upx; 2340 | font-size: 30upx; 2341 | position: relative; 2342 | height: 60upx; 2343 | line-height: 60upx; 2344 | } 2345 | 2346 | .cu-form-group input { 2347 | flex: 1; 2348 | font-size: 30upx; 2349 | color: #555; 2350 | padding-right: 20upx; 2351 | } 2352 | 2353 | .cu-form-group > text[class*='cuIcon-'] { 2354 | font-size: 36upx; 2355 | padding: 0; 2356 | box-sizing: border-box; 2357 | } 2358 | 2359 | .cu-form-group textarea { 2360 | margin: 32upx 0 30upx; 2361 | height: 4.6em; 2362 | width: 100%; 2363 | line-height: 1.2em; 2364 | flex: 1; 2365 | font-size: 28upx; 2366 | padding: 0; 2367 | } 2368 | 2369 | .cu-form-group.align-start .title { 2370 | height: 1em; 2371 | margin-top: 32upx; 2372 | line-height: 1em; 2373 | } 2374 | 2375 | .cu-form-group picker { 2376 | flex: 1; 2377 | padding-right: 40upx; 2378 | overflow: hidden; 2379 | position: relative; 2380 | } 2381 | 2382 | .cu-form-group picker .picker { 2383 | line-height: 100upx; 2384 | font-size: 28upx; 2385 | text-overflow: ellipsis; 2386 | white-space: nowrap; 2387 | overflow: hidden; 2388 | width: 100%; 2389 | text-align: right; 2390 | } 2391 | 2392 | .cu-form-group picker::after { 2393 | font-family: cuIcon; 2394 | display: block; 2395 | content: '\e6a3'; 2396 | position: absolute; 2397 | font-size: 34upx; 2398 | color: #8799a3; 2399 | line-height: 100upx; 2400 | width: 60upx; 2401 | text-align: center; 2402 | top: 0; 2403 | bottom: 0; 2404 | right: -20upx; 2405 | margin: auto; 2406 | } 2407 | 2408 | .cu-form-group textarea[disabled], 2409 | .cu-form-group textarea[disabled] .placeholder { 2410 | color: transparent; 2411 | } 2412 | 2413 | /* ================== 2414 | 模态窗口 2415 | ==================== */ 2416 | 2417 | .cu-modal { 2418 | position: fixed; 2419 | top: 0; 2420 | right: 0; 2421 | bottom: 0; 2422 | left: 0; 2423 | z-index: 1110; 2424 | opacity: 0; 2425 | outline: 0; 2426 | text-align: center; 2427 | -ms-transform: scale(1.185); 2428 | transform: scale(1.185); 2429 | backface-visibility: hidden; 2430 | perspective: 2000upx; 2431 | background: rgba(0, 0, 0, 0.6); 2432 | transition: all 0.3s ease-in-out 0s; 2433 | pointer-events: none; 2434 | } 2435 | 2436 | .cu-modal::before { 2437 | content: '\200B'; 2438 | display: inline-block; 2439 | height: 100%; 2440 | vertical-align: middle; 2441 | } 2442 | 2443 | .cu-modal.show { 2444 | opacity: 1; 2445 | transition-duration: 0.3s; 2446 | -ms-transform: scale(1); 2447 | transform: scale(1); 2448 | overflow-x: hidden; 2449 | overflow-y: auto; 2450 | pointer-events: auto; 2451 | } 2452 | 2453 | .cu-dialog { 2454 | position: relative; 2455 | display: inline-block; 2456 | vertical-align: middle; 2457 | margin-left: auto; 2458 | margin-right: auto; 2459 | width: 680upx; 2460 | max-width: 100%; 2461 | background-color: #f8f8f8; 2462 | border-radius: 10upx; 2463 | overflow: hidden; 2464 | } 2465 | 2466 | .cu-modal.bottom-modal::before { 2467 | vertical-align: bottom; 2468 | } 2469 | 2470 | .cu-modal.bottom-modal .cu-dialog { 2471 | width: 100%; 2472 | border-radius: 0; 2473 | } 2474 | 2475 | .cu-modal.bottom-modal { 2476 | margin-bottom: -1000upx; 2477 | } 2478 | 2479 | .cu-modal.bottom-modal.show { 2480 | margin-bottom: 0; 2481 | } 2482 | 2483 | .cu-modal.drawer-modal { 2484 | transform: scale(1); 2485 | display: flex; 2486 | } 2487 | 2488 | .cu-modal.drawer-modal .cu-dialog { 2489 | height: 100%; 2490 | min-width: 200upx; 2491 | border-radius: 0; 2492 | margin: initial; 2493 | transition-duration: 0.3s; 2494 | } 2495 | 2496 | .cu-modal.drawer-modal.justify-start .cu-dialog { 2497 | transform: translateX(-100%); 2498 | } 2499 | 2500 | .cu-modal.drawer-modal.justify-end .cu-dialog { 2501 | transform: translateX(100%); 2502 | } 2503 | 2504 | .cu-modal.drawer-modal.show .cu-dialog { 2505 | transform: translateX(0%); 2506 | } 2507 | .cu-modal .cu-dialog > .cu-bar:first-child .action { 2508 | min-width: 100rpx; 2509 | margin-right: 0; 2510 | min-height: 100rpx; 2511 | } 2512 | /* ================== 2513 | 轮播 2514 | ==================== */ 2515 | swiper .a-swiper-dot { 2516 | display: inline-block; 2517 | width: 16upx; 2518 | height: 16upx; 2519 | background: rgba(0, 0, 0, 0.3); 2520 | border-radius: 50%; 2521 | vertical-align: middle; 2522 | } 2523 | 2524 | swiper[class*='-dot'] .wx-swiper-dots, 2525 | swiper[class*='-dot'] .a-swiper-dots, 2526 | swiper[class*='-dot'] .uni-swiper-dots { 2527 | display: flex; 2528 | align-items: center; 2529 | width: 100%; 2530 | justify-content: center; 2531 | } 2532 | 2533 | swiper.square-dot .wx-swiper-dot, 2534 | swiper.square-dot .a-swiper-dot, 2535 | swiper.square-dot .uni-swiper-dot { 2536 | background-color: #ffffff; 2537 | opacity: 0.4; 2538 | width: 10upx; 2539 | height: 10upx; 2540 | border-radius: 20upx; 2541 | margin: 0 8upx !important; 2542 | } 2543 | 2544 | swiper.square-dot .wx-swiper-dot.wx-swiper-dot-active, 2545 | swiper.square-dot .a-swiper-dot.a-swiper-dot-active, 2546 | swiper.square-dot .uni-swiper-dot.uni-swiper-dot-active { 2547 | opacity: 1; 2548 | width: 30upx; 2549 | } 2550 | 2551 | swiper.round-dot .wx-swiper-dot, 2552 | swiper.round-dot .a-swiper-dot, 2553 | swiper.round-dot .uni-swiper-dot { 2554 | width: 10upx; 2555 | height: 10upx; 2556 | position: relative; 2557 | margin: 4upx 8upx !important; 2558 | } 2559 | 2560 | swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active::after, 2561 | swiper.round-dot .a-swiper-dot.a-swiper-dot-active::after, 2562 | swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active::after { 2563 | content: ''; 2564 | position: absolute; 2565 | width: 10upx; 2566 | height: 10upx; 2567 | top: 0upx; 2568 | left: 0upx; 2569 | right: 0; 2570 | bottom: 0; 2571 | margin: auto; 2572 | background-color: #ffffff; 2573 | border-radius: 20upx; 2574 | } 2575 | 2576 | swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active, 2577 | swiper.round-dot .a-swiper-dot.a-swiper-dot-active, 2578 | swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active { 2579 | width: 18upx; 2580 | height: 18upx; 2581 | } 2582 | 2583 | .screen-swiper { 2584 | min-height: 375upx; 2585 | } 2586 | 2587 | .screen-swiper image, 2588 | .screen-swiper video, 2589 | .swiper-item image, 2590 | .swiper-item video { 2591 | width: 100%; 2592 | display: block; 2593 | height: 100%; 2594 | margin: 0; 2595 | pointer-events: none; 2596 | } 2597 | 2598 | .card-swiper { 2599 | height: 420upx !important; 2600 | } 2601 | 2602 | .card-swiper swiper-item { 2603 | width: 610upx !important; 2604 | left: 70upx; 2605 | box-sizing: border-box; 2606 | padding: 40upx 0upx 70upx; 2607 | overflow: initial; 2608 | } 2609 | 2610 | .card-swiper swiper-item .swiper-item { 2611 | width: 100%; 2612 | display: block; 2613 | height: 100%; 2614 | border-radius: 10upx; 2615 | transform: scale(0.9); 2616 | transition: all 0.2s ease-in 0s; 2617 | overflow: hidden; 2618 | } 2619 | 2620 | .card-swiper swiper-item.cur .swiper-item { 2621 | transform: none; 2622 | transition: all 0.2s ease-in 0s; 2623 | } 2624 | 2625 | .tower-swiper { 2626 | height: 420upx; 2627 | position: relative; 2628 | max-width: 750upx; 2629 | overflow: hidden; 2630 | } 2631 | 2632 | .tower-swiper .tower-item { 2633 | position: absolute; 2634 | width: 300upx; 2635 | height: 380upx; 2636 | top: 0; 2637 | bottom: 0; 2638 | left: 50%; 2639 | margin: auto; 2640 | transition: all 0.2s ease-in 0s; 2641 | opacity: 1; 2642 | } 2643 | 2644 | .tower-swiper .tower-item.none { 2645 | opacity: 0; 2646 | } 2647 | 2648 | .tower-swiper .tower-item .swiper-item { 2649 | width: 100%; 2650 | height: 100%; 2651 | border-radius: 6upx; 2652 | overflow: hidden; 2653 | } 2654 | 2655 | /* ================== 2656 | 步骤条 2657 | ==================== */ 2658 | 2659 | .cu-steps { 2660 | display: flex; 2661 | } 2662 | 2663 | scroll-view.cu-steps { 2664 | display: block; 2665 | white-space: nowrap; 2666 | } 2667 | 2668 | scroll-view.cu-steps .cu-item { 2669 | display: inline-block; 2670 | } 2671 | 2672 | .cu-steps .cu-item { 2673 | flex: 1; 2674 | text-align: center; 2675 | position: relative; 2676 | min-width: 100upx; 2677 | } 2678 | 2679 | .cu-steps .cu-item:not([class*='text-']) { 2680 | color: #8799a3; 2681 | } 2682 | 2683 | .cu-steps .cu-item [class*='cuIcon-'], 2684 | .cu-steps .cu-item .num { 2685 | display: block; 2686 | font-size: 40upx; 2687 | line-height: 80upx; 2688 | } 2689 | 2690 | .cu-steps .cu-item::before, 2691 | .cu-steps .cu-item::after, 2692 | .cu-steps.steps-arrow .cu-item::before, 2693 | .cu-steps.steps-arrow .cu-item::after { 2694 | content: ''; 2695 | display: block; 2696 | position: absolute; 2697 | height: 0px; 2698 | width: calc(100% - 80upx); 2699 | border-bottom: 1px solid #ccc; 2700 | left: calc(0px - (100% - 80upx) / 2); 2701 | top: 40upx; 2702 | z-index: 0; 2703 | } 2704 | 2705 | .cu-steps.steps-arrow .cu-item::before, 2706 | .cu-steps.steps-arrow .cu-item::after { 2707 | content: '\e6a3'; 2708 | font-family: 'cuIcon'; 2709 | height: 30upx; 2710 | border-bottom-width: 0px; 2711 | line-height: 30upx; 2712 | top: 0; 2713 | bottom: 0; 2714 | margin: auto; 2715 | color: #ccc; 2716 | } 2717 | 2718 | .cu-steps.steps-bottom .cu-item::before, 2719 | .cu-steps.steps-bottom .cu-item::after { 2720 | bottom: 40upx; 2721 | top: initial; 2722 | } 2723 | 2724 | .cu-steps .cu-item::after { 2725 | border-bottom: 1px solid currentColor; 2726 | width: 0px; 2727 | transition: all 0.3s ease-in-out 0s; 2728 | } 2729 | 2730 | .cu-steps .cu-item[class*='text-']::after { 2731 | width: calc(100% - 80upx); 2732 | color: currentColor; 2733 | } 2734 | 2735 | .cu-steps .cu-item:first-child::before, 2736 | .cu-steps .cu-item:first-child::after { 2737 | display: none; 2738 | } 2739 | 2740 | .cu-steps .cu-item .num { 2741 | width: 40upx; 2742 | height: 40upx; 2743 | border-radius: 50%; 2744 | line-height: 40upx; 2745 | margin: 20upx auto; 2746 | font-size: 24upx; 2747 | border: 1px solid currentColor; 2748 | position: relative; 2749 | overflow: hidden; 2750 | } 2751 | 2752 | .cu-steps .cu-item[class*='text-'] .num { 2753 | background-color: currentColor; 2754 | } 2755 | 2756 | .cu-steps .cu-item .num::before, 2757 | .cu-steps .cu-item .num::after { 2758 | content: attr(data-index); 2759 | position: absolute; 2760 | left: 0; 2761 | right: 0; 2762 | top: 0; 2763 | bottom: 0; 2764 | margin: auto; 2765 | transition: all 0.3s ease-in-out 0s; 2766 | transform: translateY(0upx); 2767 | } 2768 | 2769 | .cu-steps .cu-item[class*='text-'] .num::before { 2770 | transform: translateY(-40upx); 2771 | color: #ffffff; 2772 | } 2773 | 2774 | .cu-steps .cu-item .num::after { 2775 | transform: translateY(40upx); 2776 | color: #ffffff; 2777 | transition: all 0.3s ease-in-out 0s; 2778 | } 2779 | 2780 | .cu-steps .cu-item[class*='text-'] .num::after { 2781 | content: '\e645'; 2782 | font-family: 'cuIcon'; 2783 | color: #ffffff; 2784 | transform: translateY(0upx); 2785 | } 2786 | 2787 | .cu-steps .cu-item[class*='text-'] .num.err::after { 2788 | content: '\e646'; 2789 | } 2790 | 2791 | /* ================== 2792 | 布局 2793 | ==================== */ 2794 | 2795 | /* -- flex弹性布局 -- */ 2796 | 2797 | .flex { 2798 | display: flex; 2799 | } 2800 | 2801 | .flex-row { 2802 | display: flex; 2803 | flex-direction: row; 2804 | } 2805 | 2806 | .flex-col { 2807 | display: flex; 2808 | flex-direction: column; 2809 | } 2810 | 2811 | .basis-xs { 2812 | flex-basis: 20%; 2813 | } 2814 | 2815 | .basis-sm { 2816 | flex-basis: 40%; 2817 | } 2818 | 2819 | .basis-df { 2820 | flex-basis: 50%; 2821 | } 2822 | 2823 | .basis-lg { 2824 | flex-basis: 60%; 2825 | } 2826 | 2827 | .basis-xl { 2828 | flex-basis: 80%; 2829 | } 2830 | 2831 | .flex-sub { 2832 | flex: 1; 2833 | } 2834 | 2835 | .flex-twice { 2836 | flex: 2; 2837 | } 2838 | 2839 | .flex-treble { 2840 | flex: 3; 2841 | } 2842 | 2843 | .flex-direction { 2844 | flex-direction: column; 2845 | } 2846 | 2847 | .flex-wrap { 2848 | flex-wrap: wrap; 2849 | } 2850 | 2851 | .align-start { 2852 | align-items: flex-start; 2853 | } 2854 | 2855 | .align-end { 2856 | align-items: flex-end; 2857 | } 2858 | 2859 | .align-center { 2860 | align-items: center; 2861 | } 2862 | 2863 | .align-stretch { 2864 | align-items: stretch; 2865 | } 2866 | 2867 | .self-start { 2868 | align-self: flex-start; 2869 | } 2870 | 2871 | .self-center { 2872 | align-self: flex-center; 2873 | } 2874 | 2875 | .self-end { 2876 | align-self: flex-end; 2877 | } 2878 | 2879 | .self-stretch { 2880 | align-self: stretch; 2881 | } 2882 | 2883 | .align-stretch { 2884 | align-items: stretch; 2885 | } 2886 | 2887 | .justify-start { 2888 | justify-content: flex-start; 2889 | } 2890 | 2891 | .justify-end { 2892 | justify-content: flex-end; 2893 | } 2894 | 2895 | .justify-center { 2896 | justify-content: center; 2897 | } 2898 | 2899 | .justify-between { 2900 | justify-content: space-between; 2901 | } 2902 | 2903 | .justify-around { 2904 | justify-content: space-around; 2905 | } 2906 | 2907 | /* grid布局 */ 2908 | 2909 | .grid { 2910 | display: flex; 2911 | flex-wrap: wrap; 2912 | } 2913 | 2914 | .grid.grid-square { 2915 | overflow: hidden; 2916 | } 2917 | 2918 | .grid.grid-square .cu-tag { 2919 | position: absolute; 2920 | right: 0; 2921 | top: 0; 2922 | border-bottom-left-radius: 6upx; 2923 | padding: 6upx 12upx; 2924 | height: auto; 2925 | background-color: rgba(0, 0, 0, 0.5); 2926 | } 2927 | 2928 | .grid.grid-square > view > text[class*='cuIcon-'] { 2929 | font-size: 52upx; 2930 | position: absolute; 2931 | color: #8799a3; 2932 | margin: auto; 2933 | top: 0; 2934 | bottom: 0; 2935 | left: 0; 2936 | right: 0; 2937 | display: flex; 2938 | justify-content: center; 2939 | align-items: center; 2940 | flex-direction: column; 2941 | } 2942 | 2943 | .grid.grid-square > view { 2944 | margin-right: 20upx; 2945 | margin-bottom: 20upx; 2946 | border-radius: 6upx; 2947 | position: relative; 2948 | overflow: hidden; 2949 | } 2950 | .grid.grid-square > view.bg-img image { 2951 | width: 100%; 2952 | height: 100%; 2953 | position: absolute; 2954 | } 2955 | .grid.col-1.grid-square > view { 2956 | padding-bottom: 100%; 2957 | height: 0; 2958 | margin-right: 0; 2959 | } 2960 | 2961 | .grid.col-2.grid-square > view { 2962 | padding-bottom: calc((100% - 20upx) / 2); 2963 | height: 0; 2964 | width: calc((100% - 20upx) / 2); 2965 | } 2966 | 2967 | .grid.col-3.grid-square > view { 2968 | padding-bottom: calc((100% - 40upx) / 3); 2969 | height: 0; 2970 | width: calc((100% - 40upx) / 3); 2971 | } 2972 | 2973 | .grid.col-4.grid-square > view { 2974 | padding-bottom: calc((100% - 60upx) / 4); 2975 | height: 0; 2976 | width: calc((100% - 60upx) / 4); 2977 | } 2978 | 2979 | .grid.col-5.grid-square > view { 2980 | padding-bottom: calc((100% - 80upx) / 5); 2981 | height: 0; 2982 | width: calc((100% - 80upx) / 5); 2983 | } 2984 | 2985 | .grid.col-2.grid-square > view:nth-child(2n), 2986 | .grid.col-3.grid-square > view:nth-child(3n), 2987 | .grid.col-4.grid-square > view:nth-child(4n), 2988 | .grid.col-5.grid-square > view:nth-child(5n) { 2989 | margin-right: 0; 2990 | } 2991 | 2992 | .grid.col-1 > view { 2993 | width: 100%; 2994 | } 2995 | 2996 | .grid.col-2 > view { 2997 | width: 50%; 2998 | } 2999 | 3000 | .grid.col-3 > view { 3001 | width: 33.33%; 3002 | } 3003 | 3004 | .grid.col-4 > view { 3005 | width: 25%; 3006 | } 3007 | 3008 | .grid.col-5 > view { 3009 | width: 20%; 3010 | } 3011 | 3012 | /* -- 外边距 -- */ 3013 | 3014 | .margin-0 { 3015 | margin: 0; 3016 | } 3017 | 3018 | .margin-xs { 3019 | margin: 10upx; 3020 | } 3021 | 3022 | .margin-sm { 3023 | margin: 20upx; 3024 | } 3025 | 3026 | .margin { 3027 | margin: 30upx; 3028 | } 3029 | 3030 | .margin-lg { 3031 | margin: 40upx; 3032 | } 3033 | 3034 | .margin-xl { 3035 | margin: 50upx; 3036 | } 3037 | 3038 | .margin-top-xs { 3039 | margin-top: 10upx; 3040 | } 3041 | 3042 | .margin-top-sm { 3043 | margin-top: 20upx; 3044 | } 3045 | 3046 | .margin-top { 3047 | margin-top: 30upx; 3048 | } 3049 | 3050 | .margin-top-lg { 3051 | margin-top: 40upx; 3052 | } 3053 | 3054 | .margin-top-xl { 3055 | margin-top: 50upx; 3056 | } 3057 | 3058 | .margin-right-xs { 3059 | margin-right: 10upx; 3060 | } 3061 | 3062 | .margin-right-sm { 3063 | margin-right: 20upx; 3064 | } 3065 | 3066 | .margin-right { 3067 | margin-right: 30upx; 3068 | } 3069 | 3070 | .margin-right-lg { 3071 | margin-right: 40upx; 3072 | } 3073 | 3074 | .margin-right-xl { 3075 | margin-right: 50upx; 3076 | } 3077 | 3078 | .margin-bottom-xs { 3079 | margin-bottom: 10upx; 3080 | } 3081 | 3082 | .margin-bottom-sm { 3083 | margin-bottom: 20upx; 3084 | } 3085 | 3086 | .margin-bottom { 3087 | margin-bottom: 30upx; 3088 | } 3089 | 3090 | .margin-bottom-lg { 3091 | margin-bottom: 40upx; 3092 | } 3093 | 3094 | .margin-bottom-xl { 3095 | margin-bottom: 50upx; 3096 | } 3097 | 3098 | .margin-left-xs { 3099 | margin-left: 10upx; 3100 | } 3101 | 3102 | .margin-left-sm { 3103 | margin-left: 20upx; 3104 | } 3105 | 3106 | .margin-left { 3107 | margin-left: 30upx; 3108 | } 3109 | 3110 | .margin-left-lg { 3111 | margin-left: 40upx; 3112 | } 3113 | 3114 | .margin-left-xl { 3115 | margin-left: 50upx; 3116 | } 3117 | 3118 | .margin-lr-xs { 3119 | margin-left: 10upx; 3120 | margin-right: 10upx; 3121 | } 3122 | 3123 | .margin-lr-sm { 3124 | margin-left: 20upx; 3125 | margin-right: 20upx; 3126 | } 3127 | 3128 | .margin-lr { 3129 | margin-left: 30upx; 3130 | margin-right: 30upx; 3131 | } 3132 | 3133 | .margin-lr-lg { 3134 | margin-left: 40upx; 3135 | margin-right: 40upx; 3136 | } 3137 | 3138 | .margin-lr-xl { 3139 | margin-left: 50upx; 3140 | margin-right: 50upx; 3141 | } 3142 | 3143 | .margin-tb-xs { 3144 | margin-top: 10upx; 3145 | margin-bottom: 10upx; 3146 | } 3147 | 3148 | .margin-tb-sm { 3149 | margin-top: 20upx; 3150 | margin-bottom: 20upx; 3151 | } 3152 | 3153 | .margin-tb { 3154 | margin-top: 30upx; 3155 | margin-bottom: 30upx; 3156 | } 3157 | 3158 | .margin-tb-lg { 3159 | margin-top: 40upx; 3160 | margin-bottom: 40upx; 3161 | } 3162 | 3163 | .margin-tb-xl { 3164 | margin-top: 50upx; 3165 | margin-bottom: 50upx; 3166 | } 3167 | 3168 | /* -- 内边距 -- */ 3169 | .padding-0 { 3170 | padding: 0; 3171 | } 3172 | 3173 | .padding-xs { 3174 | padding: 10upx; 3175 | } 3176 | 3177 | .padding-sm { 3178 | padding: 20upx; 3179 | } 3180 | 3181 | .padding { 3182 | padding: 30upx; 3183 | } 3184 | 3185 | .padding-lg { 3186 | padding: 40upx; 3187 | } 3188 | 3189 | .padding-xl { 3190 | padding: 50upx; 3191 | } 3192 | 3193 | .padding-top-xs { 3194 | padding-top: 10upx; 3195 | } 3196 | 3197 | .padding-top-sm { 3198 | padding-top: 20upx; 3199 | } 3200 | 3201 | .padding-top { 3202 | padding-top: 30upx; 3203 | } 3204 | 3205 | .padding-top-lg { 3206 | padding-top: 40upx; 3207 | } 3208 | 3209 | .padding-top-xl { 3210 | padding-top: 50upx; 3211 | } 3212 | 3213 | .padding-right-xs { 3214 | padding-right: 10upx; 3215 | } 3216 | 3217 | .padding-right-sm { 3218 | padding-right: 20upx; 3219 | } 3220 | 3221 | .padding-right { 3222 | padding-right: 30upx; 3223 | } 3224 | 3225 | .padding-right-lg { 3226 | padding-right: 40upx; 3227 | } 3228 | 3229 | .padding-right-xl { 3230 | padding-right: 50upx; 3231 | } 3232 | 3233 | .padding-bottom-xs { 3234 | padding-bottom: 10upx; 3235 | } 3236 | 3237 | .padding-bottom-sm { 3238 | padding-bottom: 20upx; 3239 | } 3240 | 3241 | .padding-bottom { 3242 | padding-bottom: 30upx; 3243 | } 3244 | 3245 | .padding-bottom-lg { 3246 | padding-bottom: 40upx; 3247 | } 3248 | 3249 | .padding-bottom-xl { 3250 | padding-bottom: 50upx; 3251 | } 3252 | 3253 | .padding-left-xs { 3254 | padding-left: 10upx; 3255 | } 3256 | 3257 | .padding-left-sm { 3258 | padding-left: 20upx; 3259 | } 3260 | 3261 | .padding-left { 3262 | padding-left: 30upx; 3263 | } 3264 | 3265 | .padding-left-lg { 3266 | padding-left: 40upx; 3267 | } 3268 | 3269 | .padding-left-xl { 3270 | padding-left: 50upx; 3271 | } 3272 | 3273 | .padding-lr-xs { 3274 | padding-left: 10upx; 3275 | padding-right: 10upx; 3276 | } 3277 | 3278 | .padding-lr-sm { 3279 | padding-left: 20upx; 3280 | padding-right: 20upx; 3281 | } 3282 | 3283 | .padding-lr { 3284 | padding-left: 30upx; 3285 | padding-right: 30upx; 3286 | } 3287 | 3288 | .padding-lr-lg { 3289 | padding-left: 40upx; 3290 | padding-right: 40upx; 3291 | } 3292 | 3293 | .padding-lr-xl { 3294 | padding-left: 50upx; 3295 | padding-right: 50upx; 3296 | } 3297 | 3298 | .padding-tb-xs { 3299 | padding-top: 10upx; 3300 | padding-bottom: 10upx; 3301 | } 3302 | 3303 | .padding-tb-sm { 3304 | padding-top: 20upx; 3305 | padding-bottom: 20upx; 3306 | } 3307 | 3308 | .padding-tb { 3309 | padding-top: 30upx; 3310 | padding-bottom: 30upx; 3311 | } 3312 | 3313 | .padding-tb-lg { 3314 | padding-top: 40upx; 3315 | padding-bottom: 40upx; 3316 | } 3317 | 3318 | .padding-tb-xl { 3319 | padding-top: 50upx; 3320 | padding-bottom: 50upx; 3321 | } 3322 | 3323 | /* -- 浮动 -- */ 3324 | 3325 | .cf::after, 3326 | .cf::before { 3327 | content: ' '; 3328 | display: table; 3329 | } 3330 | 3331 | .cf::after { 3332 | clear: both; 3333 | } 3334 | 3335 | .fl { 3336 | float: left; 3337 | } 3338 | 3339 | .fr { 3340 | float: right; 3341 | } 3342 | 3343 | /* ================== 3344 | 背景 3345 | ==================== */ 3346 | 3347 | .line-red::after, 3348 | .lines-red::after { 3349 | border-color: #e54d42; 3350 | } 3351 | 3352 | .line-orange::after, 3353 | .lines-orange::after { 3354 | border-color: #f37b1d; 3355 | } 3356 | 3357 | .line-yellow::after, 3358 | .lines-yellow::after { 3359 | border-color: #fbbd08; 3360 | } 3361 | 3362 | .line-olive::after, 3363 | .lines-olive::after { 3364 | border-color: #8dc63f; 3365 | } 3366 | 3367 | .line-green::after, 3368 | .lines-green::after { 3369 | border-color: #39b54a; 3370 | } 3371 | 3372 | .line-cyan::after, 3373 | .lines-cyan::after { 3374 | border-color: #1cbbb4; 3375 | } 3376 | 3377 | .line-blue::after, 3378 | .lines-blue::after { 3379 | border-color: #0081ff; 3380 | } 3381 | 3382 | .line-purple::after, 3383 | .lines-purple::after { 3384 | border-color: #6739b6; 3385 | } 3386 | 3387 | .line-mauve::after, 3388 | .lines-mauve::after { 3389 | border-color: #9c26b0; 3390 | } 3391 | 3392 | .line-pink::after, 3393 | .lines-pink::after { 3394 | border-color: #e03997; 3395 | } 3396 | 3397 | .line-brown::after, 3398 | .lines-brown::after { 3399 | border-color: #a5673f; 3400 | } 3401 | 3402 | .line-grey::after, 3403 | .lines-grey::after { 3404 | border-color: #8799a3; 3405 | } 3406 | 3407 | .line-gray::after, 3408 | .lines-gray::after { 3409 | border-color: #aaaaaa; 3410 | } 3411 | 3412 | .line-black::after, 3413 | .lines-black::after { 3414 | border-color: #333333; 3415 | } 3416 | 3417 | .line-white::after, 3418 | .lines-white::after { 3419 | border-color: #ffffff; 3420 | } 3421 | 3422 | .bg-red { 3423 | background-color: #e54d42; 3424 | color: #ffffff; 3425 | } 3426 | 3427 | .bg-orange { 3428 | background-color: #f37b1d; 3429 | color: #ffffff; 3430 | } 3431 | 3432 | .bg-yellow { 3433 | background-color: #fbbd08; 3434 | color: #333333; 3435 | } 3436 | 3437 | .bg-olive { 3438 | background-color: #8dc63f; 3439 | color: #ffffff; 3440 | } 3441 | 3442 | .bg-green { 3443 | background-color: #39b54a; 3444 | color: #ffffff; 3445 | } 3446 | 3447 | .bg-cyan { 3448 | background-color: #1cbbb4; 3449 | color: #ffffff; 3450 | } 3451 | 3452 | .bg-blue { 3453 | background-color: #0081ff; 3454 | color: #ffffff; 3455 | } 3456 | 3457 | .bg-purple { 3458 | background-color: #6739b6; 3459 | color: #ffffff; 3460 | } 3461 | 3462 | .bg-mauve { 3463 | background-color: #9c26b0; 3464 | color: #ffffff; 3465 | } 3466 | 3467 | .bg-pink { 3468 | background-color: #e03997; 3469 | color: #ffffff; 3470 | } 3471 | 3472 | .bg-brown { 3473 | background-color: #a5673f; 3474 | color: #ffffff; 3475 | } 3476 | 3477 | .bg-grey { 3478 | background-color: #8799a3; 3479 | color: #ffffff; 3480 | } 3481 | 3482 | .bg-gray { 3483 | background-color: #f0f0f0; 3484 | color: #333333; 3485 | } 3486 | 3487 | .bg-black { 3488 | background-color: #333333; 3489 | color: #ffffff; 3490 | } 3491 | 3492 | .bg-white { 3493 | background-color: #ffffff; 3494 | color: #666666; 3495 | } 3496 | 3497 | .bg-shadeTop { 3498 | background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01)); 3499 | color: #ffffff; 3500 | } 3501 | 3502 | .bg-shadeBottom { 3503 | background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1)); 3504 | color: #ffffff; 3505 | } 3506 | 3507 | .bg-red.light { 3508 | color: #e54d42; 3509 | background-color: #fadbd9; 3510 | } 3511 | 3512 | .bg-orange.light { 3513 | color: #f37b1d; 3514 | background-color: #fde6d2; 3515 | } 3516 | 3517 | .bg-yellow.light { 3518 | color: #fbbd08; 3519 | background-color: #fef2ced2; 3520 | } 3521 | 3522 | .bg-olive.light { 3523 | color: #8dc63f; 3524 | background-color: #e8f4d9; 3525 | } 3526 | 3527 | .bg-green.light { 3528 | color: #39b54a; 3529 | background-color: #d7f0dbff; 3530 | } 3531 | 3532 | .bg-cyan.light { 3533 | color: #1cbbb4; 3534 | background-color: #d2f1f0; 3535 | } 3536 | 3537 | .bg-blue.light { 3538 | color: #0081ff; 3539 | background-color: #cce6ff; 3540 | } 3541 | 3542 | .bg-purple.light { 3543 | color: #6739b6; 3544 | background-color: #e1d7f0; 3545 | } 3546 | 3547 | .bg-mauve.light { 3548 | color: #9c26b0; 3549 | background-color: #ebd4ef; 3550 | } 3551 | 3552 | .bg-pink.light { 3553 | color: #e03997; 3554 | background-color: #f9d7ea; 3555 | } 3556 | 3557 | .bg-brown.light { 3558 | color: #a5673f; 3559 | background-color: #ede1d9; 3560 | } 3561 | 3562 | .bg-grey.light { 3563 | color: #8799a3; 3564 | background-color: #e7ebed; 3565 | } 3566 | 3567 | .bg-gradual-red { 3568 | background-image: linear-gradient(45deg, #f43f3b, #ec008c); 3569 | color: #ffffff; 3570 | } 3571 | 3572 | .bg-gradual-orange { 3573 | background-image: linear-gradient(45deg, #ff9700, #ed1c24); 3574 | color: #ffffff; 3575 | } 3576 | 3577 | .bg-gradual-green { 3578 | background-image: linear-gradient(45deg, #39b54a, #8dc63f); 3579 | color: #ffffff; 3580 | } 3581 | 3582 | .bg-gradual-purple { 3583 | background-image: linear-gradient(45deg, #9000ff, #5e00ff); 3584 | color: #ffffff; 3585 | } 3586 | 3587 | .bg-gradual-pink { 3588 | background-image: linear-gradient(45deg, #ec008c, #6739b6); 3589 | color: #ffffff; 3590 | } 3591 | 3592 | .bg-gradual-blue { 3593 | background-image: linear-gradient(45deg, #0081ff, #1cbbb4); 3594 | color: #ffffff; 3595 | } 3596 | 3597 | .shadow[class*='-red'] { 3598 | box-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2); 3599 | } 3600 | 3601 | .shadow[class*='-orange'] { 3602 | box-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2); 3603 | } 3604 | 3605 | .shadow[class*='-yellow'] { 3606 | box-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2); 3607 | } 3608 | 3609 | .shadow[class*='-olive'] { 3610 | box-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2); 3611 | } 3612 | 3613 | .shadow[class*='-green'] { 3614 | box-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2); 3615 | } 3616 | 3617 | .shadow[class*='-cyan'] { 3618 | box-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2); 3619 | } 3620 | 3621 | .shadow[class*='-blue'] { 3622 | box-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2); 3623 | } 3624 | 3625 | .shadow[class*='-purple'] { 3626 | box-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2); 3627 | } 3628 | 3629 | .shadow[class*='-mauve'] { 3630 | box-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2); 3631 | } 3632 | 3633 | .shadow[class*='-pink'] { 3634 | box-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2); 3635 | } 3636 | 3637 | .shadow[class*='-brown'] { 3638 | box-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2); 3639 | } 3640 | 3641 | .shadow[class*='-grey'] { 3642 | box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); 3643 | } 3644 | 3645 | .shadow[class*='-gray'] { 3646 | box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); 3647 | } 3648 | 3649 | .shadow[class*='-black'] { 3650 | box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); 3651 | } 3652 | 3653 | .shadow[class*='-white'] { 3654 | box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); 3655 | } 3656 | 3657 | .text-shadow[class*='-red'] { 3658 | text-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2); 3659 | } 3660 | 3661 | .text-shadow[class*='-orange'] { 3662 | text-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2); 3663 | } 3664 | 3665 | .text-shadow[class*='-yellow'] { 3666 | text-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2); 3667 | } 3668 | 3669 | .text-shadow[class*='-olive'] { 3670 | text-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2); 3671 | } 3672 | 3673 | .text-shadow[class*='-green'] { 3674 | text-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2); 3675 | } 3676 | 3677 | .text-shadow[class*='-cyan'] { 3678 | text-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2); 3679 | } 3680 | 3681 | .text-shadow[class*='-blue'] { 3682 | text-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2); 3683 | } 3684 | 3685 | .text-shadow[class*='-purple'] { 3686 | text-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2); 3687 | } 3688 | 3689 | .text-shadow[class*='-mauve'] { 3690 | text-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2); 3691 | } 3692 | 3693 | .text-shadow[class*='-pink'] { 3694 | text-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2); 3695 | } 3696 | 3697 | .text-shadow[class*='-brown'] { 3698 | text-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2); 3699 | } 3700 | 3701 | .text-shadow[class*='-grey'] { 3702 | text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); 3703 | } 3704 | 3705 | .text-shadow[class*='-gray'] { 3706 | text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); 3707 | } 3708 | 3709 | .text-shadow[class*='-black'] { 3710 | text-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); 3711 | } 3712 | 3713 | .bg-img { 3714 | background-size: cover; 3715 | background-position: center; 3716 | background-repeat: no-repeat; 3717 | } 3718 | 3719 | .bg-mask { 3720 | background-color: #333333; 3721 | position: relative; 3722 | } 3723 | 3724 | .bg-mask::after { 3725 | content: ''; 3726 | border-radius: inherit; 3727 | width: 100%; 3728 | height: 100%; 3729 | display: block; 3730 | background-color: rgba(0, 0, 0, 0.4); 3731 | position: absolute; 3732 | left: 0; 3733 | right: 0; 3734 | bottom: 0; 3735 | top: 0; 3736 | } 3737 | 3738 | .bg-mask view, 3739 | .bg-mask cover-view { 3740 | z-index: 5; 3741 | position: relative; 3742 | } 3743 | 3744 | .bg-video { 3745 | position: relative; 3746 | } 3747 | 3748 | .bg-video video { 3749 | display: block; 3750 | height: 100%; 3751 | width: 100%; 3752 | -o-object-fit: cover; 3753 | object-fit: cover; 3754 | position: absolute; 3755 | top: 0; 3756 | z-index: 0; 3757 | pointer-events: none; 3758 | } 3759 | 3760 | /* ================== 3761 | 文本 3762 | ==================== */ 3763 | 3764 | .text-xs { 3765 | font-size: 20upx; 3766 | } 3767 | 3768 | .text-sm { 3769 | font-size: 24upx; 3770 | } 3771 | 3772 | .text-df { 3773 | font-size: 28upx; 3774 | } 3775 | 3776 | .text-lg { 3777 | font-size: 32upx; 3778 | } 3779 | 3780 | .text-xl { 3781 | font-size: 36upx; 3782 | } 3783 | 3784 | .text-xxl { 3785 | font-size: 44upx; 3786 | } 3787 | 3788 | .text-sl { 3789 | font-size: 80upx; 3790 | } 3791 | 3792 | .text-xsl { 3793 | font-size: 120upx; 3794 | } 3795 | 3796 | .text-Abc { 3797 | text-transform: Capitalize; 3798 | } 3799 | 3800 | .text-ABC { 3801 | text-transform: Uppercase; 3802 | } 3803 | 3804 | .text-abc { 3805 | text-transform: Lowercase; 3806 | } 3807 | 3808 | .text-price::before { 3809 | content: '¥'; 3810 | font-size: 80%; 3811 | margin-right: 4upx; 3812 | } 3813 | 3814 | .text-cut { 3815 | text-overflow: ellipsis; 3816 | white-space: nowrap; 3817 | overflow: hidden; 3818 | } 3819 | 3820 | .text-bold { 3821 | font-weight: bold; 3822 | } 3823 | 3824 | .text-center { 3825 | text-align: center; 3826 | } 3827 | 3828 | .text-content { 3829 | line-height: 1.6; 3830 | } 3831 | 3832 | .text-left { 3833 | text-align: left; 3834 | } 3835 | 3836 | .text-right { 3837 | text-align: right; 3838 | } 3839 | 3840 | .text-red, 3841 | .line-red, 3842 | .lines-red { 3843 | color: #e54d42; 3844 | } 3845 | 3846 | .text-orange, 3847 | .line-orange, 3848 | .lines-orange { 3849 | color: #f37b1d; 3850 | } 3851 | 3852 | .text-yellow, 3853 | .line-yellow, 3854 | .lines-yellow { 3855 | color: #fbbd08; 3856 | } 3857 | 3858 | .text-olive, 3859 | .line-olive, 3860 | .lines-olive { 3861 | color: #8dc63f; 3862 | } 3863 | 3864 | .text-green, 3865 | .line-green, 3866 | .lines-green { 3867 | color: #39b54a; 3868 | } 3869 | 3870 | .text-cyan, 3871 | .line-cyan, 3872 | .lines-cyan { 3873 | color: #1cbbb4; 3874 | } 3875 | 3876 | .text-blue, 3877 | .line-blue, 3878 | .lines-blue { 3879 | color: #0081ff; 3880 | } 3881 | 3882 | .text-purple, 3883 | .line-purple, 3884 | .lines-purple { 3885 | color: #6739b6; 3886 | } 3887 | 3888 | .text-mauve, 3889 | .line-mauve, 3890 | .lines-mauve { 3891 | color: #9c26b0; 3892 | } 3893 | 3894 | .text-pink, 3895 | .line-pink, 3896 | .lines-pink { 3897 | color: #e03997; 3898 | } 3899 | 3900 | .text-brown, 3901 | .line-brown, 3902 | .lines-brown { 3903 | color: #a5673f; 3904 | } 3905 | 3906 | .text-grey, 3907 | .line-grey, 3908 | .lines-grey { 3909 | color: #8799a3; 3910 | } 3911 | 3912 | .text-gray, 3913 | .line-gray, 3914 | .lines-gray { 3915 | color: #aaaaaa; 3916 | } 3917 | 3918 | .text-black, 3919 | .line-black, 3920 | .lines-black { 3921 | color: #333333; 3922 | } 3923 | 3924 | .text-white, 3925 | .line-white, 3926 | .lines-white { 3927 | color: #ffffff; 3928 | } 3929 | --------------------------------------------------------------------------------