illli
Version:
微信小程序 WXSS 样式库,简洁高效的UI组件、动画和样式类集合
585 lines (505 loc) • 18.6 kB
JavaScript
#!/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();
}
}