UNPKG

illli

Version:

微信小程序 WXSS 样式库,简洁高效的UI组件、动画和样式类集合

585 lines (505 loc) 18.6 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const readline = require('readline'); // 组件定义 const components = { button: { name: 'Button', styles: fs.readFileSync(path.join(__dirname, 'components', 'button.wxss'), 'utf8'), usage: `<!-- 基础按钮 --> <view class="btn">按钮</view> <!-- 主要按钮 --> <view class="btn btn-primary">主要按钮</view> <!-- 危险按钮 --> <view class="btn btn-danger">危险按钮</view> <!-- 警告按钮 --> <view class="btn btn-warning">警告按钮</view> <!-- 信息按钮 --> <view class="btn btn-info">信息按钮</view> <!-- 朴素按钮 --> <view class="btn btn-outline">朴素按钮</view> <!-- 尺寸 --> <view class="btn btn-primary btn-sm">小按钮</view> <view class="btn btn-primary">普通按钮</view> <view class="btn btn-primary btn-lg">大按钮</view> <!-- 块级按钮 --> <view class="btn btn-primary btn-block">块级按钮</view> <!-- 按钮动画效果 --> <view class="btn btn-primary btn-ripple">波纹按钮</view> <view class="btn btn-primary btn-pulse">脉冲按钮</view> <view class="btn btn-gradient-primary">渐变按钮</view> <view class="btn btn-primary btn-glow">闪烁按钮</view> <view class="btn btn-primary btn-circle">圆形</view> <view class="btn btn-primary btn-loading">加载中</view>` }, card: { name: 'Card', styles: fs.readFileSync(path.join(__dirname, 'components', 'card.wxss'), 'utf8'), usage: `<!-- 基础卡片 --> <view class="card"> <view class="card-body">卡片内容</view> </view> <!-- 带标题的卡片 --> <view class="card"> <view class="card-header">卡片标题</view> <view class="card-body">卡片内容</view> </view> <!-- 带底部的卡片 --> <view class="card"> <view class="card-header">卡片标题</view> <view class="card-body">卡片内容</view> <view class="card-footer">卡片底部</view> </view>` }, list: { name: 'List', styles: fs.readFileSync(path.join(__dirname, 'components', 'list.wxss'), 'utf8'), usage: `<!-- 基础列表 --> <view class="list"> <view class="list-item"> <view class="list-item-content">列表项 1</view> </view> <view class="list-item"> <view class="list-item-content">列表项 2</view> </view> <view class="list-item"> <view class="list-item-content">列表项 3</view> </view> </view> <!-- 带附加内容的列表 --> <view class="list"> <view class="list-item"> <view class="list-item-content">列表项 1</view> <view class="list-item-extra">附加信息</view> </view> <view class="list-item"> <view class="list-item-content">列表项 2</view> <view class="list-item-extra">附加信息</view> </view> </view>` }, tag: { name: 'Tag', styles: fs.readFileSync(path.join(__dirname, 'components', 'tag.wxss'), 'utf8'), usage: `<!-- 标签类型 --> <view class="tag tag-primary">标签</view> <view class="tag tag-danger">标签</view> <view class="tag tag-warning">标签</view> <view class="tag tag-info">标签</view>` }, form: { name: 'Form', styles: fs.readFileSync(path.join(__dirname, 'components', 'form.wxss'), 'utf8'), usage: `<!-- 基础表单字段 --> <view class="form-group"> <text class="form-label">输入框标签</text> <input class="form-input" placeholder="请输入内容" /> </view> <!-- 文本域 --> <view class="form-group"> <text class="form-label">文本域标签</text> <textarea class="form-textarea" placeholder="请输入内容" /> </view> <!-- 复选框 --> <view class="form-group"> <text class="form-label">复选框</text> <view class="form-checkbox-group"> <label class="form-checkbox"> <checkbox value="1" /> <text>选项一</text> </label> <label class="form-checkbox"> <checkbox value="2" /> <text>选项二</text> </label> </view> </view>` }, avatar: { name: 'Avatar', styles: fs.readFileSync(path.join(__dirname, 'components', 'avatar.wxss'), 'utf8'), usage: `<!-- 基础头像 --> <view class="avatar"> <image src="/path/to/avatar.png" mode="aspectFill"></image> </view> <!-- 头像尺寸 --> <view class="avatar avatar-sm"> <image src="/path/to/avatar.png" mode="aspectFill"></image> </view> <view class="avatar"> <image src="/path/to/avatar.png" mode="aspectFill"></image> </view> <view class="avatar avatar-lg"> <image src="/path/to/avatar.png" mode="aspectFill"></image> </view> <!-- 方形头像 --> <view class="avatar avatar-square"> <image src="/path/to/avatar.png" mode="aspectFill"></image> </view> <!-- 头像组 --> <view class="avatar-group"> <view class="avatar avatar-border"> <image src="/path/to/avatar1.png" mode="aspectFill"></image> </view> <view class="avatar avatar-border"> <image src="/path/to/avatar2.png" mode="aspectFill"></image> </view> <view class="avatar avatar-border"> <image src="/path/to/avatar3.png" mode="aspectFill"></image> </view> </view>` }, layout: { name: 'Layout', styles: fs.readFileSync(path.join(__dirname, 'components', 'layout.wxss'), 'utf8'), usage: `<!-- 容器 --> <view class="container"> <!-- 内容 --> </view> <!-- Flex 行布局 --> <view class="flex-row"> <view>元素 1</view> <view>元素 2</view> </view> <!-- Flex 列布局 --> <view class="flex-col"> <view>元素 1</view> <view>元素 2</view> </view> <!-- 居中布局 --> <view class="flex-center"> <view>居中内容</view> </view> <!-- 两端对齐 --> <view class="flex-between"> <view>左侧</view> <view>右侧</view> </view>` }, utils: { name: 'Utils', styles: fs.readFileSync(path.join(__dirname, 'components', 'utils.wxss'), 'utf8'), usage: `<!-- 边距类 --> <view class="m-10">外边距 10rpx</view> <view class="p-20">内边距 20rpx</view> <view class="mt-10">上外边距 10rpx</view> <view class="mb-20">下外边距 20rpx</view> <!-- 文本类 --> <view class="text-center">居中文本</view> <view class="text-bold">粗体文本</view> <view class="text-small">小号文本</view> <view class="text-large">大号文本</view> <!-- 颜色类 --> <view class="text-primary">主色文本</view> <view class="bg-primary">主色背景</view> <view class="text-danger">危险色文本</view> <!-- 边框类 --> <view class="border">带边框</view> <view class="radius">圆角</view>` }, animations: { name: 'Animations', styles: fs.readFileSync(path.join(__dirname, 'components', 'animations.wxss'), 'utf8'), usage: `<!-- 基础动画 --> <view class="animate fade-in">淡入效果</view> <view class="animate zoom-in">缩放效果</view> <view class="animate slide-in-left">从左滑入</view> <view class="animate slide-in-right">从右滑入</view> <!-- 动画速度控制 --> <view class="animate animate-slow fade-in">慢速淡入</view> <view class="animate animate-fast fade-in">快速淡入</view> <!-- 循环动画 --> <view class="animate animate-infinite pulse">脉冲效果</view> <view class="animate animate-infinite rotate">旋转效果</view> <!-- 特殊效果 --> <view class="animate bounce">弹跳效果</view> <view class="animate shake">摇晃效果</view> <view class="animate flash">闪烁效果</view> <!-- 按钮动画效果 --> <view class="btn btn-primary btn-animated">波纹按钮</view>` }, transitions: { name: 'Transitions', styles: fs.readFileSync(path.join(__dirname, 'components', 'transitions.wxss'), 'utf8'), usage: `<!-- 基础过渡 --> <view class="transition">基础过渡效果</view> <!-- 过渡速度 --> <view class="transition transition-fast">快速过渡</view> <view class="transition transition-slow">慢速过渡</view> <!-- 过渡函数 --> <view class="transition transition-ease-in">渐入</view> <view class="transition transition-ease-out">渐出</view> <!-- 悬停效果 --> <view class="hover-scale">缩放效果</view> <view class="hover-lift">上浮效果</view> <view class="hover-opacity">透明效果</view> <!-- 特殊过渡效果 --> <view class="btn btn-transition">按钮过渡</view> <view class="card card-transition">卡片过渡</view> <view class="color-transition">颜色过渡</view> <view class="border-transition">边框过渡</view> <view class="shape-transition">形状过渡</view>` } }; // 获取所有组件名称 function getAllComponents() { return Object.keys(components); } function showHelp() { console.log(` illli - 微信小程序 WXSS 样式库 CLI 工具 v${require('./package.json').version} 用法: npx illli init 初始化 illli 样式库 npx illli add <component> 将组件添加到项目 npx illli list 列出所有可用组件 npx illli help <component> 显示组件用法帮助 支持的组件: ${getAllComponents().join(', ')} `); } // 应用暗色主题到 CSS 变量 function applyDarkTheme(cssContent) { return cssContent // 主题颜色 .replace('--color-dark: #333333;', '--color-dark: #121212;') .replace('--color-light: #F7F7F7;', '--color-light: #2C2C2C;') .replace('--color-white: #FFFFFF;', '--color-white: #1E1E1E;') .replace('--color-border: #EEEEEE;', '--color-border: #444444;') .replace('--color-bg: #F7F7F7;', '--color-bg: #121212;') .replace('--color-text: #333333;', '--color-text: #E0E0E0;') .replace('--color-text-secondary: #666666;', '--color-text-secondary: #A0A0A0;') .replace('--color-text-tertiary: #999999;', '--color-text-tertiary: #777777;') .replace('--color-disabled: #CCCCCC;', '--color-disabled: #444444;') .replace('--color-divider: #EEEEEE;', '--color-divider: #444444;') .replace('--color-mask: rgba(0, 0, 0, 0.4);', '--color-mask: rgba(0, 0, 0, 0.7);') .replace('--box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);', '--box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.4);'); } // 初始化 illli 样式库 function initLibrary() { console.log('正在初始化 illli 样式库...'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('请选择主题颜色 (1: 白色主题, 2: 黑色主题): ', (answer) => { const theme = answer === '2' ? 'dark' : 'light'; console.log(`已选择 ${theme === 'dark' ? '黑色' : '白色'} 主题`); // 创建 illli 文件夹 if (!fs.existsSync('./illli')) { fs.mkdirSync('./illli', { recursive: true }); console.log('创建 illli 文件夹成功'); } else { console.log('illli 文件夹已存在'); } // 复制 illli.wxss 到项目并应用主题 let illlWxss = fs.readFileSync(path.join(__dirname, 'illli.wxss'), 'utf8'); // 应用主题 if (theme === 'dark') { // 应用暗色主题 illlWxss = applyDarkTheme(illlWxss); } fs.writeFileSync('./illli/illli.wxss', illlWxss, 'utf8'); console.log('illli.wxss 文件已创建'); // 检查 app.wxss 是否存在 if (fs.existsSync('./app.wxss')) { // 检查是否已经引入 let appWxss = fs.readFileSync('./app.wxss', 'utf8'); if (!appWxss.includes('@import "./illli/illli.wxss";')) { // 添加引用到 app.wxss appWxss = `@import "./illli/illli.wxss";\n\n${appWxss}`; fs.writeFileSync('./app.wxss', appWxss, 'utf8'); console.log('已将 illli.wxss 引入到 app.wxss'); } else { console.log('app.wxss 已包含 illli.wxss 引用'); } } else { // 创建 app.wxss 并引入 fs.writeFileSync('./app.wxss', '@import "./illli/illli.wxss";\n', 'utf8'); console.log('已创建 app.wxss 并引入 illli.wxss'); } console.log('初始化完成!可以使用 npx illli add <component> 添加组件'); rl.close(); }); } // 安装所有组件 function installAllComponents() { console.log('正在安装所有组件...'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('请选择主题颜色 (1: 白色主题, 2: 黑色主题): ', (answer) => { const theme = answer === '2' ? 'dark' : 'light'; console.log(`已选择 ${theme === 'dark' ? '黑色' : '白色'} 主题`); // 确保 illli 文件夹存在 if (!fs.existsSync('./illli')) { fs.mkdirSync('./illli', { recursive: true }); console.log('创建 illli 文件夹成功'); // 复制 illli.wxss 到项目并应用主题 let illlWxss = fs.readFileSync(path.join(__dirname, 'illli.wxss'), 'utf8'); // 应用主题 if (theme === 'dark') { // 应用暗色主题 illlWxss = applyDarkTheme(illlWxss); } fs.writeFileSync('./illli/illli.wxss', illlWxss, 'utf8'); console.log('illli.wxss 文件已创建'); } // 引入每个组件到 illli.wxss const componentImports = getAllComponents().map(comp => `@import "./components/${comp}.wxss";` ).join('\n'); // 读取 illli.wxss let illlWxss = fs.readFileSync('./illli/illli.wxss', 'utf8'); // 如果已存在且需要应用黑色主题 if (theme === 'dark' && !illlWxss.includes('--color-white: #1E1E1E;')) { // 应用暗色主题 illlWxss = applyDarkTheme(illlWxss); } // 检查导入组件样式行是否存在,如果不存在则添加 if (!illlWxss.includes('/* 导入组件样式 */')) { illlWxss = illlWxss.replace('/* 导入组件样式 */', `/* 导入组件样式 */\n${componentImports}`); } else { // 替换现有导入 const importRegex = /\/\* 导入组件样式 \*\/\n((?:@import[^\n]*\n)*)/; if (importRegex.test(illlWxss)) { illlWxss = illlWxss.replace(importRegex, `/* 导入组件样式 */\n${componentImports}\n`); } else { illlWxss = illlWxss.replace('/* 导入组件样式 */', `/* 导入组件样式 */\n${componentImports}`); } } fs.writeFileSync('./illli/illli.wxss', illlWxss, 'utf8'); // 创建 components 文件夹 if (!fs.existsSync('./illli/components')) { fs.mkdirSync('./illli/components', { recursive: true }); } // 复制所有组件到 components 文件夹 for (const comp of getAllComponents()) { fs.writeFileSync( `./illli/components/${comp}.wxss`, components[comp].styles, 'utf8' ); console.log(`组件 ${comp} 已安装`); } // 检查 app.wxss 是否存在并添加引用 if (fs.existsSync('./app.wxss')) { // 读取当前内容 let appWxss = fs.readFileSync('./app.wxss', 'utf8'); // 检查是否已经引入 if (!appWxss.includes('@import "./illli/illli.wxss";')) { // 添加引用到 app.wxss appWxss = `@import "./illli/illli.wxss";\n\n${appWxss}`; fs.writeFileSync('./app.wxss', appWxss, 'utf8'); console.log('已将 illli.wxss 引入到 app.wxss'); } else { console.log('app.wxss 已包含 illli.wxss 引用'); } } else { // 创建 app.wxss 并引入 fs.writeFileSync('./app.wxss', '@import "./illli/illli.wxss";\n', 'utf8'); console.log('已创建 app.wxss 并引入 illli.wxss'); } console.log('所有组件安装完成!'); rl.close(); }); } function listComponents() { console.log(` 可用组件列表: ${getAllComponents().map(name => `- ${name}: ${components[name].name} 组件`).join('\n ')} 使用 'npx illli help <component>' 查看组件详细用法 `); } function showComponentHelp(componentName) { const component = components[componentName]; if (component) { console.log(` ${component.name} 组件使用指南 WXSS 类名称和用法: ${component.styles} 用法示例: ${component.usage} `); } else { console.log(`错误: 未找到组件 "${componentName}"`); } } function addComponent(componentName) { if (!components[componentName]) { console.log(`错误: 未找到组件 "${componentName}"`); console.log(`可用组件: ${getAllComponents().join(', ')}`); return; } // 确保 illli 文件夹存在 if (!fs.existsSync('./illli')) { console.log('错误: illli 文件夹不存在,请先运行 npx illli init'); return; } // 确保 components 文件夹存在 if (!fs.existsSync('./illli/components')) { fs.mkdirSync('./illli/components', { recursive: true }); } // 复制组件到 components 文件夹 fs.writeFileSync( `./illli/components/${componentName}.wxss`, components[componentName].styles, 'utf8' ); // 更新 illli.wxss let illlWxss = fs.readFileSync('./illli/illli.wxss', 'utf8'); const importLine = `@import "./components/${componentName}.wxss";`; // 检查是否已经导入 if (illlWxss.includes(importLine)) { console.log(`组件 ${componentName} 已存在`); return; } // 添加导入到 illli.wxss if (illlWxss.includes('/* 导入组件样式 */')) { // 在导入组件样式后添加 illlWxss = illlWxss.replace( '/* 导入组件样式 */', `/* 导入组件样式 */\n${importLine}` ); } else { // 添加到文件开头 illlWxss = `/* 导入组件样式 */\n${importLine}\n\n${illlWxss}`; } fs.writeFileSync('./illli/illli.wxss', illlWxss, 'utf8'); console.log(`组件 ${componentName} 已添加到项目`); } // 命令行参数处理 const args = process.argv.slice(2); const command = args[0]; const param = args[1]; switch (command) { case 'init': initLibrary(); break; case 'add': if (!param) { console.log('错误: 缺少组件名称'); showHelp(); } else { addComponent(param); } break; case 'list': listComponents(); break; case 'help': if (param) { showComponentHelp(param); } else { showHelp(); } break; default: if (command === 'install' || !command) { installAllComponents(); } else { console.log(`错误: 未知命令 "${command}"`); showHelp(); } }