Showing preview only (334K chars total). Download the full file or copy to clipboard to get everything.
Repository: chokcoco/iCSS
Branch: master
Commit: e03eb3e59021
Files: 53
Total size: 318.0 KB
Directory structure:
gitextract_o4i__mil/
├── .gitattributes
├── MCP/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.en.md
│ ├── README.md
│ ├── bin/
│ │ ├── icss-mcp.js
│ │ └── install.js
│ ├── debug-interactive.js
│ ├── debug-local.js
│ ├── debug-query.js
│ ├── debug.js
│ ├── diagnose-mcp.js
│ ├── package.json
│ ├── scripts/
│ │ ├── cursor-config.json
│ │ ├── fetch-inspiration.js
│ │ ├── fetch-issues.js
│ │ └── publish-check.js
│ ├── server.js
│ ├── setup.js
│ ├── test-inspiration.js
│ └── test-server.js
├── readme.md
└── website/
├── README.md
├── THEME_LANG_FEATURES.md
├── app/
│ ├── api/
│ │ ├── articles/
│ │ │ ├── [id]/
│ │ │ │ └── route.ts
│ │ │ └── route.ts
│ │ └── categories/
│ │ └── route.ts
│ ├── article/
│ │ └── [id]/
│ │ └── page.tsx
│ ├── components/
│ │ ├── CodeBlock.tsx
│ │ ├── LanguageToggle.tsx
│ │ └── ThemeToggle.tsx
│ ├── contexts/
│ │ └── AppContext.tsx
│ ├── globals.css
│ ├── layout.tsx
│ ├── lib/
│ │ ├── cache.ts
│ │ ├── github.ts
│ │ ├── language.ts
│ │ ├── theme.ts
│ │ └── translations.ts
│ ├── page.tsx
│ ├── test-api/
│ │ └── page.tsx
│ ├── test-demo/
│ │ └── page.tsx
│ ├── test-fixes/
│ │ └── page.tsx
│ └── test-theme-lang/
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── public/
│ └── index.md
├── tailwind.config.js
├── test-features.md
├── tsconfig.json
└── vercel.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.md linguist-language=CSS
*.png linguist-language=CSS
================================================
FILE: MCP/.gitignore
================================================
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Database (keep for npm package)
# data/
*.db
*.sqlite
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
*.lcov
# Dependency directories
node_modules/
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Ignore Cursor IDE local config
.cursor/ .env
================================================
FILE: MCP/LICENSE
================================================
MIT License
Copyright (c) 2024 iCSS MCP Server
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MCP/README.en.md
================================================
# iCSS MCP Server
> 🎨 A comprehensive Model Context Protocol (MCP) server that integrates both [iCSS repository](https://github.com/chokcoco/iCSS) techniques and [CSS-Inspiration](https://github.com/chokcoco/CSS-Inspiration) demos, providing complete CSS solutions with runnable code examples.
[](https://www.npmjs.com/package/icss-mcp-server)
[](https://opensource.org/licenses/MIT)
## 🚀 Quick Start
### Option 1: NPM Installation (Recommended)
```bash
# Install globally
npm install -g icss-mcp-server
# Auto-configure for Cursor
icss-mcp-install
# Start the server (if needed manually)
icss-mcp
```
### Option 2: NPX (No Installation)
```bash
# Run directly
npx icss-mcp-server
# Auto-configure for Cursor
npx icss-mcp-server install
```
### Option 3: Local Development
```bash
# Clone and setup
git clone https://github.com/chokcoco/iCSS.git
cd iCSS/MCP
npm install
npm run setup
npm start
```
## 📋 Features
- 🔍 **Dual Search**: Search both iCSS articles and CSS-Inspiration demos
- 📖 **Article Details**: Access full content of specific iCSS articles
- 🎯 **Demo Code**: Get complete runnable HTML/CSS code from CSS-Inspiration
- 🏷️ **Smart Categories**: Browse by technology type and difficulty level
- 🎲 **Random Discovery**: Get random techniques or demo examples
- 🔧 **Code Snippets**: Extract and manage CSS/HTML code blocks
- 🚀 **Easy Integration**: Auto-configures with Cursor IDE
- 📊 **Performance Analysis**: Browser compatibility and performance insights
## 🛠️ Installation & Configuration
### Automatic Setup
The easiest way is to use the automatic installer:
```bash
npm install -g icss-mcp-server
icss-mcp-install
```
This will:
1. Install the package globally
2. Auto-configure Cursor IDE settings
3. Create necessary database files
4. Verify the installation
### Manual Configuration
If automatic setup doesn't work, you can manually configure Cursor:
1. Create or edit `~/.config/cursor/mcp_settings.json`:
```json
{
"mcpServers": {
"icss": {
"command": "node",
"args": ["/path/to/global/node_modules/icss-mcp-server/server.js"],
"env": {}
}
}
}
```
2. Restart Cursor IDE completely
## 💡 Usage in Cursor
Once installed and configured, you can ask Cursor about CSS techniques:
### Example Queries
#### iCSS Articles
- *"Show me CSS techniques for flex layout"*
- *"Find articles about CSS animations from iCSS"*
- *"How to create gradient borders with CSS?"*
- *"Get details for issue #80"*
#### CSS-Inspiration Demos
- *"Search for 3D effect demonstrations"*
- *"Find animation demos with complete code"*
- *"Show border effect examples"*
- *"Get complete code for demo ID #25"*
#### General Features
- *"Get a random CSS tip"*
- *"What CSS technique categories are available?"*
- *"Show all CSS-Inspiration categories"*
- *"Random animation demo"*
### MCP Functions Available
| Function | Description | Parameters |
|----------|-------------|------------|
| `search_css_techniques` | Search iCSS technique articles | `query`, `limit` (optional) |
| `search_css_demos` | Search CSS-Inspiration demos | `query`, `category` (optional), `difficulty` (optional), `limit` (optional) |
| `get_css_article` | Get full iCSS article content | `issue_number` |
| `get_css_demo` | Get complete demo with code | `demo_id` |
| `list_css_categories` | List all available categories | `source` (optional): icss/inspiration/all |
| `get_random_css_tip` | Get random technique or demo | `source` (optional): icss/inspiration/both |
## 🔧 CLI Commands
After installation, these commands are available:
```bash
# Start MCP server
icss-mcp
# Install/configure for Cursor
icss-mcp-install
# Run setup (create database, fetch data)
npm run setup
# Fetch iCSS article data
npm run build
# Fetch CSS-Inspiration demo data
npm run build:inspiration
# Fetch all data
npm run build:all
# Test server functionality
npm test
```
## 📊 Data Source
### iCSS Technique Library
- **270+ high-quality CSS articles** covering animations, layouts, effects, and performance
- Comprehensive technique explanations with detailed examples
- Source: [iCSS repository](https://github.com/chokcoco/iCSS)
### CSS-Inspiration Demo Library
- **14 categories** of complete CSS demonstrations
- Runnable HTML/CSS code with live examples
- **Difficulty levels**: Beginner, Intermediate, Advanced
- **Browser compatibility** information included
- Source: [CSS-Inspiration repository](https://github.com/chokcoco/CSS-Inspiration)
### Technical Features
- **Fuzzy search** with intelligent matching
- **Smart categorization** by technology and difficulty
- **Automatic code extraction** and snippet management
- **Performance analysis** and browser compatibility insights
- **Regular updates** from both repositories
## 🔍 Troubleshooting
### Common Issues
**1. MCP Server not found in Cursor**
- Ensure Cursor is completely restarted after installation
- Check the config file: `~/.config/cursor/mcp_settings.json`
- Verify the server path in the configuration
**2. Permission errors**
- On macOS/Linux: `chmod +x node_modules/icss-mcp-server/bin/*`
- Run with sudo if needed: `sudo npm install -g icss-mcp-server`
**3. Database issues**
- Run setup again: `npm run setup`
- Check if SQLite3 is properly installed
- Clear and rebuild: `rm -rf data/icss.db && npm run build`
### Debug Mode
Enable debug logging:
```bash
# Set debug environment
export DEBUG=icss-mcp:*
# Run with debug info
icss-mcp
```
### Manual Testing
Test the server directly:
```bash
# Test server functionality
npm test
# Test specific functions
node -e "
import('./server.js').then(async () => {
// Server will start and show debug info
});
"
```
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
### Development Setup
```bash
git clone https://github.com/chokcoco/iCSS.git
cd iCSS/MCP
npm install
npm run setup
npm run dev
```
### Publishing
```bash
npm run prepublishOnly
npm publish
```
## 📄 License
MIT License - see the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments
- [iCSS Repository](https://github.com/chokcoco/iCSS) - Original CSS techniques collection
- [chokcoco](https://github.com/chokcoco) - Creator of iCSS
- [Model Context Protocol](https://github.com/modelcontextprotocol) - MCP specification
- [Cursor IDE](https://cursor.sh/) - AI-powered code editor
## 📞 Support
- 🐛 [Report Issues](https://github.com/chokcoco/iCSS/issues)
- 💬 [Discussions](https://github.com/chokcoco/iCSS/discussions)
- 📚 [iCSS Documentation](https://github.com/chokcoco/iCSS)
---
Made with ❤️ for the CSS community
================================================
FILE: MCP/README.md
================================================
# iCSS MCP Server 中文使用指南
> iCSS MCP Server 是一个基于 Model Context Protocol (MCP) 的服务端,整合了 iCSS 技巧库和 CSS-Inspiration 演示案例,提供 CSS 技巧搜索、分类、文章详情、完整代码演示等能力,支持 Cursor IDE 智能调用。
[](https://www.npmjs.com/package/icss-mcp-server)
[](https://opensource.org/licenses/MIT)
## 🚀 快速开始
### 1. 全局安装(推荐)
```bash
npm install -g icss-mcp-server
icss-mcp-install
# 启动 MCP 服务(如需手动)
icss-mcp
```
### 2. NPX 免安装
```bash
npx icss-mcp-server
npx icss-mcp-server install
```
### 3. 本地开发
```bash
git clone https://github.com/chokcoco/iCSS.git
cd iCSS/MCP
npm install
npm run setup
npm start
```
## 📋 主要功能
- 🔍 **双库搜索**:同时搜索 iCSS 文章和 CSS-Inspiration 演示
- 📖 **文章详情**:获取指定 iCSS 文章的完整内容
- 🎯 **演示代码**:获取 CSS-Inspiration 的完整可运行代码
- 🏷️ **智能分类**:按技术类别、难度级别浏览内容
- 🎲 **随机发现**:随机获取技巧或演示案例
- 🔧 **代码片段**:提取和管理 CSS/HTML 代码块
- 🚀 **一键集成**:自动配置 Cursor IDE
- 📊 **性能分析**:提供浏览器兼容性和性能建议
## 🛠️ 安装与配置
### 自动配置
```bash
npm install -g icss-mcp-server
icss-mcp-install
```
### 手动配置(如自动失败)
编辑 `~/.config/cursor/mcp_settings.json`,添加:
```json
{
"mcpServers": {
"icss": {
"command": "node",
"args": ["/path/to/global/node_modules/icss-mcp-server/server.js"],
"env": {}
}
}
}
```
重启 Cursor IDE。
## 💡 Cursor 智能调用示例
- “查找 flex 布局的 CSS 技巧”
- “iCSS 有哪些动画相关的技巧?”
- “如何实现渐变边框?”
- “来一个随机 CSS 技巧”
- “有哪些 CSS 技巧分类?”
- “获取 issue #1 的详细内容”
## 🧩 MCP 可用工具
| 工具名 | 说明 | 参数 |
|--------|------|------|
| search_css_techniques | 搜索 iCSS 技巧文章 | query, limit(可选) |
| search_css_demos | 搜索 CSS-Inspiration 演示 | query, category(可选), difficulty(可选), limit(可选) |
| get_css_article | 获取 iCSS 文章详情 | issue_number |
| get_css_demo | 获取演示完整代码 | demo_id |
| list_css_categories | 获取所有分类 | source(可选): icss/inspiration/all |
| get_random_css_tip | 随机技巧或演示 | source(可选): icss/inspiration/both |
## 🔧 常用命令
```bash
icss-mcp # 启动 MCP 服务
icss-mcp-install # 自动配置 Cursor
npm run setup # 初始化数据库
npm run build # 拉取 iCSS 文章数据
npm run build:inspiration # 拉取 CSS-Inspiration 演示数据
npm run build:all # 拉取所有数据
npm test # 测试服务
```
## 📊 数据来源
### iCSS 技巧库
- 超过 270 篇高质量 CSS 技巧文章
- 涵盖动画、布局、特效、性能优化等主题
- 原始仓库:[iCSS](https://github.com/chokcoco/iCSS)
### CSS-Inspiration 演示库
- 包含 14 个分类的完整 CSS 演示
- 提供可运行的 HTML/CSS 代码
- 按难度级别分类(初级/中级/高级)
- 包含浏览器兼容性信息
- 原始仓库:[CSS-Inspiration](https://github.com/chokcoco/CSS-Inspiration)
### 技术特性
- 支持模糊搜索、智能分类
- 自动提取代码片段
- 性能分析和优化建议
- 定期同步最新内容
## ❓ 常见问题
1. **Cursor 未识别 MCP Server**
- 检查配置文件路径和 server.js 路径
- 完全重启 Cursor
2. **数据库报错**
- 运行 `npm run setup` 重新初始化
3. **权限问题**
- macOS/Linux 下 `chmod +x node_modules/icss-mcp-server/bin/*`
## 📝 贡献与支持
- 欢迎 PR 和 Issue
- [iCSS 讨论区](https://github.com/chokcoco/iCSS/discussions)
- [原文档/英文版](./README.en.md)
---
Made with ❤️ for the CSS community
================================================
FILE: MCP/bin/icss-mcp.js
================================================
#!/usr/bin/env node
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { spawn } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const serverPath = join(__dirname, '..', 'server.js');
console.log('🚀 Starting iCSS MCP Server v1.1.1...');
console.log('📚 Integrating iCSS techniques + CSS-Inspiration demos');
// 启动 MCP 服务器
const server = spawn('node', [serverPath], {
stdio: 'inherit',
env: process.env
});
server.on('error', (error) => {
console.error('❌ Failed to start iCSS MCP Server:', error);
console.error('💡 Try running: npm install -g icss-mcp-server');
process.exit(1);
});
server.on('close', (code) => {
if (code !== 0) {
console.error(`❌ Server exited with code ${code}`);
console.error('💡 For help, visit: https://github.com/chokcoco/iCSS/tree/main/MCP');
}
process.exit(code);
});
// 处理进程信号
process.on('SIGINT', () => {
console.log('\n⏹️ Shutting down iCSS MCP Server...');
server.kill('SIGINT');
});
process.on('SIGTERM', () => {
console.log('\n⏹️ Shutting down iCSS MCP Server...');
server.kill('SIGTERM');
});
// 显示帮助信息
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(`
iCSS MCP Server v1.1.1 - CSS Techniques & Demos
Usage:
icss-mcp Start the MCP server
icss-mcp-install Install for Cursor IDE
Features:
• 270+ CSS technique articles from iCSS
• 160+ complete CSS demos from CSS-Inspiration
• Smart search and categorization
• Complete runnable code examples
For more information:
https://github.com/chokcoco/iCSS/tree/main/MCP
`);
process.exit(0);
}
================================================
FILE: MCP/bin/install.js
================================================
#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
import os from 'os';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
console.log('🚀 Installing iCSS MCP Server v1.1.1 for Cursor...\n');
// 获取 Cursor 配置目录
function getCursorConfigPath() {
const platform = process.platform;
const homeDir = os.homedir();
switch (platform) {
case 'darwin': // macOS
return path.join(homeDir, '.config', 'cursor');
case 'win32': // Windows
return path.join(homeDir, 'AppData', 'Roaming', 'Cursor', 'User');
case 'linux': // Linux
return path.join(homeDir, '.config', 'cursor');
default:
throw new Error(`Unsupported platform: ${platform}`);
}
}
// 获取包的绝对路径
function getPackagePath() {
// 从 node_modules/@icss/mcp-server/bin/install.js 回到包根目录
return path.resolve(__dirname, '..');
}
// 创建或更新 MCP 配置
function updateMcpConfig() {
try {
const configDir = getCursorConfigPath();
const configFile = path.join(configDir, 'mcp_settings.json');
// 确保配置目录存在
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
console.log(`✅ Created Cursor config directory: ${configDir}`);
}
// 读取现有配置或创建新配置
let config = { mcpServers: {} };
if (fs.existsSync(configFile)) {
try {
const existingConfig = fs.readFileSync(configFile, 'utf8');
config = JSON.parse(existingConfig);
console.log('📝 Found existing MCP configuration');
} catch (err) {
console.warn('⚠️ Existing config file is invalid, creating new one');
}
}
// 确保 mcpServers 对象存在
if (!config.mcpServers) {
config.mcpServers = {};
}
// 添加或更新 iCSS MCP Server 配置
const packagePath = getPackagePath();
const serverPath = path.join(packagePath, 'server.js');
config.mcpServers.icss = {
command: "node",
args: [serverPath],
env: {}
};
// 写入配置文件
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
console.log(`✅ Updated MCP configuration: ${configFile}`);
return configFile;
} catch (error) {
console.error('❌ Failed to update MCP configuration:', error.message);
throw error;
}
}
// 验证安装
function verifyInstallation() {
try {
const packagePath = getPackagePath();
const serverPath = path.join(packagePath, 'server.js');
const dbPath = path.join(packagePath, 'data', 'icss.db');
console.log('\n🔍 Verifying installation...');
if (!fs.existsSync(serverPath)) {
throw new Error(`Server file not found: ${serverPath}`);
}
console.log('✅ Server file exists');
if (!fs.existsSync(dbPath)) {
console.log('⚠️ Database not found, will be created on first run');
} else {
console.log('✅ Database file exists');
}
// 检查新增的脚本文件
const inspirationScript = path.join(packagePath, 'scripts', 'fetch-inspiration.js');
if (fs.existsSync(inspirationScript)) {
console.log('✅ CSS-Inspiration integration script exists');
}
const testInspiration = path.join(packagePath, 'test-inspiration.js');
if (fs.existsSync(testInspiration)) {
console.log('✅ CSS-Inspiration test script exists');
}
console.log('✅ Installation verified');
} catch (error) {
console.error('❌ Installation verification failed:', error.message);
throw error;
}
}
// 显示使用说明
function showUsageInstructions(configFile) {
console.log('\n🎉 Installation completed successfully!\n');
console.log('🆕 What\'s new in v1.1.1:');
console.log(' - 🎨 Integrated CSS-Inspiration with 160+ complete demos');
console.log(' - 🔍 Search both iCSS articles and CSS-Inspiration demos');
console.log(' - 💾 Complete runnable code for all demos');
console.log(' - 📊 Smart categorization by difficulty and type\n');
console.log('📋 Next steps:');
console.log('1. Restart Cursor IDE completely');
console.log('2. The iCSS MCP Server should be available automatically');
console.log('3. Try asking Cursor about CSS techniques from both libraries\n');
console.log('🛠️ Configuration details:');
console.log(` Config file: ${configFile}`);
console.log(` Server path: ${path.join(getPackagePath(), 'server.js')}`);
console.log('\n💡 Enhanced usage examples:');
console.log(' - "Show me CSS techniques for flex layout"');
console.log(' - "Find 3D animation demos from CSS-Inspiration"');
console.log(' - "Get complete code for demo ID 25"');
console.log(' - "Search for border effects with runnable code"');
console.log(' - "Get a random CSS tip from both libraries"');
console.log('\n🔧 Manual testing:');
console.log(' Run: npx icss-mcp-server');
console.log(' Or: icss-mcp');
console.log('\n📚 More info: https://github.com/chokcoco/iCSS');
console.log('📚 CSS-Inspiration: https://github.com/chokcoco/CSS-Inspiration');
}
// 主安装流程
async function main() {
try {
// 更新配置
const configFile = updateMcpConfig();
// 验证安装
verifyInstallation();
// 显示说明
showUsageInstructions(configFile);
} catch (error) {
console.error('\n❌ Installation failed:', error.message);
console.error('\n🔧 Manual setup instructions:');
console.error('1. Create ~/.config/cursor/mcp_settings.json');
console.error('2. Add the following configuration:');
console.error(JSON.stringify({
mcpServers: {
icss: {
command: "node",
args: [path.join(getPackagePath(), 'server.js')],
env: {}
}
}
}, null, 2));
process.exit(1);
}
}
// 如果直接运行此脚本
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
================================================
FILE: MCP/debug-interactive.js
================================================
#!/usr/bin/env node
import { spawn } from 'child_process';
import path from 'path';
import { fileURLToPath } from 'url';
import readline from 'readline';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 创建readline接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log('🔄 Starting MCP Server...');
// 启动服务器进程
const serverProcess = spawn('node', ['debug-local.js'], {
cwd: __dirname,
stdio: ['pipe', 'pipe', 'inherit']
});
let serverReady = false;
// 监听服务器输出
serverProcess.stdout.on('data', (data) => {
const output = data.toString();
// 检查服务器是否准备好
if (output.includes('Search index loaded with') && !serverReady) {
serverReady = true;
console.log('\n🚀 Server is ready! You can now send commands.');
showPrompt();
}
});
// 显示命令提示
function showPrompt() {
console.log('\n📝 Available commands:');
console.log('1. List all tools');
console.log('2. Search CSS techniques');
console.log('3. Get random CSS tip');
console.log('4. Custom command');
console.log('5. Exit');
rl.question('\n👉 Enter command number: ', (answer) => {
switch(answer) {
case '1':
sendCommand({
jsonrpc: "2.0",
id: 1,
method: "tools/list",
params: {}
});
break;
case '2':
rl.question('Enter search query: ', (query) => {
sendCommand({
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: {
name: "search_css_techniques",
arguments: {
query: query,
limit: 3
}
}
});
});
break;
case '3':
sendCommand({
jsonrpc: "2.0",
id: 3,
method: "tools/call",
params: {
name: "get_random_css_tip",
arguments: {}
}
});
break;
case '4':
rl.question('Enter custom JSON-RPC command: ', (cmd) => {
try {
const command = JSON.parse(cmd);
sendCommand(command);
} catch (e) {
console.error('❌ Invalid JSON:', e.message);
showPrompt();
}
});
break;
case '5':
console.log('👋 Shutting down server...');
serverProcess.kill();
rl.close();
process.exit(0);
break;
default:
console.log('❌ Invalid command number');
showPrompt();
}
});
}
// 发送命令到服务器
function sendCommand(command) {
console.log('\n📤 Sending command:', JSON.stringify(command, null, 2));
serverProcess.stdin.write(JSON.stringify(command) + '\n');
setTimeout(showPrompt, 1000);
}
// 处理退出
process.on('SIGINT', () => {
console.log('\n👋 Shutting down server...');
serverProcess.kill();
rl.close();
process.exit(0);
});
serverProcess.on('error', (error) => {
console.error('❌ Server error:', error);
rl.close();
process.exit(1);
});
================================================
FILE: MCP/debug-local.js
================================================
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import Database from 'sqlite3';
import Fuse from 'fuse.js';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 调试模式
const DEBUG = true;
const debugLog = (...args) => {
if (DEBUG) {
console.error(`[DEBUG ${new Date().toISOString()}]`, ...args);
}
};
class IcssDebugServer {
constructor() {
debugLog('🚀 Initializing iCSS Debug Server');
this.server = new Server(
{
name: 'icss-debug-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.transport = null;
this.db = null;
this.searchEngine = null;
this.isReady = false;
this.dbInitFailed = false;
this.setupDatabase();
this.setupHandlers();
}
setupDatabase() {
debugLog('📂 Setting up database connection...');
const dbPath = path.join(__dirname, 'data', 'icss.db');
debugLog(`📍 Database path: ${dbPath}`);
this.db = new Database.Database(dbPath, (err) => {
if (err) {
console.error('❌ Error opening database:', err);
this.dbInitFailed = true;
} else {
debugLog('✅ Connected to SQLite database');
this.loadSearchIndex();
}
});
}
loadSearchIndex() {
debugLog('🔍 Loading search index...');
const query = `
SELECT
i.*,
GROUP_CONCAT(DISTINCT al.label) as tags,
GROUP_CONCAT(DISTINCT al.category) as categories,
GROUP_CONCAT(DISTINCT al.weight) as weights,
GROUP_CONCAT(DISTINCT lc.description) as tag_descriptions
FROM issues i
LEFT JOIN article_labels al ON i.number = al.issue_number
LEFT JOIN label_categories lc ON al.label = lc.label
GROUP BY i.number
`;
this.db.all(query, [], (err, rows) => {
if (err) {
console.error('❌ Error loading search index:', err);
this.dbInitFailed = true;
return;
}
debugLog(`📊 Loaded ${rows.length} articles for search index`);
// 处理数据
const processedRows = rows.map(row => {
const tags = row.tags ? row.tags.split(',') : [];
const categories = row.categories ? row.categories.split(',') : [];
const weights = row.weights ? row.weights.split(',').map(Number) : [];
const descriptions = row.tag_descriptions ? row.tag_descriptions.split(',') : [];
// 解析 JSON 格式的标签
let labels = [];
try {
labels = row.labels ? JSON.parse(row.labels) : [];
} catch (e) {
debugLog(`⚠️ Failed to parse labels for issue #${row.number}`);
}
return {
...row,
tags,
categories,
weights,
descriptions,
labels,
// 合并所有可搜索的文本
searchContent: [
row.title,
row.body,
...tags,
...categories,
...descriptions,
...labels
].filter(Boolean).join(' ')
};
});
const fuseOptions = {
keys: [
{ name: 'title', weight: 0.4 },
{ name: 'searchContent', weight: 0.3 },
{ name: 'tags', weight: 0.2 },
{ name: 'categories', weight: 0.1 }
],
threshold: 0.3,
includeScore: true,
includeMatches: true
};
this.searchEngine = new Fuse(processedRows, fuseOptions);
this.isReady = true;
debugLog(`🎉 Search index loaded with ${rows.length} articles - Server ready!`);
});
}
async waitForReady(timeout = 10000) {
debugLog(`⏳ Waiting for server to be ready (timeout: ${timeout}ms)`);
const startTime = Date.now();
while (!this.isReady && !this.dbInitFailed) {
if (Date.now() - startTime > timeout) {
throw new McpError(
ErrorCode.InternalError,
'Server initialization timeout'
);
}
await new Promise(resolve => setTimeout(resolve, 100));
}
if (this.dbInitFailed) {
throw new McpError(
ErrorCode.InternalError,
'Server initialization failed'
);
}
}
setupHandlers() {
debugLog('🔗 Setting up request handlers...');
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
try {
debugLog('📋 Received ListTools request');
await this.waitForReady();
const tools = [
{
name: 'search_css_techniques',
description: 'Search for CSS techniques with filtering and sorting options',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query'
},
categories: {
type: 'array',
items: { type: 'string' },
description: 'Filter by categories'
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Filter by tags'
},
min_weight: {
type: 'number',
description: 'Minimum tag weight'
},
limit: {
type: 'number',
default: 10
}
},
required: ['query']
}
}
];
return { tools };
} catch (error) {
debugLog('❌ Error in ListTools:', error);
throw error;
}
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
debugLog(`🔧 Received CallTool request: ${name}`, args);
try {
await this.waitForReady();
switch (name) {
case 'search_css_techniques':
return await this.searchCssTechniques(args);
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error) {
debugLog(`❌ Error in ${name}:`, error);
throw error;
}
});
}
async searchCssTechniques({ query, categories = [], tags = [], min_weight, limit = 10 }) {
debugLog(`🔍 Searching CSS techniques: "${query}"`);
if (!this.searchEngine) {
throw new McpError(
ErrorCode.InternalError,
'Search engine not initialized'
);
}
let results = this.searchEngine.search(query);
debugLog(`📊 Found ${results.length} initial results`);
// 过滤结果
if (categories.length > 0) {
results = results.filter(result =>
result.item.categories.some(cat =>
categories.some(c => cat.toLowerCase().includes(c.toLowerCase()))
)
);
debugLog(`📊 After category filter: ${results.length} results`);
}
if (tags.length > 0) {
results = results.filter(result =>
tags.every(tag =>
result.item.tags.some(t => t.toLowerCase().includes(tag.toLowerCase()))
)
);
debugLog(`📊 After tag filter: ${results.length} results`);
}
if (min_weight) {
results = results.filter(result =>
result.item.weights.some(w => w >= min_weight)
);
debugLog(`📊 After weight filter: ${results.length} results`);
}
// 格式化结果
const formattedResults = results.slice(0, limit).map(result => {
const item = result.item;
return {
title: item.title,
number: item.number,
url: item.html_url,
relevance: Math.round((1 - result.score) * 100),
tags: item.tags.map((tag, i) => ({
name: tag,
category: item.categories[i] || 'other',
weight: item.weights[i] || 1.0,
description: item.descriptions[i] || ''
})),
preview: this.extractPreview(item.body),
updated_at: item.updated_at
};
});
debugLog(`✅ Returning ${formattedResults.length} formatted results`);
return {
content: [
{
type: 'text',
text: `Found ${formattedResults.length} CSS techniques for "${query}":\n\n` +
formattedResults.map((result, index) =>
`${index + 1}. **${result.title}** (Issue #${result.number})\n` +
` 📅 Updated: ${new Date(result.updated_at).toLocaleDateString()}\n` +
` 💯 Relevance: ${result.relevance}%\n` +
` 🏷️ Tags:\n${result.tags.map(tag =>
` - ${tag.name} (${tag.category}, weight: ${tag.weight.toFixed(2)})` +
(tag.description ? `\n ${tag.description}` : '')
).join('\n')}\n` +
` 📝 Preview: ${result.preview}\n` +
` 🔗 Link: ${result.url}\n`
).join('\n')
}
]
};
}
extractPreview(body, maxLength = 200) {
if (!body) return 'No preview available';
const cleanText = body
.replace(/```[\s\S]*?```/g, '[code block]')
.replace(/`([^`]+)`/g, '$1')
.replace(/[#*_~]/g, '')
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
.replace(/\s+/g, ' ')
.trim();
return cleanText.length > maxLength
? cleanText.substring(0, maxLength - 3) + '...'
: cleanText;
}
async run() {
debugLog('🚀 Starting debug server...');
this.transport = new StdioServerTransport();
try {
await this.server.connect(this.transport);
debugLog('✅ Server connected to transport');
// 保持进程运行
process.stdin.resume();
// 处理进程退出
process.on('SIGINT', () => this.cleanup());
process.on('SIGTERM', () => this.cleanup());
} catch (error) {
debugLog('💥 Server error:', error);
console.error('❌ Fatal error:', error.message);
process.exit(1);
}
}
cleanup() {
debugLog('🧹 Cleaning up...');
if (this.db) {
this.db.close();
}
if (this.transport) {
this.transport.close();
}
process.exit(0);
}
}
// 启动服务器
const server = new IcssDebugServer();
server.run();
================================================
FILE: MCP/debug-query.js
================================================
#!/usr/bin/env node
import { spawn } from 'child_process';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 测试查询列表
const testQueries = [
{
name: 'List Tools',
query: {
jsonrpc: "2.0",
id: 1,
method: "tools/list",
params: {}
}
},
{
name: 'Search Border Techniques',
query: {
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: {
name: "search_css_techniques",
arguments: {
query: "border",
categories: ["visual_effects"],
limit: 3
}
}
}
},
{
name: 'Search Animation Techniques',
query: {
jsonrpc: "2.0",
id: 3,
method: "tools/call",
params: {
name: "search_css_techniques",
arguments: {
query: "animation",
categories: ["animation"],
limit: 3
}
}
}
},
{
name: 'Search High Weight Techniques',
query: {
jsonrpc: "2.0",
id: 4,
method: "tools/call",
params: {
name: "search_css_techniques",
arguments: {
query: "",
min_weight: 3,
limit: 3
}
}
}
}
];
// 创建一个Promise来处理服务器响应
function queryServer(command) {
return new Promise((resolve, reject) => {
console.log('\n🔄 Starting debug server process...');
const serverProcess = spawn('node', ['debug-local.js'], {
cwd: __dirname,
stdio: ['pipe', 'pipe', 'inherit']
});
let responseData = '';
let serverReady = false;
// 监听服务器输出
serverProcess.stdout.on('data', (data) => {
const output = data.toString();
console.log('📝 Server output:', output);
// 检查服务器是否已经准备好
if (output.includes('Search index loaded with') && !serverReady) {
serverReady = true;
console.log('\n🚀 Server is ready, sending query...');
// 发送命令
console.log('\n📤 Sending query:', JSON.stringify(command, null, 2));
serverProcess.stdin.write(JSON.stringify(command) + '\n');
}
// 尝试解析响应
try {
if (output.includes('"result"') || output.includes('"error"')) {
const jsonStart = output.indexOf('{');
const jsonEnd = output.lastIndexOf('}') + 1;
if (jsonStart !== -1 && jsonEnd !== -1) {
const jsonStr = output.substring(jsonStart, jsonEnd);
const response = JSON.parse(jsonStr);
console.log('\n✅ Received response:', JSON.stringify(response, null, 2));
// 关闭服务器
serverProcess.kill();
if (response.error) {
reject(new Error(response.error.message));
} else {
resolve(response);
}
}
}
} catch (e) {
console.log('⚠️ Parse error:', e.message);
}
});
// 错误处理
serverProcess.on('error', (error) => {
console.error('❌ Server process error:', error);
reject(error);
});
// 设置超时
setTimeout(() => {
if (!serverReady) {
console.log('\n⚠️ Server never became ready');
}
console.log('\n⚠️ Query timeout, shutting down server...');
serverProcess.kill();
reject(new Error('Query timeout'));
}, 15000);
});
}
// 运行所有测试查询
async function runTests() {
console.log('🧪 Starting test queries...\n');
for (const test of testQueries) {
console.log(`\n📋 Running test: ${test.name}`);
try {
const response = await queryServer(test.query);
console.log('\n✅ Response:', JSON.stringify(response, null, 2));
} catch (error) {
console.error('\n❌ Error:', error.message);
}
// 等待一下,避免服务器进程冲突
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log('\n🎉 All tests completed!');
}
// 执行测试
runTests().catch(error => {
console.error('❌ Test execution error:', error);
process.exit(1);
});
================================================
FILE: MCP/debug.js
================================================
#!/usr/bin/env node
import Database from 'sqlite3';
import Fuse from 'fuse.js';
console.log('🔍 MCP Server Debug Tool\n');
class DebugTester {
constructor() {
this.db = null;
this.searchEngine = null;
this.isReady = false;
}
async init() {
return new Promise((resolve, reject) => {
console.log('📂 Connecting to database...');
this.db = new Database.Database('./data/icss.db', (err) => {
if (err) {
console.error('❌ Database connection failed:', err.message);
reject(err);
return;
}
console.log('✅ Database connected');
this.loadSearchIndex().then(resolve).catch(reject);
});
});
}
async loadSearchIndex() {
return new Promise((resolve, reject) => {
console.log('🔄 Loading search index...');
this.db.all('SELECT * FROM issues', (err, rows) => {
if (err) {
console.error('❌ Failed to load search index:', err.message);
reject(err);
return;
}
console.log(`📊 Loaded ${rows.length} articles`);
const fuseOptions = {
keys: [
{ name: 'title', weight: 0.4 },
{ name: 'search_content', weight: 0.4 },
{ name: 'labels', weight: 0.2 }
],
threshold: 0.3,
includeScore: true,
includeMatches: true
};
this.searchEngine = new Fuse(rows, fuseOptions);
this.isReady = true;
console.log('✅ Search index ready');
resolve();
});
});
}
async testSearchFunction(query = "透明 边框") {
console.log(`\n🔍 Testing search for: "${query}"`);
if (!this.isReady) {
console.error('❌ Search engine not ready');
return;
}
const startTime = Date.now();
try {
const results = this.searchEngine.search(query).slice(0, 5);
const endTime = Date.now();
console.log(`⏱️ Search completed in ${endTime - startTime}ms`);
console.log(`📋 Found ${results.length} results`);
results.forEach((result, index) => {
const item = result.item;
console.log(`\n${index + 1}. ${item.title}`);
console.log(` Issue #${item.number}`);
console.log(` Score: ${Math.round((1 - result.score) * 100)}%`);
console.log(` URL: ${item.html_url}`);
if (result.matches) {
console.log(` Matches: ${result.matches.length}`);
result.matches.forEach(match => {
console.log(` - ${match.key}: ${match.value?.substring(0, 50)}...`);
});
}
});
return results;
} catch (error) {
console.error('❌ Search failed:', error.message);
console.error(error.stack);
}
}
async testSpecificArticle(issueNumber = 1) {
console.log(`\n📄 Testing get article #${issueNumber}`);
return new Promise((resolve, reject) => {
this.db.get(
'SELECT * FROM issues WHERE number = ?',
[issueNumber],
(err, row) => {
if (err) {
console.error('❌ Database query failed:', err.message);
reject(err);
return;
}
if (!row) {
console.error(`❌ Article #${issueNumber} not found`);
reject(new Error('Article not found'));
return;
}
console.log('✅ Article found:');
console.log(` Title: ${row.title}`);
console.log(` Created: ${row.created_at}`);
console.log(` Updated: ${row.updated_at}`);
console.log(` Body length: ${row.body?.length || 0} chars`);
resolve(row);
}
);
});
}
async testCategories() {
console.log('\n🏷️ Testing categories listing');
return new Promise((resolve, reject) => {
this.db.all(
'SELECT labels, COUNT(*) as count FROM issues WHERE labels IS NOT NULL GROUP BY labels LIMIT 10',
(err, rows) => {
if (err) {
console.error('❌ Categories query failed:', err.message);
reject(err);
return;
}
console.log(`✅ Found ${rows.length} label groups`);
const categoryMap = new Map();
rows.forEach(row => {
if (row.labels) {
try {
const labels = JSON.parse(row.labels);
labels.forEach(label => {
categoryMap.set(label, (categoryMap.get(label) || 0) + row.count);
});
} catch (parseErr) {
console.warn(`⚠️ Failed to parse labels: ${row.labels}`);
}
}
});
const topCategories = Array.from(categoryMap.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
console.log('📊 Top categories:');
topCategories.forEach(([label, count]) => {
console.log(` • ${label}: ${count} articles`);
});
resolve(topCategories);
}
);
});
}
close() {
if (this.db) {
this.db.close();
console.log('📚 Database connection closed');
}
}
}
// 运行调试测试
async function runDebugTests() {
const tester = new DebugTester();
try {
await tester.init();
// 测试搜索功能 - 用你想要的查询
await tester.testSearchFunction("透明 边框");
await tester.testSearchFunction("border radius");
await tester.testSearchFunction("镂空");
// 测试获取文章
await tester.testSpecificArticle(1);
// 测试分类
await tester.testCategories();
console.log('\n🎉 All debug tests completed successfully!');
} catch (error) {
console.error('\n❌ Debug test failed:', error.message);
console.error(error.stack);
} finally {
tester.close();
}
}
// 如果直接运行此脚本
if (import.meta.url === `file://${process.argv[1]}`) {
runDebugTests();
}
================================================
FILE: MCP/diagnose-mcp.js
================================================
#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
import { spawn } from 'child_process';
console.log('🔧 Comprehensive MCP Diagnosis Tool\n');
// 检查所有可能的 Cursor MCP 配置位置
function checkCursorConfigs() {
console.log('1️⃣ Checking Cursor MCP Configuration Locations:\n');
const possiblePaths = [
'~/.config/cursor/mcp_settings.json',
'~/Library/Application Support/Cursor/mcp_settings.json',
'~/.cursor/mcp_settings.json',
process.env.HOME + '/.config/cursor/mcp_settings.json',
process.env.HOME + '/Library/Application Support/Cursor/mcp_settings.json'
];
let foundConfigs = 0;
possiblePaths.forEach(configPath => {
const expandedPath = configPath.startsWith('~') ?
configPath.replace('~', process.env.HOME) : configPath;
if (fs.existsSync(expandedPath)) {
foundConfigs++;
console.log(` ✅ Found: ${configPath}`);
try {
const content = fs.readFileSync(expandedPath, 'utf8');
const config = JSON.parse(content);
console.log(` Servers: ${Object.keys(config.mcpServers || {}).join(', ')}`);
} catch (err) {
console.log(` ❌ Invalid JSON: ${err.message}`);
}
} else {
console.log(` ❌ Not found: ${configPath}`);
}
});
if (foundConfigs === 0) {
console.log('\n ⚠️ No MCP configuration files found!');
}
return foundConfigs > 0;
}
// 检查服务器可执行性
function checkServerExecutability() {
console.log('\n2️⃣ Checking Server Executability:\n');
const serverPath = path.resolve('./server.js');
console.log(` Server path: ${serverPath}`);
if (!fs.existsSync(serverPath)) {
console.log(' ❌ server.js not found');
return false;
}
console.log(' ✅ server.js exists');
// 检查权限
try {
fs.accessSync(serverPath, fs.constants.R_OK);
console.log(' ✅ server.js is readable');
} catch (err) {
console.log(' ❌ server.js is not readable');
return false;
}
return true;
}
// 手动测试 MCP 协议
function testMCPProtocol() {
console.log('\n3️⃣ Testing MCP Protocol Manually:\n');
return new Promise((resolve) => {
const serverProcess = spawn('node', ['./server.js'], {
stdio: ['pipe', 'pipe', 'pipe']
});
let stdout = '';
let stderr = '';
serverProcess.stdout.on('data', (data) => {
stdout += data.toString();
});
serverProcess.stderr.on('data', (data) => {
stderr += data.toString();
});
// 发送 MCP 初始化请求
const initRequest = JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2024-11-05",
capabilities: {},
clientInfo: {
name: "test-client",
version: "1.0.0"
}
}
}) + '\n';
serverProcess.stdin.write(initRequest);
// 等待响应
setTimeout(() => {
serverProcess.kill();
console.log(' 📤 Sent initialization request');
if (stdout.trim()) {
console.log(' ✅ Got stdout response:');
console.log(` ${stdout.trim()}`);
} else {
console.log(' ❌ No stdout response');
}
if (stderr.trim()) {
console.log(' ⚠️ Got stderr:');
console.log(` ${stderr.trim()}`);
}
resolve(stdout.length > 0);
}, 3000);
});
}
// 生成正确的配置
function generateCorrectConfig() {
console.log('\n4️⃣ Generating Correct Configuration:\n');
const serverPath = path.resolve('./server.js');
const configs = [
{
path: process.env.HOME + '/.config/cursor/mcp_settings.json',
content: {
mcpServers: {
icss: {
command: "node",
args: [serverPath],
env: {}
}
}
}
},
{
path: process.env.HOME + '/Library/Application Support/Cursor/mcp_settings.json',
content: {
mcpServers: {
icss: {
command: "node",
args: [serverPath],
env: {}
}
}
}
}
];
configs.forEach((config, index) => {
console.log(` 📝 Config ${index + 1}: ${config.path}`);
// 确保目录存在
const dir = path.dirname(config.path);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
console.log(` ✅ Created directory: ${dir}`);
}
// 写入配置
try {
fs.writeFileSync(config.path, JSON.stringify(config.content, null, 2));
console.log(` ✅ Written configuration`);
} catch (err) {
console.log(` ❌ Failed to write: ${err.message}`);
}
});
console.log('\n 💡 Try both locations and restart Cursor completely');
}
// 提供故障排除建议
function provideTroubleshootingTips() {
console.log('\n5️⃣ Troubleshooting Tips:\n');
const tips = [
'1. 完全退出 Cursor (Cmd+Q),然后重新启动',
'2. 检查 Cursor 版本是否支持 MCP (需要较新版本)',
'3. 在 Cursor 中按 Cmd+Option+I 打开开发者工具,检查 Console 错误',
'4. 尝试在 Cursor 设置中查看 MCP 相关配置',
'5. 确保没有其他 MCP 服务器冲突',
'6. 如果使用 VS Code,确保安装了正确的 Cursor 而不是 VS Code'
];
tips.forEach(tip => console.log(` ${tip}`));
console.log('\n 🔧 Manual Test Command:');
console.log(` cd ${process.cwd()}`);
console.log(' echo \'{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\' | node server.js');
}
// 主诊断流程
async function runDiagnosis() {
console.log('Starting comprehensive MCP diagnosis...\n');
const hasConfig = checkCursorConfigs();
const serverWorks = checkServerExecutability();
if (serverWorks) {
const protocolWorks = await testMCPProtocol();
console.log(`\n MCP Protocol Test: ${protocolWorks ? '✅ Working' : '❌ Failed'}`);
}
generateCorrectConfig();
provideTroubleshootingTips();
console.log('\n🎯 Summary:');
console.log(` Config Found: ${hasConfig ? '✅' : '❌'}`);
console.log(` Server Works: ${serverWorks ? '✅' : '❌'}`);
console.log('\n📚 Next: Restart Cursor completely and try again');
}
// 运行诊断
runDiagnosis().catch(console.error);
================================================
FILE: MCP/package.json
================================================
{
"name": "icss-mcp-server",
"version": "1.1.1",
"description": "Comprehensive MCP Server integrating iCSS techniques and CSS-Inspiration demos - provides complete CSS solutions with runnable code",
"main": "server.js",
"bin": {
"icss-mcp": "./bin/icss-mcp.js",
"icss-mcp-install": "./bin/install.js"
},
"type": "module",
"files": [
"server.js",
"setup.js",
"bin/",
"scripts/",
"data/",
"README.md",
"README.en.md",
"LICENSE"
],
"scripts": {
"setup": "node setup.js",
"start": "node server.js",
"dev": "nodemon server.js",
"build": "node scripts/fetch-issues.js",
"build:inspiration": "node scripts/fetch-inspiration.js",
"build:all": "npm run build && npm run build:inspiration",
"test": "node test-server.js",
"test:inspiration": "node test-inspiration.js",
"test:all": "npm run test && npm run test:inspiration",
"install-mcp": "node bin/install.js",
"postinstall": "node setup.js",
"prepublishOnly": "npm run build:all && npm test"
},
"keywords": [
"mcp",
"css",
"frontend",
"cursor",
"icss",
"css-inspiration",
"model-context-protocol",
"ai-tools",
"css-techniques",
"css-demos",
"web-development",
"css-examples",
"chokcoco"
],
"author": {
"name": "iCSS MCP Server",
"email": "icss-mcp@example.com",
"url": "https://github.com/chokcoco/iCSS"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/chokcoco/iCSS.git",
"directory": "MCP"
},
"homepage": "https://github.com/chokcoco/iCSS/tree/main/MCP",
"bugs": {
"url": "https://github.com/chokcoco/iCSS/issues"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.4.0",
"axios": "^1.10.0",
"cheerio": "^1.0.0-rc.12",
"dotenv": "^16.6.1",
"fuse.js": "^7.0.0",
"marked": "^9.1.6",
"sqlite3": "^5.1.7"
},
"devDependencies": {
"nodemon": "^3.0.1"
},
"peerDependencies": {
"node": ">=18.0.0"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}
================================================
FILE: MCP/scripts/cursor-config.json
================================================
{
"mcpServers": {
"icss": {
"command": "node",
"args": ["/Users/qi.qiao/Documents/Git/icss/MCP/server.js"],
"cwd": "/Users/qi.qiao/Documents/Git/icss/MCP",
"env": {
"DEBUG": "true"
},
"description": "iCSS repository CSS techniques and solutions"
}
},
"_alternatives": {
"comment": "Alternative configurations based on your setup:",
"option1_absolute_path": {
"args": ["/Users/qi.qiao/Documents/Git/icss/MCP/server.js"]
},
"option2_if_cursor_in_root": {
"args": ["./MCP/server.js"]
},
"option3_with_cwd": {
"args": ["server.js"],
"cwd": "./MCP"
}
},
"_instructions": {
"setup": "Copy the 'mcpServers' section to your Cursor settings.json",
"location_mac": "~/Library/Application Support/Cursor/User/settings.json",
"location_windows": "%APPDATA%/Cursor/User/settings.json",
"location_linux": "~/.config/Cursor/User/settings.json"
}
}
================================================
FILE: MCP/scripts/fetch-inspiration.js
================================================
import axios from 'axios';
import Database from 'sqlite3';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class InspirationFetcher {
constructor() {
this.baseURL = 'https://api.github.com/repos/chokcoco/CSS-Inspiration';
this.rawURL = 'https://raw.githubusercontent.com/chokcoco/CSS-Inspiration/master';
this.dbPath = path.join(__dirname, '../data/icss.db');
this.dataDir = path.join(__dirname, '../data');
// GitHub Token
this.githubToken = process.env.GITHUB_TOKEN;
if (!this.githubToken) {
console.warn('⚠️ No GITHUB_TOKEN found in environment variables. API rate limits will be restricted.');
}
// 确保数据目录存在
if (!fs.existsSync(this.dataDir)) {
fs.mkdirSync(this.dataDir, { recursive: true });
}
// 初始化数据库连接
this.db = new Database.Database(this.dbPath, (err) => {
if (err) {
console.error('❌ Error opening database:', err);
process.exit(1);
}
});
// CSS-Inspiration 分类映射
this.categoryMapping = {
'3d': '3D 效果',
'animation': '动画效果',
'background': '背景效果',
'blendmode': '混合模式',
'border': '边框效果',
'clippath': '裁剪路径',
'cssdoodle': 'CSS-doodle',
'filter': '滤镜效果',
'layout': '布局技术',
'others': '综合技巧',
'pesudo': '伪类/伪元素',
'shadow': '阴影效果',
'svg': 'SVG 技术',
'text': '文字效果'
};
this.initializeDatabase();
}
initializeDatabase() {
console.log('🔧 Initializing CSS-Inspiration tables...');
// CSS-Inspiration 项目表
const createInspirationTableSQL = `
CREATE TABLE IF NOT EXISTS css_inspiration (
id INTEGER PRIMARY KEY,
category TEXT NOT NULL,
filename TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
html_content TEXT,
css_content TEXT,
demo_url TEXT,
source_url TEXT,
tags TEXT,
difficulty_level TEXT,
browser_support TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
search_content TEXT,
UNIQUE(category, filename)
)
`;
// 代码片段表(用于存储提取的代码块)
const createCodeSnippetsTableSQL = `
CREATE TABLE IF NOT EXISTS code_snippets (
id INTEGER PRIMARY KEY,
inspiration_id INTEGER,
snippet_type TEXT, -- 'html', 'css', 'javascript'
code_content TEXT,
line_start INTEGER,
line_end INTEGER,
description TEXT,
FOREIGN KEY(inspiration_id) REFERENCES css_inspiration(id)
)
`;
// Demo 样式表(用于存储完整的可运行 demo)
const createDemoStylesTableSQL = `
CREATE TABLE IF NOT EXISTS demo_styles (
id INTEGER PRIMARY KEY,
inspiration_id INTEGER,
complete_html TEXT,
complete_css TEXT,
preview_image TEXT,
is_interactive BOOLEAN DEFAULT 0,
performance_notes TEXT,
FOREIGN KEY(inspiration_id) REFERENCES css_inspiration(id)
)
`;
this.db.serialize(() => {
this.db.run(createInspirationTableSQL)
.run(createCodeSnippetsTableSQL)
.run(createDemoStylesTableSQL);
console.log('✅ CSS-Inspiration database tables initialized');
});
}
async fetchDirectoryContents(category) {
console.log(`📂 Fetching contents for category: ${category}`);
try {
const response = await axios.get(`${this.baseURL}/contents/${category}`, {
headers: {
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'iCSS-MCP-Server',
...(this.githubToken && { 'Authorization': `token ${this.githubToken}` })
}
});
const files = response.data.filter(item =>
item.type === 'file' && item.name.endsWith('.md')
);
console.log(` 📝 Found ${files.length} markdown files in ${category}`);
return files;
} catch (error) {
console.error(`❌ Error fetching ${category} contents:`, error.message);
return [];
}
}
async fetchFileContent(filePath) {
try {
const response = await axios.get(`${this.rawURL}/${filePath}`, {
headers: {
'User-Agent': 'iCSS-MCP-Server',
...(this.githubToken && { 'Authorization': `token ${this.githubToken}` })
}
});
return response.data;
} catch (error) {
console.error(`❌ Error fetching file ${filePath}:`, error.message);
return null;
}
}
parseMarkdownContent(content, category, filename) {
const lines = content.split('\n');
let title = '';
let description = '';
let htmlContent = '';
let cssContent = '';
let currentSection = '';
let codeBlock = [];
let isInCodeBlock = false;
let codeBlockType = '';
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// 提取标题
if (line.startsWith('## ') && !title) {
title = line.replace('## ', '').trim();
continue;
}
// 检测代码块开始
if (line.startsWith('```')) {
if (!isInCodeBlock) {
// 开始代码块
isInCodeBlock = true;
codeBlockType = line.replace('```', '').trim() || 'text';
codeBlock = [];
} else {
// 结束代码块
isInCodeBlock = false;
const code = codeBlock.join('\n');
if (codeBlockType === 'html' || codeBlockType.includes('html')) {
htmlContent += code + '\n\n';
} else if (codeBlockType === 'css' || codeBlockType.includes('css')) {
cssContent += code + '\n\n';
}
codeBlock = [];
codeBlockType = '';
}
continue;
}
// 收集代码块内容
if (isInCodeBlock) {
codeBlock.push(line);
continue;
}
// 收集描述信息
if (!isInCodeBlock && line.trim() && !line.startsWith('#')) {
if (!description && title) {
description += line + ' ';
}
}
}
// 如果没有找到标题,使用文件名
if (!title) {
title = filename.replace('.md', '').replace(/-/g, ' ');
}
// 生成标签
const tags = this.generateTags(title, description, cssContent, category);
// 评估难度级别
const difficultyLevel = this.assessDifficulty(cssContent, htmlContent);
// 评估浏览器支持
const browserSupport = this.assessBrowserSupport(cssContent);
return {
title: title.trim(),
description: description.trim().substring(0, 500),
htmlContent: htmlContent.trim(),
cssContent: cssContent.trim(),
tags: JSON.stringify(tags),
difficultyLevel,
browserSupport: JSON.stringify(browserSupport)
};
}
generateTags(title, description, cssContent, category) {
const tags = [this.categoryMapping[category] || category];
// 从 CSS 内容中提取关键属性
const cssProperties = [
'transform', 'animation', 'transition', 'background', 'border',
'box-shadow', 'clip-path', 'mask', 'filter', 'grid', 'flex',
'position', 'pseudo', ':hover', ':before', ':after'
];
cssProperties.forEach(prop => {
if (cssContent.toLowerCase().includes(prop)) {
tags.push(prop);
}
});
// 从标题和描述中提取关键词
const keywords = [
'动画', '效果', '布局', '渐变', '阴影', '3D', '响应式',
'Loading', '按钮', '卡片', '导航', '菜单'
];
const text = (title + ' ' + description).toLowerCase();
keywords.forEach(keyword => {
if (text.includes(keyword.toLowerCase())) {
tags.push(keyword);
}
});
return [...new Set(tags)]; // 去重
}
assessDifficulty(cssContent, htmlContent) {
let complexity = 0;
// 基于 CSS 复杂度评估
const advancedProperties = [
'@keyframes', 'transform3d', 'perspective', 'clip-path',
'mask', 'filter', 'mix-blend-mode', 'calc(', 'var(',
'custom-property', '@property'
];
advancedProperties.forEach(prop => {
if (cssContent.includes(prop)) {
complexity += 2;
}
});
// 基于嵌套和选择器复杂度
const selectorComplexity = (cssContent.match(/::?[\w-]+/g) || []).length;
complexity += Math.floor(selectorComplexity / 5);
// 基于动画复杂度
const animationCount = (cssContent.match(/@keyframes/g) || []).length;
complexity += animationCount * 3;
if (complexity < 5) return '初级';
if (complexity < 10) return '中级';
return '高级';
}
assessBrowserSupport(cssContent) {
const support = {
chrome: '完全支持',
firefox: '完全支持',
safari: '完全支持',
edge: '完全支持',
ie: '不支持'
};
// 检查新特性
const modernFeatures = {
'clip-path': { safari: '部分支持', ie: '不支持' },
'mask': { safari: '需要前缀', ie: '不支持' },
'@property': { firefox: '部分支持', safari: '部分支持', ie: '不支持' },
'backdrop-filter': { firefox: '部分支持', ie: '不支持' },
'grid': { ie: '部分支持' },
'custom-property': { ie: '不支持' }
};
Object.entries(modernFeatures).forEach(([feature, limitations]) => {
if (cssContent.includes(feature)) {
Object.assign(support, limitations);
}
});
return support;
}
async saveToDatabase(category, filename, parsedContent) {
const insertSQL = `
INSERT OR REPLACE INTO css_inspiration
(category, filename, title, description, html_content, css_content,
demo_url, source_url, tags, difficulty_level, browser_support,
search_content, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
`;
const sourceUrl = `https://github.com/chokcoco/CSS-Inspiration/blob/master/${category}/${filename}`;
const demoUrl = `https://chokcoco.github.io/CSS-Inspiration/${category}/${filename.replace('.md', '.html')}`;
const searchContent = [
parsedContent.title,
parsedContent.description,
category,
this.categoryMapping[category] || category,
...JSON.parse(parsedContent.tags)
].join(' ');
return new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
category,
filename,
parsedContent.title,
parsedContent.description,
parsedContent.htmlContent,
parsedContent.cssContent,
demoUrl,
sourceUrl,
parsedContent.tags,
parsedContent.difficultyLevel,
parsedContent.browserSupport,
searchContent
],
function(err) {
if (err) {
reject(err);
} else {
resolve(this.lastID);
}
}
);
});
}
async extractAndSaveCodeSnippets(inspirationId, htmlContent, cssContent) {
if (!htmlContent && !cssContent) return;
const snippets = [];
if (htmlContent) {
snippets.push({
inspiration_id: inspirationId,
snippet_type: 'html',
code_content: htmlContent,
description: 'HTML 结构代码'
});
}
if (cssContent) {
// 分割 CSS 代码块
const cssBlocks = cssContent.split(/\/\*[\s\S]*?\*\/|\/\/.*$/gm)
.filter(block => block.trim());
cssBlocks.forEach((block, index) => {
if (block.trim()) {
snippets.push({
inspiration_id: inspirationId,
snippet_type: 'css',
code_content: block.trim(),
description: `CSS 样式代码块 ${index + 1}`
});
}
});
}
const insertSnippetSQL = `
INSERT INTO code_snippets
(inspiration_id, snippet_type, code_content, description)
VALUES (?, ?, ?, ?)
`;
for (const snippet of snippets) {
await new Promise((resolve, reject) => {
this.db.run(
insertSnippetSQL,
[snippet.inspiration_id, snippet.snippet_type, snippet.code_content, snippet.description],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
}
async generateCompleteDemo(inspirationId, title, htmlContent, cssContent) {
if (!cssContent) return;
const completeHTML = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
}
${cssContent}
</style>
</head>
<body>
${htmlContent || '<div class="demo-container">CSS Demo</div>'}
</body>
</html>`;
const insertDemoSQL = `
INSERT OR REPLACE INTO demo_styles
(inspiration_id, complete_html, complete_css, is_interactive)
VALUES (?, ?, ?, ?)
`;
const isInteractive = cssContent.includes(':hover') ||
cssContent.includes('animation') ||
cssContent.includes('transition');
await new Promise((resolve, reject) => {
this.db.run(
insertDemoSQL,
[inspirationId, completeHTML, cssContent, isInteractive ? 1 : 0],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
async fetchAllInspirations() {
console.log('🚀 Starting to fetch CSS-Inspiration repository contents...');
try {
// 获取所有分类目录
const categories = Object.keys(this.categoryMapping);
let totalProcessed = 0;
for (const category of categories) {
console.log(`\n📁 Processing category: ${category} (${this.categoryMapping[category]})`);
const files = await this.fetchDirectoryContents(category);
for (const file of files) {
try {
console.log(` 📄 Processing: ${file.name}`);
const filePath = `${category}/${file.name}`;
const content = await this.fetchFileContent(filePath);
if (content) {
const parsedContent = this.parseMarkdownContent(content, category, file.name);
if (parsedContent.title) {
const inspirationId = await this.saveToDatabase(category, file.name, parsedContent);
// 保存代码片段
await this.extractAndSaveCodeSnippets(
inspirationId,
parsedContent.htmlContent,
parsedContent.cssContent
);
// 生成完整的演示页面
await this.generateCompleteDemo(
inspirationId,
parsedContent.title,
parsedContent.htmlContent,
parsedContent.cssContent
);
totalProcessed++;
console.log(` ✅ Saved: ${parsedContent.title}`);
}
}
// 添加延迟以避免速率限制
await new Promise(resolve => setTimeout(resolve, 500));
} catch (error) {
console.error(` ❌ Error processing ${file.name}:`, error.message);
continue;
}
}
}
console.log(`\n🎉 CSS-Inspiration import completed! Processed ${totalProcessed} demos.`);
this.generateStats();
} catch (error) {
console.error('❌ Error fetching CSS-Inspiration:', error.message);
}
}
generateStats() {
console.log('\n📊 CSS-Inspiration Statistics:');
this.db.all(`
SELECT
category,
COUNT(*) as count,
difficulty_level
FROM css_inspiration
GROUP BY category, difficulty_level
ORDER BY category, difficulty_level
`, (err, rows) => {
if (err) {
console.error('Error generating stats:', err);
return;
}
const stats = {};
rows.forEach(row => {
if (!stats[row.category]) {
stats[row.category] = {};
}
stats[row.category][row.difficulty_level] = row.count;
});
Object.entries(stats).forEach(([category, difficulties]) => {
const total = Object.values(difficulties).reduce((sum, count) => sum + count, 0);
console.log(` ${this.categoryMapping[category] || category}: ${total} 个案例`);
Object.entries(difficulties).forEach(([level, count]) => {
console.log(` - ${level}: ${count} 个`);
});
});
// 总体统计
this.db.get('SELECT COUNT(*) as total FROM css_inspiration', (err, row) => {
if (!err && row) {
console.log(`\n 📈 总计: ${row.total} 个 CSS 演示案例`);
}
console.log('\n🎉 CSS-Inspiration 数据导入完成!');
process.exit(0);
});
});
}
close() {
this.db.close();
}
}
// 运行脚本
const fetcher = new InspirationFetcher();
fetcher.fetchAllInspirations().catch(console.error);
// 优雅关闭
process.on('SIGINT', () => {
console.log('\n⏹️ Shutting down...');
fetcher.close();
process.exit(0);
});
================================================
FILE: MCP/scripts/fetch-issues.js
================================================
import axios from 'axios';
import Database from 'sqlite3';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class IssuesFetcher {
constructor() {
this.baseURL = 'https://api.github.com/repos/chokcoco/iCSS/issues';
this.dbPath = path.join(__dirname, '../data/icss.db');
this.dataDir = path.join(__dirname, '../data');
// 检查 GitHub token
this.githubToken = process.env.GITHUB_TOKEN;
if (!this.githubToken) {
console.warn('⚠️ No GITHUB_TOKEN found in environment variables. API rate limits will be restricted.');
}
// 确保数据目录存在
if (!fs.existsSync(this.dataDir)) {
fs.mkdirSync(this.dataDir, { recursive: true });
}
// 初始化数据库连接
this.db = new Database.Database(this.dbPath, (err) => {
if (err) {
console.error('❌ Error opening database:', err);
process.exit(1);
}
});
this.labelCategories = {
// 核心技术类标签
core_tech: [
'CSS Layout', // CSS 布局
'CSS Function', // CSS 函数
'CSS-Houdini', // CSS Houdini API
'CSS Variable', // CSS 变量
'CSS 新特性', // CSS 新特性
'Modern CSS', // 现代 CSS
'CSS-doodle' // CSS-doodle
],
// 视觉效果类标签
visual_effects: [
'Background', // 背景效果
'Border', // 边框效果
'Shadow', // 阴影效果
'Shape', // 形状效果
'混合模式', // 混合模式
'滤镜', // 滤镜效果
'clip-path', // 裁剪路径
'Mask', // 遮罩效果
'3D 效果', // 3D 效果
'图片效果', // 图片处理
'文字效果', // 文字效果
'边框效果' // 边框特效
],
// 动画类标签
animation: [
'动效', // 动态效果
'动画', // 动画效果
'特殊交互' // 特殊交互效果
],
// 技术实现类标签
implementation: [
'SVG', // SVG 技术
'伪类', // CSS 伪类
'性能', // 性能优化
'技巧', // 技术技巧
'奇技淫巧', // 特殊技巧
'浏览器特性' // 浏览器特性
],
// 用户体验类标签
ux: [
'可访问性', // 可访问性
'用户体验', // UX
'设计' // 设计相关
],
// 内容类型标签
content_type: [
'翻译', // 翻译文章
'面试', // 面试相关
'Bug' // 问题修复
]
};
// 标签权重配置
this.labelWeights = {
// 核心技术标签权重较高
'CSS Layout': 1.5,
'CSS Function': 1.5,
'CSS-Houdini': 1.6,
'CSS Variable': 1.4,
'CSS 新特性': 1.6,
'Modern CSS': 1.5,
// 视觉效果标签权重
'Background': 1.2,
'Border': 1.2,
'Shadow': 1.2,
'Shape': 1.3,
'混合模式': 1.4,
'滤镜': 1.3,
'clip-path': 1.4,
'Mask': 1.4,
// 动画相关标签权重
'动效': 1.3,
'动画': 1.3,
'特殊交互': 1.4,
'3D 效果': 1.5,
// 实现技巧标签权重
'SVG': 1.4,
'伪类': 1.2,
'性能': 1.5,
'技巧': 1.1,
'奇技淫巧': 1.3,
// 用户体验标签权重
'可访问性': 1.4,
'用户体验': 1.3,
'设计': 1.2
};
// 标签关系映射
this.labelRelations = {
// 相关技术映射
'CSS Layout': ['CSS Function', 'CSS Variable'],
'CSS-Houdini': ['CSS 新特性', 'Modern CSS'],
'Background': ['混合模式', '滤镜', 'clip-path', 'Mask'],
'Border': ['clip-path', 'Shape', '边框效果'],
'动画': ['动效', '特殊交互', '3D 效果'],
'SVG': ['Shape', 'Mask', 'clip-path'],
// 应用场景映射
'性能': ['Modern CSS', 'CSS-Houdini'],
'可访问性': ['用户体验', '设计'],
'特殊交互': ['用户体验', '动效']
};
this.initializeDatabase();
}
initializeDatabase() {
// 原有的 issues 表
const createIssuesTableSQL = `
CREATE TABLE IF NOT EXISTS issues (
id INTEGER PRIMARY KEY,
number INTEGER UNIQUE,
title TEXT NOT NULL,
body TEXT,
html_url TEXT,
labels TEXT,
created_at TEXT,
updated_at TEXT,
search_content TEXT
)
`;
// 标签分类表
const createLabelCategoriesTableSQL = `
CREATE TABLE IF NOT EXISTS label_categories (
id INTEGER PRIMARY KEY,
label TEXT UNIQUE,
category TEXT,
description TEXT,
usage_count INTEGER DEFAULT 0,
last_used TEXT
)
`;
// 标签关系表(记录标签之间的关联)
const createLabelRelationsTableSQL = `
CREATE TABLE IF NOT EXISTS label_relations (
id INTEGER PRIMARY KEY,
label1 TEXT,
label2 TEXT,
cooccurrence_count INTEGER DEFAULT 0,
correlation_score REAL,
last_updated TEXT,
UNIQUE(label1, label2)
)
`;
// 文章标签映射表(用于快速查询)
const createArticleLabelsTableSQL = `
CREATE TABLE IF NOT EXISTS article_labels (
id INTEGER PRIMARY KEY,
issue_number INTEGER,
label TEXT,
category TEXT,
weight REAL DEFAULT 1.0,
FOREIGN KEY(issue_number) REFERENCES issues(number)
)
`;
// 标签层级关系表
const createLabelHierarchyTableSQL = `
CREATE TABLE IF NOT EXISTS label_hierarchy (
id INTEGER PRIMARY KEY,
parent_label TEXT,
child_label TEXT,
relation_type TEXT,
UNIQUE(parent_label, child_label)
)
`;
this.db.serialize(() => {
this.db.run(createIssuesTableSQL)
.run(createLabelCategoriesTableSQL)
.run(createLabelRelationsTableSQL)
.run(createArticleLabelsTableSQL)
.run(createLabelHierarchyTableSQL);
// 初始化标签分类
this.initializeLabelCategories();
});
}
async initializeLabelCategories() {
// 预定义的标签分类和描述
const labelDescriptions = {
// 核心技术类
'CSS Layout': 'CSS 布局技术和方法',
'CSS Function': 'CSS 函数使用和技巧',
'CSS-Houdini': 'CSS Houdini API 相关技术',
'CSS Variable': 'CSS 变量使用和应用',
'CSS 新特性': '最新的 CSS 特性和用法',
'Modern CSS': '现代 CSS 技术和方法',
'CSS-doodle': 'CSS-doodle 绘图技术',
// 视觉效果类
'Background': '背景相关的效果和技巧',
'Border': '边框相关的效果和技巧',
'Shadow': '阴影效果实现方法',
'Shape': '图形形状相关技术',
'混合模式': '混合模式效果实现',
'滤镜': '滤镜效果实现和应用',
'clip-path': '裁剪路径技术和应用',
'Mask': '遮罩效果实现方法',
'3D 效果': '3D 效果实现技术',
'图片效果': '图片处理和效果实现',
'文字效果': '文字特效和排版技巧',
'边框效果': '特殊边框效果实现',
// 动画类
'动效': '动态效果实现方法',
'动画': '动画效果实现技术',
'特殊交互': '特殊交互效果实现',
// 技术实现类
'SVG': 'SVG 图形和动画技术',
'伪类': 'CSS 伪类使用技巧',
'性能': 'CSS 性能优化方法',
'技巧': 'CSS 使用技巧和方法',
'奇技淫巧': '特殊效果实现技巧',
'浏览器特性': '浏览器特性和兼容性',
// 用户体验类
'可访问性': '可访问性优化方法',
'用户体验': '用户体验优化技巧',
'设计': 'CSS 设计相关技术'
};
// 插入预定义的标签分类
const insertSQL = `
INSERT OR REPLACE INTO label_categories (label, category, description)
VALUES (?, ?, ?)
`;
for (const [category, labels] of Object.entries(this.labelCategories)) {
for (const label of labels) {
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[label, category, labelDescriptions[label] || `${category}类标签`],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
}
}
async analyzeLabelRelations(issues) {
console.log('📊 Analyzing label relations...');
const labelPairs = new Map();
const labelCounts = new Map();
// 收集标签共现信息
for (const issue of issues) {
try {
const labels = Array.isArray(issue.labels)
? issue.labels.map(label => typeof label === 'string' ? label : label.name)
: JSON.parse(issue.labels || '[]');
// 更新单个标签计数
labels.forEach(label => {
labelCounts.set(label, (labelCounts.get(label) || 0) + 1);
});
// 更新标签对的共现计数
for (let i = 0; i < labels.length; i++) {
for (let j = i + 1; j < labels.length; j++) {
const pair = [labels[i], labels[j]].sort().join('->');
labelPairs.set(pair, (labelPairs.get(pair) || 0) + 1);
}
}
} catch (error) {
console.error(`Error processing labels for issue #${issue.number}:`, error);
continue;
}
}
// 计算相关性分数并更新数据库
const updateRelationSQL = `
INSERT OR REPLACE INTO label_relations
(label1, label2, cooccurrence_count, correlation_score, last_updated)
VALUES (?, ?, ?, ?, datetime('now'))
`;
for (const [pair, count] of labelPairs.entries()) {
try {
const [label1, label2] = pair.split('->');
const correlation = count / Math.sqrt(labelCounts.get(label1) * labelCounts.get(label2));
await new Promise((resolve, reject) => {
this.db.run(
updateRelationSQL,
[label1, label2, count, correlation],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
} catch (error) {
console.error(`Error saving relation for pair ${pair}:`, error);
continue;
}
}
console.log(`✅ Analyzed ${labelPairs.size} label relationships`);
}
async analyzeArticleLabels(issue) {
try {
const labels = Array.isArray(issue.labels)
? issue.labels.map(label => typeof label === 'string' ? label : label.name)
: JSON.parse(issue.labels || '[]');
const content = issue.body || '';
// 获取标签分类信息
const labelInfo = await Promise.all(
labels.map(label =>
new Promise((resolve, reject) => {
this.db.get(
'SELECT category FROM label_categories WHERE label = ?',
[label],
(err, row) => {
if (err) reject(err);
else resolve({
label,
category: row ? row.category : 'uncategorized'
});
}
);
})
)
);
// 计算标签权重
const weights = this.calculateLabelWeights(labels, content);
// 保存到数据库
const insertSQL = `
INSERT OR REPLACE INTO article_labels
(issue_number, label, category, weight)
VALUES (?, ?, ?, ?)
`;
for (const {label, category} of labelInfo) {
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[issue.number, label, category, weights[label] || 1.0],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
} catch (error) {
console.error(`Error analyzing labels for issue #${issue.number}:`, error);
// 继续处理下一个文章,而不是中断整个过程
return;
}
}
calculateLabelWeights(labels, content) {
const weights = {};
for (const label of labels) {
// 基础权重
let weight = this.labelWeights[label] || 1.0;
// 基于内容相关度调整权重
const labelRegex = new RegExp(label, 'gi');
const matches = content.match(labelRegex) || [];
weight += matches.length * 0.1;
// 基于标签位置调整权重
if (content.toLowerCase().includes(label.toLowerCase())) {
const firstIndex = content.toLowerCase().indexOf(label.toLowerCase());
if (firstIndex < content.length * 0.2) {
weight += 0.3; // 在文章开头出现的标签更重要
}
}
// 基于代码示例调整权重
const codeBlocks = content.match(/```[^`]+```/g) || [];
for (const block of codeBlocks) {
if (block.toLowerCase().includes(label.toLowerCase())) {
weight += 0.2; // 在代码示例中出现的标签更重要
}
}
// 基于标签关系调整权重
if (this.labelRelations[label]) {
const relatedLabels = this.labelRelations[label];
const presentRelatedLabels = relatedLabels.filter(rel =>
labels.includes(rel)
);
weight += presentRelatedLabels.length * 0.1; // 相关标签共现提升权重
}
weights[label] = weight;
}
return weights;
}
async buildLabelHierarchy() {
console.log('🌳 Building label hierarchy...');
// 基于预定义的分类构建层级关系
for (const [category, labels] of Object.entries(this.labelCategories)) {
// 将分类作为父节点
for (const label of labels) {
await new Promise((resolve, reject) => {
this.db.run(
`INSERT OR REPLACE INTO label_hierarchy (parent_label, child_label, relation_type)
VALUES (?, ?, ?)`,
[category, label, 'category'],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
}
// 基于标签共现关系构建关联
const relatedLabelsSQL = `
SELECT label1, label2, correlation_score
FROM label_relations
WHERE correlation_score > 0.5
ORDER BY correlation_score DESC
`;
this.db.all(relatedLabelsSQL, [], async (err, rows) => {
if (err) {
console.error('Error building label hierarchy:', err);
return;
}
for (const row of rows) {
await new Promise((resolve, reject) => {
this.db.run(
`INSERT OR REPLACE INTO label_hierarchy (parent_label, child_label, relation_type)
VALUES (?, ?, ?)`,
[row.label1, row.label2, 'related'],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
});
}
async saveAnalysisToDatabase(issueNumber, analysis) {
const insertSQL = `
INSERT OR REPLACE INTO article_analysis
(issue_number, css_properties, techniques, complexity_level,
browser_support, use_cases, code_snippets, demo_links, related_articles)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
return new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
issueNumber,
analysis.css_properties,
analysis.techniques,
analysis.complexity_level,
analysis.browser_support,
analysis.use_cases,
analysis.code_snippets,
analysis.demo_links,
analysis.related_articles
],
function(err) {
if (err) reject(err);
else resolve();
}
);
});
}
async saveIssuesToDatabase(issues) {
console.log('💾 Saving and analyzing issues...');
const insertSQL = `
INSERT OR REPLACE INTO issues
(number, title, body, html_url, labels, created_at, updated_at, search_content)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`;
let savedCount = 0;
for (const issue of issues) {
if (issue.pull_request) continue;
try {
const labels = Array.isArray(issue.labels)
? JSON.stringify(issue.labels.map(label => typeof label === 'string' ? label : label.name))
: issue.labels;
const searchContent = this.createSearchContent(issue);
// 保存基本信息
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
issue.number,
issue.title,
issue.body || '',
issue.html_url,
labels,
issue.created_at,
issue.updated_at,
searchContent
],
async function(err) {
if (err) {
console.error(`Error saving issue #${issue.number}:`, err);
reject(err);
} else {
try {
// 分析并保存标签信息
await this.analyzeArticleLabels(issue);
savedCount++;
resolve();
} catch (analysisErr) {
console.error(`Error analyzing issue #${issue.number}:`, analysisErr);
reject(analysisErr);
}
}
}.bind(this)
);
});
if (savedCount % 10 === 0) {
console.log(` 📝 Processed ${savedCount} articles...`);
}
} catch (error) {
console.error(`Error processing issue #${issue.number}:`, error);
continue;
}
}
// 分析标签关系
await this.analyzeLabelRelations(issues);
// 构建标签层级
await this.buildLabelHierarchy();
console.log(`✅ Successfully saved and analyzed ${savedCount} articles`);
await this.generateLabelStatistics();
}
async updateRelatedArticles() {
console.log('🔄 Updating article relations...');
// 获取所有文章的分析数据
const articles = await new Promise((resolve, reject) => {
this.db.all(`
SELECT
i.number,
i.title,
a.css_properties,
a.techniques,
a.complexity_level
FROM issues i
JOIN article_analysis a ON i.number = a.issue_number
`, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
// 计算文章间的相关性
for (const article of articles) {
const related = articles
.filter(other => other.number !== article.number)
.map(other => {
const score = this.calculateRelationScore(article, other);
return { number: other.number, score };
})
.sort((a, b) => b.score - a.score)
.slice(0, 5) // 取前5个最相关的文章
.map(r => r.number);
// 更新相关文章
await this.saveAnalysisToDatabase(article.number, {
...article,
related_articles: JSON.stringify(related)
});
}
}
calculateRelationScore(article1, article2) {
let score = 0;
// 比较 CSS 属性相似度
const props1 = new Set(JSON.parse(article1.css_properties));
const props2 = new Set(JSON.parse(article2.css_properties));
const commonProps = new Set([...props1].filter(x => props2.has(x)));
score += commonProps.size * 2;
// 比较技术相似度
const techs1 = new Set(JSON.parse(article1.techniques));
const techs2 = new Set(JSON.parse(article2.techniques));
const commonTechs = new Set([...techs1].filter(x => techs2.has(x)));
score += commonTechs.size * 3;
// 考虑难度级别
if (article1.complexity_level === article2.complexity_level) {
score += 1;
}
return score;
}
generateEnhancedStats() {
console.log('\n📊 Enhanced Database Statistics:');
// 技术分布统计
this.db.all(`
SELECT
techniques,
COUNT(*) as count
FROM article_analysis
GROUP BY techniques
ORDER BY count DESC
LIMIT 10
`, (err, techRows) => {
if (err) {
console.error('Error getting technique stats:', err);
return;
}
console.log('\n🛠️ Top Techniques Distribution:');
techRows.forEach((row, index) => {
const techs = JSON.parse(row.techniques);
console.log(` ${index + 1}. ${techs.join(', ')} (${row.count} articles)`);
});
// 难度级别分布
this.db.all(`
SELECT
complexity_level,
COUNT(*) as count
FROM article_analysis
GROUP BY complexity_level
ORDER BY count DESC
`, (err, complexityRows) => {
if (err) {
console.error('Error getting complexity stats:', err);
return;
}
console.log('\n📈 Complexity Level Distribution:');
complexityRows.forEach(row => {
console.log(` ${row.complexity_level}: ${row.count} articles`);
});
console.log('\n🎉 Enhanced analysis completed!');
process.exit(0);
});
});
}
async fetchAllIssues() {
console.log('🚀 Starting to fetch iCSS repository issues...');
let page = 1;
let allIssues = [];
const perPage = 100; // GitHub API maximum
try {
while (true) {
console.log(`📄 Fetching page ${page}...`);
const response = await axios.get(this.baseURL, {
params: {
state: 'all', // 获取所有状态的issues
per_page: perPage,
page: page,
sort: 'updated',
direction: 'desc'
},
headers: {
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'iCSS-MCP-Server',
...(this.githubToken && { 'Authorization': `token ${this.githubToken}` })
}
});
const issues = response.data;
if (issues.length === 0) {
console.log('✅ No more issues found');
break;
}
console.log(` 📝 Found ${issues.length} issues on page ${page}`);
allIssues = allIssues.concat(issues);
// GitHub API rate limiting
if (issues.length < perPage) {
break;
}
page++;
// 添加延迟以避免速率限制
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log(`🎉 Total issues fetched: ${allIssues.length}`);
await this.saveIssuesToDatabase(allIssues);
} catch (error) {
if (error.response?.status === 403) {
console.error('❌ GitHub API rate limit exceeded. Please set GITHUB_TOKEN environment variable.');
console.error('Visit https://github.com/settings/tokens to generate a token.');
process.exit(1);
}
console.error('❌ Error fetching issues:', error.message);
if (error.response) {
console.error('Response status:', error.response.status);
console.error('Response data:', error.response.data);
}
}
}
createSearchContent(issue) {
// 更好地处理标签
const labels = Array.isArray(issue.labels)
? issue.labels
.map(label => typeof label === 'string' ? label : label.name)
.join(' ')
: '';
const body = issue.body || '';
// 移除markdown语法,提取纯文本用于搜索
const cleanBody = body
.replace(/```[\s\S]*?```/g, ' ') // 移除代码块
.replace(/`([^`]+)`/g, '$1') // 移除行内代码
.replace(/[#*_~]/g, '') // 移除markdown格式
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // 移除链接,保留文本
.replace(/\s+/g, ' ') // 标准化空白字符
.trim();
// 构建更丰富的搜索内容
const searchContent = [
issue.title,
labels,
cleanBody,
// 添加标签的不同组合形式,以提高匹配率
...labels.split(' ').filter(Boolean),
// 为某些常见的组合词添加变体
labels.includes('奇技淫巧') ? '技巧 奇技' : '',
labels.includes('动画') ? '动效 特效' : '',
labels.includes('特殊交互') ? '交互 动效' : ''
].filter(Boolean).join(' ');
return searchContent.substring(0, 1000); // 限制长度
}
generateStats() {
this.db.all('SELECT COUNT(*) as total FROM issues', (err, rows) => {
if (err) {
console.error('Error generating stats:', err);
return;
}
console.log('\n📊 Database Statistics:');
console.log(` Total articles: ${rows[0].total}`);
// 标签统计
this.db.all(`
SELECT labels, COUNT(*) as count
FROM issues
WHERE labels IS NOT NULL AND labels != '[]'
GROUP BY labels
ORDER BY count DESC
LIMIT 10
`, (err, labelRows) => {
if (err) {
console.error('Error getting label stats:', err);
return;
}
console.log('\n🏷️ Top 10 Label Combinations:');
labelRows.forEach((row, index) => {
const labels = JSON.parse(row.labels);
console.log(` ${index + 1}. ${labels.join(', ')} (${row.count} articles)`);
});
console.log('\n🎉 Database update completed!');
process.exit(0);
});
});
}
close() {
this.db.close();
}
analyzeCodePatterns(content) {
const patterns = [];
const codeBlocks = content.match(/```[^`]+```/g) || [];
codeBlocks.forEach((block, index) => {
const cleanCode = block.replace(/```(css|html|javascript)?\n/g, '').replace(/```$/g, '');
// 分析动画模式
if (cleanCode.includes('@keyframes') || cleanCode.includes('animation')) {
patterns.push({
pattern_name: `animation_pattern_${index}`,
pattern_type: 'animation',
code_snippet: cleanCode,
explanation: this.analyzeAnimationPattern(cleanCode),
use_cases: JSON.stringify(['transitions', 'hover effects', 'loading indicators']),
performance_notes: this.analyzeAnimationPerformance(cleanCode),
browser_support: this.getAnimationBrowserSupport(cleanCode)
});
}
// 分析布局模式
if (cleanCode.includes('grid') || cleanCode.includes('flex')) {
patterns.push({
pattern_name: `layout_pattern_${index}`,
pattern_type: 'layout',
code_snippet: cleanCode,
explanation: this.analyzeLayoutPattern(cleanCode),
use_cases: JSON.stringify(['responsive layouts', 'card layouts', 'centering']),
performance_notes: this.analyzeLayoutPerformance(cleanCode),
browser_support: this.getLayoutBrowserSupport(cleanCode)
});
}
});
return patterns;
}
analyzeAnimationPattern(code) {
const analysis = [];
if (code.includes('transform')) {
analysis.push('使用 transform 实现动画,性能优良');
}
if (code.includes('opacity')) {
analysis.push('使用 opacity 实现淡入淡出效果');
}
if (code.includes('will-change')) {
analysis.push('使用 will-change 优化动画性能');
}
return analysis.join('. ');
}
analyzeAnimationPerformance(code) {
const notes = [];
// 检查是否使用 GPU 加速
if (code.includes('transform3d') || code.includes('translateZ')) {
notes.push('使用 3D 变换触发 GPU 加速');
}
// 检查是否有性能优化
if (code.includes('will-change')) {
notes.push('使用 will-change 提示浏览器优化');
}
// 检查动画属性
if (code.includes('left') || code.includes('top')) {
notes.push('警告:使用定位属性动画可能触发重排');
}
return notes.join('. ');
}
getAnimationBrowserSupport(code) {
const support = {
chrome: '支持',
firefox: '支持',
safari: '支持',
edge: '支持',
ie: '部分支持'
};
// 检查新特性支持
if (code.includes('@property') || code.includes('backdrop-filter')) {
support.safari = '部分支持';
support.ie = '不支持';
}
// 检查动画特性
if (code.includes('animation') || code.includes('@keyframes')) {
support.ie = 'IE10+ 需要前缀';
}
return JSON.stringify(support);
}
analyzeLayoutPattern(code) {
const analysis = [];
if (code.includes('grid')) {
analysis.push('使用 Grid 布局实现复杂的二维布局');
}
if (code.includes('flex')) {
analysis.push('使用 Flexbox 实现灵活的一维布局');
}
if (code.includes('calc')) {
analysis.push('使用 calc() 进行动态计算');
}
return analysis.join('. ');
}
analyzeLayoutPerformance(code) {
const notes = [];
// 检查 Flexbox 性能
if (code.includes('flex')) {
notes.push('Flexbox 在大量元素时可能影响性能');
}
// 检查 Grid 性能
if (code.includes('grid')) {
notes.push('Grid 布局在复杂嵌套时可能影响性能');
}
// 检查动态布局
if (code.includes('calc')) {
notes.push('calc() 在频繁计算时可能影响性能');
}
return notes.join('. ');
}
getLayoutBrowserSupport(code) {
const support = {
chrome: '完全支持',
firefox: '完全支持',
safari: '完全支持',
edge: '完全支持',
ie: '部分支持'
};
// Grid 支持
if (code.includes('grid')) {
support.ie = '不支持 Grid';
}
// Flexbox 支持
if (code.includes('flex')) {
support.ie = 'IE11 部分支持 Flexbox';
}
return JSON.stringify(support);
}
analyzePerformance(content, cssProperties) {
const properties = JSON.parse(cssProperties);
return {
gpu_accelerated: this.checkGPUAcceleration(properties),
paint_complexity: this.analyzePaintComplexity(properties),
layout_triggers: this.checkLayoutTriggers(properties),
memory_impact: this.analyzeMemoryImpact(properties),
optimization_tips: JSON.stringify(this.generateOptimizationTips(properties))
};
}
checkGPUAcceleration(properties) {
return properties.some(p =>
p.includes('transform3d') ||
p.includes('translateZ') ||
p.includes('will-change')
);
}
analyzePaintComplexity(properties) {
let complexity = 'low';
if (properties.some(p => p.includes('box-shadow') || p.includes('text-shadow'))) {
complexity = 'medium';
}
if (properties.some(p => p.includes('filter') || p.includes('backdrop-filter'))) {
complexity = 'high';
}
return complexity;
}
checkLayoutTriggers(properties) {
const layoutProperties = ['width', 'height', 'padding', 'margin', 'position', 'top', 'left', 'right', 'bottom'];
return properties.some(p => layoutProperties.includes(p));
}
analyzeMemoryImpact(properties) {
let impact = 'low';
if (properties.some(p => p.includes('background-image'))) {
impact = 'medium';
}
if (properties.some(p => p.includes('filter') || p.includes('backdrop-filter'))) {
impact = 'high';
}
return impact;
}
generateOptimizationTips(properties) {
const tips = [];
if (this.checkLayoutTriggers(properties)) {
tips.push('考虑使用 transform 替代改变位置和尺寸的属性');
}
if (properties.some(p => p.includes('box-shadow'))) {
tips.push('大面积阴影考虑使用 filter: drop-shadow() 优化性能');
}
if (properties.some(p => p.includes('@keyframes'))) {
tips.push('长动画考虑使用 requestAnimationFrame 实现');
}
return tips;
}
analyzeCSSPropertyCategories(properties) {
return properties.map(prop => ({
property_name: prop,
category: this.getCSSPropertyCategory(prop),
sub_category: this.getCSSPropertySubCategory(prop),
description: this.getPropertyDescription(prop),
performance_impact: this.getPropertyPerformanceImpact(prop),
best_practices: JSON.stringify(this.getPropertyBestPractices(prop)),
common_pitfalls: JSON.stringify(this.getPropertyCommonPitfalls(prop)),
browser_notes: this.getPropertyBrowserNotes(prop)
}));
}
getCSSPropertyCategory(prop) {
if (prop.match(/margin|padding|width|height|position|top|left|right|bottom|float|clear|display/)) {
return 'layout';
}
if (prop.match(/color|background|border|box-shadow|opacity|filter/)) {
return 'visual';
}
if (prop.match(/animation|transition|transform/)) {
return 'animation';
}
if (prop.match(/font|text|line-height|letter-spacing/)) {
return 'typography';
}
return 'other';
}
getCSSPropertySubCategory(prop) {
if (prop.includes('flex')) return 'flexbox';
if (prop.includes('grid')) return 'grid';
if (prop.includes('animation')) return 'keyframe-animation';
if (prop.includes('transition')) return 'transition';
if (prop.includes('transform')) return 'transform';
return 'basic';
}
getPropertyDescription(prop) {
// 这里可以添加更多属性的描述
const descriptions = {
'flex': 'Flexbox 布局的核心属性,用于设置弹性布局',
'grid': 'Grid 布局的核心属性,用于设置网格布局',
'animation': '用于设置动画效果的属性',
'transform': '用于元素的 2D 或 3D 转换',
// ... 更多属性描述
};
return descriptions[prop] || `CSS ${prop} 属性`;
}
getPropertyPerformanceImpact(prop) {
const highImpact = ['box-shadow', 'text-shadow', 'filter', 'backdrop-filter'];
const mediumImpact = ['border-radius', 'opacity', 'transform'];
if (highImpact.some(p => prop.includes(p))) return 'high';
if (mediumImpact.some(p => prop.includes(p))) return 'medium';
return 'low';
}
getPropertyBestPractices(prop) {
const practices = [];
if (prop.includes('animation')) {
practices.push('使用 transform 和 opacity 实现动画');
practices.push('添加 will-change 提示');
}
if (prop.includes('transform')) {
practices.push('使用 3D transform 触发 GPU 加速');
practices.push('合理使用 will-change');
}
return practices;
}
getPropertyCommonPitfalls(prop) {
const pitfalls = [];
if (prop.includes('animation')) {
pitfalls.push('过度使用可能导致性能问题');
pitfalls.push('没有提供回退方案');
}
if (prop.includes('flex')) {
pitfalls.push('嵌套使用可能导致性能问题');
pitfalls.push('未考虑浏览器前缀');
}
return pitfalls;
}
getPropertyBrowserNotes(prop) {
const notes = [];
if (prop.includes('@property')) {
notes.push('Chrome 85+, Safari 15.4+');
}
if (prop.includes('backdrop-filter')) {
notes.push('需要注意浏览器兼容性');
}
return notes.join('. ');
}
async saveCodePatterns(issueNumber, patterns) {
const insertSQL = `
INSERT OR REPLACE INTO code_patterns
(issue_number, pattern_name, pattern_type, code_snippet, explanation, use_cases, performance_notes, browser_support)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`;
for (const pattern of patterns) {
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
issueNumber,
pattern.pattern_name,
pattern.pattern_type,
pattern.code_snippet,
pattern.explanation,
pattern.use_cases,
pattern.performance_notes,
pattern.browser_support
],
function(err) {
if (err) reject(err);
else resolve();
}
);
});
}
}
async savePropertyCategories(categories) {
const insertSQL = `
INSERT OR REPLACE INTO property_categories
(property_name, category, sub_category, description, performance_impact, best_practices, common_pitfalls, browser_notes)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`;
for (const category of categories) {
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
category.property_name,
category.category,
category.sub_category,
category.description,
category.performance_impact,
category.best_practices,
category.common_pitfalls,
category.browser_notes
],
function(err) {
if (err) reject(err);
else resolve();
}
);
});
}
}
async savePerformanceAnalysis(issueNumber, analysis) {
const insertSQL = `
INSERT OR REPLACE INTO performance_analysis
(issue_number, gpu_accelerated, paint_complexity, layout_triggers, memory_impact, optimization_tips)
VALUES (?, ?, ?, ?, ?, ?)
`;
await new Promise((resolve, reject) => {
this.db.run(
insertSQL,
[
issueNumber,
analysis.gpu_accelerated,
analysis.paint_complexity,
analysis.layout_triggers,
analysis.memory_impact,
analysis.optimization_tips
],
function(err) {
if (err) reject(err);
else resolve();
}
);
});
}
async generateLabelStatistics() {
console.log('\n📊 Label Statistics:');
// 标签使用统计
this.db.all(`
SELECT
l.label,
l.category,
COUNT(al.issue_number) as usage_count,
AVG(al.weight) as avg_weight
FROM label_categories l
LEFT JOIN article_labels al ON l.label = al.label
GROUP BY l.label, l.category
ORDER BY usage_count DESC
`, [], (err, rows) => {
if (err) {
console.error('Error generating label stats:', err);
return;
}
console.log('\n🏷️ Label Usage by Category:');
const byCategory = {};
rows.forEach(row => {
if (!byCategory[row.category]) {
byCategory[row.category] = [];
}
byCategory[row.category].push({
label: row.label,
count: row.usage_count,
weight: row.avg_weight
});
});
Object.entries(byCategory).forEach(([category, labels]) => {
console.log(`\n${category}:`);
labels.forEach(({label, count, weight}) => {
console.log(` ${label}: ${count} articles (avg weight: ${weight?.toFixed(2) || 0})`);
});
});
// 标签关系统计
this.db.all(`
SELECT
label1,
label2,
cooccurrence_count,
correlation_score
FROM label_relations
WHERE correlation_score > 0.3
ORDER BY correlation_score DESC
LIMIT 10
`, [], (err, relations) => {
if (err) {
console.error('Error getting label relations:', err);
return;
}
console.log('\n🔗 Strong Label Correlations:');
relations.forEach(rel => {
console.log(` ${rel.label1} <-> ${rel.label2}: ${rel.correlation_score.toFixed(2)} (${rel.cooccurrence_count} co-occurrences)`);
});
console.log('\n🎉 Label analysis completed!');
process.exit(0);
});
});
}
}
// 运行脚本
const fetcher = new IssuesFetcher();
fetcher.fetchAllIssues().catch(console.error);
// 优雅关闭
process.on('SIGINT', () => {
console.log('\n⏹️ Shutting down...');
fetcher.close();
process.exit(0);
});
================================================
FILE: MCP/scripts/publish-check.js
================================================
#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = path.resolve(__dirname, '..');
console.log('🔍 Pre-publish check for icss-mcp-server v1.1.1\n');
let allPassed = true;
function checkFailed(message) {
console.log(`❌ ${message}`);
allPassed = false;
}
function checkPassed(message) {
console.log(`✅ ${message}`);
}
// 1. 检查必要文件
console.log('📁 Checking required files...');
const requiredFiles = [
'package.json',
'server.js',
'setup.js',
'bin/icss-mcp.js',
'bin/install.js',
'scripts/fetch-issues.js',
'scripts/fetch-inspiration.js',
'test-server.js',
'test-inspiration.js',
'README.md',
'README.en.md',
'LICENSE'
];
requiredFiles.forEach(file => {
const filePath = path.join(rootDir, file);
if (fs.existsSync(filePath)) {
checkPassed(`Required file exists: ${file}`);
} else {
checkFailed(`Missing required file: ${file}`);
}
});
// 2. 检查 package.json
console.log('\n📦 Checking package.json...');
try {
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
if (packageJson.name === 'icss-mcp-server') {
checkPassed('Package name is correct');
} else {
checkFailed(`Package name should be icss-mcp-server, got: ${packageJson.name}`);
}
if (packageJson.version === '1.1.1') {
checkPassed(`Version is updated to v1.1.1`);
} else {
checkFailed(`Version should be 1.1.1, got: ${packageJson.version}`);
}
if (packageJson.bin && packageJson.bin['icss-mcp'] && packageJson.bin['icss-mcp-install']) {
checkPassed('CLI commands are defined');
} else {
checkFailed('CLI commands are missing in package.json');
}
if (packageJson.files && packageJson.files.length > 0) {
checkPassed('Files array is defined');
} else {
checkFailed('Files array is missing or empty');
}
// 检查新的脚本命令
const requiredScripts = ['build:inspiration', 'build:all', 'test:inspiration', 'test:all'];
requiredScripts.forEach(script => {
if (packageJson.scripts && packageJson.scripts[script]) {
checkPassed(`Script '${script}' is defined`);
} else {
checkFailed(`Missing script: ${script}`);
}
});
} catch (error) {
checkFailed(`Failed to parse package.json: ${error.message}`);
}
// 3. 检查 CLI 脚本权限
console.log('\n🔧 Checking CLI scripts...');
const cliScripts = ['bin/icss-mcp.js', 'bin/install.js'];
cliScripts.forEach(script => {
const scriptPath = path.join(rootDir, script);
try {
const stats = fs.statSync(scriptPath);
if (stats.mode & parseInt('111', 8)) {
checkPassed(`${script} is executable`);
} else {
checkFailed(`${script} is not executable`);
}
const content = fs.readFileSync(scriptPath, 'utf8');
if (content.startsWith('#!/usr/bin/env node')) {
checkPassed(`${script} has correct shebang`);
} else {
checkFailed(`${script} is missing shebang`);
}
// 检查版本信息
if (content.includes('v1.1.1')) {
checkPassed(`${script} includes version v1.1.1`);
} else {
checkFailed(`${script} missing version v1.1.1`);
}
} catch (error) {
checkFailed(`Failed to check ${script}: ${error.message}`);
}
});
// 4. 检查依赖
console.log('\n📚 Checking dependencies...');
try {
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
const requiredDeps = [
'@modelcontextprotocol/sdk',
'sqlite3',
'fuse.js',
'axios',
'marked',
'dotenv',
'cheerio'
];
requiredDeps.forEach(dep => {
if (packageJson.dependencies && packageJson.dependencies[dep]) {
checkPassed(`Dependency ${dep} is included`);
} else {
checkFailed(`Missing dependency: ${dep}`);
}
});
} catch (error) {
checkFailed(`Failed to check dependencies: ${error.message}`);
}
// 5. 检查数据库
console.log('\n🗄️ Checking database...');
const dbPath = path.join(rootDir, 'data', 'icss.db');
if (fs.existsSync(dbPath)) {
try {
const stats = fs.statSync(dbPath);
if (stats.size > 1024) { // At least 1KB
checkPassed(`Database file exists and has content (${Math.round(stats.size / 1024)}KB)`);
} else {
checkFailed('Database file is too small (might be empty)');
}
} catch (error) {
checkFailed(`Failed to check database: ${error.message}`);
}
} else {
console.log('⚠️ Database file not found (will be created on first run)');
}
// 6. 检查新增功能文件
console.log('\n🎨 Checking CSS-Inspiration integration...');
const inspirationFiles = [
'scripts/fetch-inspiration.js',
'test-inspiration.js'
];
inspirationFiles.forEach(file => {
const filePath = path.join(rootDir, file);
if (fs.existsSync(filePath)) {
checkPassed(`CSS-Inspiration file exists: ${file}`);
// 检查文件内容
const content = fs.readFileSync(filePath, 'utf8');
if (content.includes('css_inspiration') || content.includes('CSS-Inspiration')) {
checkPassed(`${file} contains CSS-Inspiration logic`);
} else {
checkFailed(`${file} missing CSS-Inspiration references`);
}
} else {
checkFailed(`Missing CSS-Inspiration file: ${file}`);
}
});
// 7. 检查 README
console.log('\n📖 Checking README files...');
const readmeFiles = ['README.md', 'README.en.md'];
readmeFiles.forEach(readmeFile => {
try {
const readme = fs.readFileSync(path.join(rootDir, readmeFile), 'utf8');
if (readme.includes('# iCSS MCP Server')) {
checkPassed(`${readmeFile} has correct title`);
} else {
checkFailed(`${readmeFile} title is incorrect`);
}
if (readme.includes('CSS-Inspiration')) {
checkPassed(`${readmeFile} mentions CSS-Inspiration integration`);
} else {
checkFailed(`${readmeFile} missing CSS-Inspiration references`);
}
if (readme.includes('npm install -g icss-mcp-server')) {
checkPassed(`${readmeFile} includes installation instructions`);
} else {
checkFailed(`${readmeFile} missing installation instructions`);
}
if (readme.length > 1000) {
checkPassed(`${readmeFile} has sufficient content`);
} else {
checkFailed(`${readmeFile} is too short`);
}
} catch (error) {
checkFailed(`Failed to check ${readmeFile}: ${error.message}`);
}
});
// 8. 检查 LICENSE
console.log('\n⚖️ Checking LICENSE...');
try {
const license = fs.readFileSync(path.join(rootDir, 'LICENSE'), 'utf8');
if (license.includes('MIT License')) {
checkPassed('LICENSE is MIT');
} else {
checkFailed('LICENSE is not MIT or incorrectly formatted');
}
} catch (error) {
checkFailed(`Failed to check LICENSE: ${error.message}`);
}
// 9. 检查服务器版本
console.log('\n🖥️ Checking server version...');
try {
const serverContent = fs.readFileSync(path.join(rootDir, 'server.js'), 'utf8');
if (serverContent.includes('1.1.1')) {
checkPassed('Server.js includes version 1.1.1');
} else {
checkFailed('Server.js missing version 1.1.1');
}
// 检查新的 MCP 功能
const newFunctions = ['search_css_demos', 'get_css_demo'];
newFunctions.forEach(func => {
if (serverContent.includes(func)) {
checkPassed(`Server includes new function: ${func}`);
} else {
checkFailed(`Server missing new function: ${func}`);
}
});
} catch (error) {
checkFailed(`Failed to check server.js: ${error.message}`);
}
// 总结
console.log('\n' + '='.repeat(50));
if (allPassed) {
console.log('🎉 All checks passed! Ready to publish v1.1.1.');
console.log('\n📋 New features in v1.1.1:');
console.log(' • Integrated CSS-Inspiration with 160+ demos');
console.log(' • Added search_css_demos and get_css_demo functions');
console.log(' • Enhanced CLI with better error handling');
console.log(' • Updated documentation and examples');
console.log('\n📋 To publish:');
console.log(' npm publish');
console.log('\n📋 After publishing:');
console.log(' npm install -g icss-mcp-server');
console.log(' icss-mcp-install');
process.exit(0);
} else {
console.log('❌ Some checks failed. Please fix the issues before publishing.');
process.exit(1);
}
================================================
FILE: MCP/server.js
================================================
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import Database from 'sqlite3';
import Fuse from 'fuse.js';
import { marked } from 'marked';
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
dotenv.config();
// 调试模式检测
const isDebugMode = process.env.NODE_ENV === 'development' || process.env.DEBUG;
const debugLog = (...args) => {
if (isDebugMode) {
console.error(`[DEBUG ${new Date().toISOString()}]`, ...args);
}
};
class IcssServer {
constructor() {
debugLog('🚀 Initializing iCSS MCP Server in debug mode');
this.server = new Server(
{
name: 'icss-mcp-server',
version: '1.1.1',
},
{
capabilities: {
tools: {},
},
}
);
this.db = null;
this.searchEngine = null;
this.isReady = false;
this.dbInitFailed = false;
this.setupDatabase();
this.setupHandlers();
}
setupDatabase() {
debugLog('📂 Setting up database connection...');
// 更健壮的数据库路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dbPath = path.join(__dirname, 'data', 'icss.db');
debugLog(`📍 Database path: ${dbPath}`);
this.db = new Database.Database(dbPath, (err) => {
if (err) {
console.error('❌ Error opening database:', err);
this.dbInitFailed = true;
} else {
debugLog('✅ Connected to SQLite database');
this.initializeDatabase();
}
});
}
initializeDatabase() {
debugLog('🔧 Initializing database tables...');
const createTableSQL = `
CREATE TABLE IF NOT EXISTS issues (
id INTEGER PRIMARY KEY,
number INTEGER UNIQUE,
title TEXT NOT NULL,
body TEXT,
html_url TEXT,
labels TEXT,
created_at TEXT,
updated_at TEXT,
search_content TEXT
)
`;
this.db.run(createTableSQL, (err) => {
if (err) {
console.error('❌ Error creating table:', err);
this.dbInitFailed = true;
} else {
debugLog('✅ Database table initialized');
this.loadSearchIndex();
}
});
}
loadSearchIndex() {
debugLog('🔍 Loading search index...');
this.db.all('SELECT * FROM issues', (err, rows) => {
if (err) {
console.error('❌ Error loading search index:', err);
this.dbInitFailed = true;
return;
}
debugLog(`📊 Loaded ${rows.length} articles for search index`);
const fuseOptions = {
keys: [
{ name: 'title', weight: 0.4 },
{ name: 'search_content', weight: 0.4 },
{ name: 'labels', weight: 0.2 }
],
threshold: 0.6, // 提高阈值以允许更多匹配
includeScore: true,
includeMatches: true,
useExtendedSearch: true, // 启用扩展搜索
ignoreLocation: true, // 忽略位置影响
findAllMatches: true, // 查找所有匹配项
minMatchCharLength: 1 // 最小匹配字符长度,有助于中文匹配
};
this.searchEngine = new Fuse(rows, fuseOptions);
this.isReady = true;
debugLog(`🎉 Search index loaded with ${rows.length} articles - Server ready!`);
console.error(`✅ iCSS MCP Server ready! (Debug mode: ${isDebugMode})`);
});
}
async waitForReady(timeout = 10000) {
debugLog(`⏳ Waiting for server to be ready (timeout: ${timeout}ms)`);
const startTime = Date.now();
while (!this.isReady && !this.dbInitFailed) {
if (Date.now() - startTime > timeout) {
debugLog('⚠️ Server initialization timeout');
throw new McpError(
ErrorCode.InternalError,
'Server initialization timeout'
);
}
await new Promise(resolve => setTimeout(resolve, 100));
}
if (this.dbInitFailed) {
debugLog('❌ Server initialization failed');
throw new McpError(
ErrorCode.InternalError,
'Server initialization failed'
);
}
debugLog('✅ Server is ready');
}
setupHandlers() {
debugLog('🔗 Setting up request handlers...');
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
try {
debugLog('📋 Received ListTools request');
await this.waitForReady();
const tools = [
{
name: 'search_css_techniques',
description: 'Search for CSS techniques and solutions from iCSS repository issues',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query for CSS techniques (e.g., "flex layout", "animation", "grid")'
},
limit: {
type: 'number',
description: 'Maximum number of results to return (default: 5)',
default: 5
}
},
required: ['query']
}
},
{
name: 'search_css_demos',
description: 'Search for CSS demo examples from CSS-Inspiration repository with complete code',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query for CSS demos (e.g., "animation", "3d effect", "layout")'
},
category: {
type: 'string',
description: 'Filter by category (e.g., "animation", "3d", "layout", "background")'
},
difficulty: {
type: 'string',
description: 'Filter by difficulty level (初级, 中级, 高级)'
},
limit: {
type: 'number',
description: 'Maximum number of results to return (default: 5)',
default: 5
}
},
required: ['query']
}
},
{
name: 'get_css_demo',
description: 'Get complete demo with HTML and CSS code for a specific CSS-Inspiration example',
inputSchema: {
type: 'object',
properties: {
demo_id: {
type: 'number',
description: 'CSS-Inspiration demo ID'
}
},
required: ['demo_id']
}
},
{
name: 'get_css_article',
description: 'Get detailed content of a specific CSS article by issue number',
inputSchema: {
type: 'object',
properties: {
issue_number: {
type: 'number',
description: 'GitHub issue number of the article'
}
},
required: ['issue_number']
}
},
{
name: 'list_css_categories',
description: 'List available CSS technique categories from both iCSS and CSS-Inspiration',
inputSchema: {
type: 'object',
properties: {
source: {
type: 'string',
description: 'Filter by source: "icss", "inspiration", or "all" (default: all)'
}
}
}
},
{
name: 'get_random_css_tip',
description: 'Get a random CSS technique or tip from the collection',
inputSchema: {
type: 'object',
properties: {
source: {
type: 'string',
description: 'Source preference: "icss", "inspiration", or "both" (default: both)'
}
}
}
}
];
debugLog(`📋 Returning ${tools.length} tools`);
return { tools };
} catch (error) {
debugLog('❌ Error in ListTools:', error);
throw error;
}
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
debugLog(`🔧 Received CallTool request: ${name}`, args);
try {
await this.waitForReady();
let result;
switch (name) {
case 'search_css_techniques':
debugLog(`🔍 Executing search: "${args.query}" (limit: ${args.limit || 5})`);
result = await this.searchCssTechniques(args.query, args.limit || 5);
return result;
case 'search_css_demos':
debugLog(`🎨 Searching CSS demos: "${args.query}" (category: ${args.category || 'all'}, difficulty: ${args.difficulty || 'all'})`);
result = await this.searchCssDemos(args.query, args.category, args.difficulty, args.limit || 5);
return result;
case 'get_css_demo':
debugLog(`🎯 Fetching CSS demo #${args.demo_id}`);
result = await this.getCssDemo(args.demo_id);
return result;
case 'get_css_article':
debugLog(`📖 Fetching article #${args.issue_number}`);
result = await this.getCssArticle(args.issue_number);
return result;
case 'list_css_categories':
debugLog(`🏷️ Listing CSS categories (source: ${args.source || 'all'})`);
result = await this.listCssCategories(args.source);
return result;
case 'get_random_css_tip':
debugLog(`🎲 Getting random CSS tip (source: ${args.source || 'both'})`);
result = await this.getRandomCssTip(args.source);
return result;
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error) {
debugLog(`❌ Error in ${name}:`, error);
throw error;
}
});
}
async searchCssTechniques(query, limit = 5) {
debugLog(`[DEBUG] searchCssTechniques called with query: "${query}", limit: ${limit}`);
debugLog(`[DEBUG] Search engine ready: ${this.isReady}`);
return new Promise((resolve, reject) => {
const startTime = Date.now();
debugLog(`[DEBUG] Starting search at ${new Date().toISOString()}`);
try {
// 处理中文搜索词
const searchTerms = query.split(/\s+/).filter(Boolean);
let results = [];
// 对每个搜索词分别进行搜索
searchTerms.forEach(term => {
const termResults = this.searchEngine.search(term);
results = results.concat(termResults);
});
// 去重并按相关度排序
results = Array.from(new Set(results.map(r => r.item.number)))
.map(number => results.find(r => r.item.number === number))
.sort((a, b) => a.score - b.score)
.slice(0, limit);
const endTime = Date.now();
debugLog(`[DEBUG] Search completed in ${endTime - startTime}ms, found ${results.length} results`);
const formattedResults = results.map(result => {
const item = result.item;
const matches = result.matches?.map(match => ({
key: match.key,
value: match.value.substring(0, 100) + '...'
})) || [];
return {
title: item.title,
issue_number: item.number,
url: item.html_url,
labels: item.labels ? JSON.parse(item.labels) : [],
score: Math.round((1 - result.score) * 100),
preview: this.extractPreview(item.body),
matches: matches
};
});
debugLog(`[DEBUG] Formatted ${formattedResults.length} results, returning response`);
resolve({
content: [
{
type: 'text',
text: `Found ${formattedResults.length} CSS techniques for "${query}":\n\n` +
formattedResults.map((result, index) =>
`${index + 1}. **${result.title}** (Issue #${result.issue_number})\n` +
` 💯 Relevance: ${result.score}%\n` +
` 🏷️ Tags: ${result.labels.join(', ')}\n` +
` 📝 Preview: ${result.preview}\n` +
` 🔗 Link: ${result.url}\n`
).join('\n')
}
]
});
} catch (error) {
debugLog(`[DEBUG] Search failed with error:`, error);
reject(error);
}
});
}
async getCssArticle(issueNumber) {
debugLog(`📖 Getting article #${issueNumber}`);
return new Promise((resolve, reject) => {
this.db.get(
'SELECT * FROM issues WHERE number = ?',
[issueNumber],
(err, row) => {
if (err) {
debugLog(`❌ Database error for article #${issueNumber}:`, err);
reject(err);
return;
}
if (!row) {
debugLog(`❌ Article #${issueNumber} not found`);
reject(new Error(`Article with issue number ${issueNumber} not found`));
return;
}
debugLog(`✅ Found article #${issueNumber}: "${row.title}"`);
const htmlContent = marked(row.body || '');
const labels = row.labels ? JSON.parse(row.labels) : [];
resolve({
content: [
{
type: 'text',
text: `# ${row.title}\n\n` +
`**Issue #${row.number}** | **Updated:** ${new Date(row.updated_at).toLocaleDateString()}\n\n` +
`**Tags:** ${labels.join(', ')}\n\n` +
`**GitHub Link:** ${row.html_url}\n\n` +
`---\n\n${row.body}`
}
]
});
}
);
});
}
async searchCssDemos(query, category, difficulty, limit = 5) {
debugLog(`🎨 Searching CSS demos with query: "${query}"`);
return new Promise((resolve, reject) => {
let sql = `
SELECT * FROM css_inspiration
WHERE search_content LIKE ?
`;
let params = [`%${query}%`];
if (category) {
sql += ` AND category = ?`;
params.push(category);
}
if (difficulty) {
sql += ` AND difficulty_level = ?`;
params.push(difficulty);
}
sql += ` ORDER BY title LIMIT ?`;
params.push(limit);
this.db.all(sql, params, (err, rows) => {
if (err) {
debugLog('❌ Error searching CSS demos:', err);
reject(err);
return;
}
debugLog(`✅ Found ${rows.length} CSS demos`);
const formattedResults = rows.map(row => {
const tags = JSON.parse(row.tags || '[]');
const browserSupport = JSON.parse(row.browser_support || '{}');
return {
id: row.id,
title: row.title,
category: row.category,
difficulty: row.difficulty_level,
description: row.description,
tags: tags,
demo_url: row.demo_url,
source_url: row.source_url,
browser_support: browserSupport
};
});
resolve({
content: [
{
type: 'text',
text: `Found ${formattedResults.length} CSS demos for "${query}":\n\n` +
formattedResults.map((demo, index) =>
`${index + 1}. **${demo.title}** (ID: ${demo.id})\n` +
` 🏷️ Category: ${demo.category} | Difficulty: ${demo.difficulty}\n` +
` 📝 ${demo.description}\n` +
` 🏆 Tags: ${demo.tags.join(', ')}\n` +
` 🔗 Demo: ${demo.demo_url}\n` +
` 📁 Source: ${demo.source_url}\n`
).join('\n')
}
]
});
});
});
}
async getCssDemo(demoId) {
debugLog(`🎯 Getting CSS demo #${demoId}`);
return new Promise((resolve, reject) => {
// 获取基本信息
this.db.get(
'SELECT * FROM css_inspiration WHERE id = ?',
[demoId],
(err, row) => {
if (err) {
debugLog(`❌ Database error for demo #${demoId}:`, err);
reject(err);
return;
}
if (!row) {
debugLog(`❌ Demo #${demoId} not found`);
reject(new Error(`CSS demo with ID ${demoId} not found`));
return;
}
// 获取完整的演示代码
this.db.get(
'SELECT * FROM demo_styles WHERE inspiration_id = ?',
[demoId],
(err, demoRow) => {
if (err) {
debugLog(`❌ Error getting demo styles for #${demoId}:`, err);
reject(err);
return;
}
debugLog(`✅ Found demo #${demoId}: "${row.title}"`);
const tags = JSON.parse(row.tags || '[]');
const browserSupport = JSON.parse(row.browser_support || '{}');
resolve({
content: [
{
type: 'text',
text: `# ${row.title}\n\n` +
`**Category:** ${row.category} | **Difficulty:** ${row.difficulty_level}\n\n` +
`**Description:** ${row.description}\n\n` +
`**Tags:** ${tags.join(', ')}\n\n` +
`**Browser Support:**\n` +
Object.entries(browserSupport).map(([browser, support]) =>
`- ${browser}: ${support}`
).join('\n') + '\n\n' +
`## HTML Code\n\n\`\`\`html\n${row.html_content || '<div class="demo">Demo</div>'}\n\`\`\`\n\n` +
`## CSS Code\n\n\`\`\`css\n${row.css_content}\n\`\`\`\n\n` +
(demoRow ? `## Complete Demo\n\n\`\`\`html\n${demoRow.complete_html}\n\`\`\`\n\n` : '') +
`**Demo URL:** ${row.demo_url}\n` +
`**Source:** ${row.source_url}`
}
]
});
}
);
}
);
});
}
async listCssCategories(source = 'all') {
debugLog(`🏷️ Listing CSS categories (source: ${source})`);
return new Promise((resolve, reject) => {
let promises = [];
// iCSS categories
if (source === 'all' || source === 'icss') {
promises.push(
new Promise((resolve, reject) => {
this.db.all(
'SELECT labels, COUNT(*) as count FROM issues WHERE labels IS NOT NULL GROUP BY labels',
(err, rows) => {
if (err) {
reject(err);
return;
}
const categoryMap = new Map();
rows.forEach(row => {
if (row.labels) {
const labels = JSON.parse(row.labels);
labels.forEach(label => {
categoryMap.set(label, (categoryMap.get(label) || 0) + row.count);
});
}
});
const categories = Array.from(categoryMap.entries())
.sort((a, b) => b[1] - a[1])
.map(([label, count]) => ({
label,
count,
source: 'iCSS',
type: 'article'
}));
resolve(categories);
}
);
})
);
}
// CSS-Inspiration categories
if (source === 'all' || source === 'inspiration') {
promises.push(
new Promise((resolve, reject) => {
this.db.all(
'SELECT category, COUNT(*) as count FROM css_inspiration GROUP BY category ORDER BY count DESC',
(err, rows) => {
if (err) {
reject(err);
return;
}
const categories = rows.map(row => ({
label: row.category,
count: row.count,
source: 'CSS-Inspiration',
type: 'demo'
}));
resolve(categories);
}
);
})
);
}
Promise.all(promises)
.then(results => {
const allCategories = results.flat();
debugLog(`✅ Found ${allCategories.length} categories`);
let output = `Available CSS technique categories:\n\n`;
if (source === 'all') {
// 按来源分组显示
const iCSSCategories = allCategories.filter(cat => cat.source === 'iCSS');
const inspirationCategories = allCategories.filter(cat => cat.source === 'CSS-Inspiration');
if (iCSSCategories.length > 0) {
output += `## iCSS Articles (${iCSSCategories.length} categories)\n`;
output += iCSSCategories.map(cat =>
`• **${cat.label}** (${cat.count} articles)`
).join('\n') + '\n\n';
}
if (inspirationCategories.length > 0) {
output += `## CSS-Inspiration Demos (${inspirationCategories.length} categories)\n`;
output += inspirationCategories.map(cat =>
`• **${cat.label}** (${cat.count} demos)`
).join('\n');
}
} else {
output += allCategories.map(cat =>
`• **${cat.label}** (${cat.count} ${cat.type}s) - ${cat.source}`
).join('\n');
}
resolve({
content: [
{
type: 'text',
text: output
}
]
});
})
.catch(reject);
});
}
async getRandomCssTip(source = 'both') {
debugLog(`🎲 Getting random CSS tip (source: ${source})`);
return new Promise((resolve, reject) => {
let queries = [];
if (source === 'both' || source === 'icss') {
queries.push({
sql: 'SELECT *, "icss" as source_type FROM issues ORDER BY RANDOM() LIMIT 1',
params: []
});
}
if (source === 'both' || source === 'inspiration') {
queries.push({
sql: 'SELECT *, "inspiration" as source_type FROM css_inspiration ORDER BY RANDOM() LIMIT 1',
params: []
});
}
// 随机选择一个查询
const randomQuery = queries[Math.floor(Math.random() * queries.length)];
this.db.get(randomQuery.sql, randomQuery.params, (err, row) => {
if (err) {
debugLog('❌ Error getting random tip:', err);
reject(err);
return;
}
if (!row) {
reject(new Error('No content available'));
return;
}
if (row.source_type === 'icss') {
debugLog(`✅ Random iCSS tip: "${row.title}" (Issue #${row.number})`);
const labels = row.labels ? JSON.parse(row.labels) : [];
const preview = this.extractPreview(row.body);
resolve({
content: [
{
type: 'text',
text: `🎲 **Random CSS Tip** (from iCSS): ${row.title}\n\n` +
`**Issue #${row.number}** | **Tags:** ${labels.join(', ')}\n\n` +
`${preview}\n\n` +
`[Read full article](${row.html_url})`
}
]
});
} else {
debugLog(`✅ Random CSS-Inspiration demo: "${row.title}" (ID #${row.id})`);
const tags = row.tags ? JSON.parse(row.tags) : [];
resolve({
content: [
{
type: 'text',
text: `🎲 **Random CSS Demo** (from CSS-Inspiration): ${row.title}\n\n` +
`**Demo ID #${row.id}** | **Category:** ${row.category} | **Difficulty:** ${row.difficulty_level}\n\n` +
`**Tags:** ${tags.join(', ')}\n\n` +
`${row.description}\n\n` +
`**Demo:** ${row.demo_url}\n` +
`**Source:** ${row.source_url}\n\n` +
`💡 Use \`get_css_demo\` with ID ${row.id} to see the complete code!`
}
]
});
}
});
});
}
extractPreview(body, maxLength = 200) {
if (!body) return 'No preview available';
// Remove markdown formatting for preview
const cleanText = body
.replace(/```[\s\S]*?```/g, '[code block]')
.replace(/`([^`]+)`/g, '$1')
.replace(/[#*_~]/g, '')
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
.trim();
return cleanText.length > maxLength
? cleanText.substring(0, maxLength) + '...'
: cleanText;
}
async run() {
debugLog('🚀 Starting MCP Server transport...');
const transport = new StdioServerTransport();
debugLog('🎯 iCSS MCP Server running on stdio (Debug Mode)');
console.error('🎯 iCSS MCP Server running on stdio (Debug Mode)');
try {
await this.server.connect(transport);
} catch (error) {
debugLog('💥 Server error:', error);
console.error('❌ Fatal error:', error.message);
process.exit(1);
}
}
}
// 启动服务器
const server = new IcssServer();
server.run();
================================================
FILE: MCP/setup.js
================================================
#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class ProjectSetup {
constructor() {
this.projectRoot = __dirname;
this.dataDir = path.join(this.projectRoot, 'data');
}
async setup() {
console.log('🚀 Setting up iCSS MCP Server...\n');
// 1. 创建必要的目录
this.createDirectories();
// 2. 创建环境变量文件
this.createEnvFile();
// 3. 显示下一步指令
this.showNextSteps();
}
createDirectories() {
console.log('📁 Creating necessary directories...');
const directories = [
this.dataDir
];
directories.forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
console.log(` ✅ Created: ${path.relative(this.projectRoot, dir)}`);
} else {
console.log(` ℹ️ Already exists: ${path.relative(this.projectRoot, dir)}`);
}
});
}
createEnvFile() {
console.log('\n🔧 Creating environment configuration...');
const envPath = path.join(this.projectRoot, '.env');
const envExampleContent = `
# GitHub API Configuration (Optional - for higher rate limits)
# Get your token from: https://github.com/settings/tokens
GITHUB_TOKEN=your_github_token_here
# Server Configuration
NODE_ENV=production
PORT=3000
# Database Configuration
DB_PATH=./data/icss.db
`;
if (!fs.existsSync(envPath)) {
fs.writeFileSync(envPath, envExampleContent);
console.log(' ✅ Created .env file');
} else {
console.log(' ℹ️ .env file already exists');
}
}
showNextSteps() {
console.log('\n🎉 Setup completed! Next steps:\n');
console.log('1️⃣ Install dependencies:');
console.log(' npm install\n');
console.log('2️⃣ Fetch iCSS repository data:');
console.log(' npm run fetch-issues\n');
console.log('3️⃣ Test the server:');
console.log(' npm start\n');
console.log('4️⃣ Configure Cursor IDE:');
console.log(' Add this to your MCP settings (~/.config/cursor/mcp_settings.json):');
console.log(' {');
console.log(' "mcpServers": {');
console.log(' "icss": {');
console.log(` "command": "node",`);
console.log(` "args": ["${path.resolve(this.projectRoot, 'server.js')}"],`);
console.log(' "env": {}');
console.log(' }');
console.log(' }');
console.log(' }\n');
console.log('5️⃣ Restart Cursor IDE to load the MCP server\n');
console.log('📚 For more information, see README.md');
}
}
const setup = new ProjectSetup();
setup.setup().catch(console.error);
================================================
FILE: MCP/test-inspiration.js
================================================
#!/usr/bin/env node
import Database from 'sqlite3';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class InspirationTester {
constructor() {
this.dbPath = path.join(__dirname, 'data', 'icss.db');
this.db = new Database.Database(this.dbPath, (err) => {
if (err) {
console.error('❌ Error opening database:', err);
process.exit(1);
}
});
}
async testDatabaseIntegrity() {
console.log('🔍 Testing database integrity...\n');
// 测试表是否存在
const tables = [
'issues',
'css_inspiration',
'code_snippets',
'demo_styles'
];
for (const table of tables) {
await this.checkTable(table);
}
}
checkTable(tableName) {
return new Promise((resolve, reject) => {
this.db.get(
`SELECT COUNT(*) as count FROM ${tableName}`,
(err, row) => {
if (err) {
console.error(`❌ Table ${tableName} error:`, err.message);
reject(err);
} else {
console.log(`✅ Table ${tableName}: ${row.count} records`);
resolve(row.count);
}
}
);
});
}
async testSearchFunctionality() {
console.log('\n🔍 Testing search functionality...\n');
// 测试 CSS-Inspiration 搜索
await this.testQuery(
'CSS-Inspiration Search',
`SELECT * FROM css_inspiration WHERE search_content LIKE '%动画%' LIMIT 3`
);
// 测试分类统计
await this.testQuery(
'Category Statistics',
`SELECT category, COUNT(*) as count FROM css_inspiration GROUP BY category ORDER BY count DESC LIMIT 5`
);
// 测试难度分布
await this.testQuery(
'Difficulty Distribution',
`SELECT difficulty_level, COUNT(*) as count FROM css_inspiration GROUP BY difficulty_level`
);
}
testQuery(testName, sql) {
return new Promise((resolve, reject) => {
this.db.all(sql, (err, rows) => {
if (err) {
console.error(`❌ ${testName} failed:`, err.message);
reject(err);
} else {
console.log(`✅ ${testName}: ${rows.length} results`);
if (rows.length > 0) {
console.log(' Sample results:');
rows.slice(0, 2).forEach((row, index) => {
console.log(` ${index + 1}.`, Object.keys(row).slice(0, 3).map(key =>
`${key}: ${String(row[key]).substring(0, 30)}`
).join(', '));
});
}
console.log('');
resolve(rows);
}
});
});
}
async testCodeSnippets() {
console.log('🔍 Testing code snippets...\n');
await this.testQuery(
'Code Snippets by Type',
`SELECT snippet_type, COUNT(*) as count FROM code_snippets GROUP BY snippet_type`
);
await this.testQuery(
'Sample CSS Snippets',
`SELECT * FROM code_snippets WHERE snippet_type = 'css' LIMIT 2`
);
}
async testDemoStyles() {
console.log('🔍 Testing demo styles...\n');
await this.testQuery(
'Interactive Demos',
`SELECT COUNT(*) as count FROM demo_styles WHERE is_interactive = 1`
);
await this.testQuery(
'Sample Demo',
`SELECT
ci.title,
ci.category,
ds.is_interactive
FROM css_inspiration ci
JOIN demo_styles ds ON ci.id = ds.inspiration_id
LIMIT 3`
);
}
async generateReport() {
console.log('📊 Generating comprehensive report...\n');
const stats = {};
// iCSS 统计
stats.icss = await new Promise((resolve) => {
this.db.get('SELECT COUNT(*) as count FROM issues', (err, row) => {
resolve(err ? 0 : row.count);
});
});
// CSS-Inspiration 统计
stats.inspiration = await new Promise((resolve) => {
this.db.get('SELECT COUNT(*) as count FROM css_inspiration', (err, row) => {
resolve(err ? 0 : row.count);
});
});
// 代码片段统计
stats.snippets = await new Promise((resolve) => {
this.db.get('SELECT COUNT(*) as count FROM code_snippets', (err, row) => {
resolve(err ? 0 : row.count);
});
});
// 演示样式统计
stats.demos = await new Promise((resolve) => {
this.db.get('SELECT COUNT(*) as count FROM demo_styles', (err, row) => {
resolve(err ? 0 : row.count);
});
});
console.log('📈 Database Statistics Summary:');
console.log(` iCSS Articles: ${stats.icss}`);
console.log(` CSS-Inspiration Demos: ${stats.inspiration}`);
console.log(` Code Snippets: ${stats.snippets}`);
console.log(` Demo Styles: ${stats.demos}`);
console.log(` Total Records: ${stats.icss + stats.inspiration + stats.snippets + stats.demos}`);
}
async runAllTests() {
try {
await this.testDatabaseIntegrity();
await this.testSearchFunctionality();
await this.testCodeSnippets();
await this.testDemoStyles();
await this.generateReport();
console.log('\n🎉 All tests completed successfully!');
console.log('\n💡 You can now use the enhanced iCSS MCP Server with both iCSS articles and CSS-Inspiration demos!');
} catch (error) {
console.error('\n❌ Test failed:', error.message);
} finally {
this.db.close();
}
}
close() {
this.db.close();
}
}
// 运行测试
console.log('🚀 Starting iCSS MCP Server Integration Tests...\n');
const tester = new InspirationTester();
tester.runAllTests().catch(console.error);
// 优雅关闭
process.on('SIGINT', () => {
console.log('\n⏹️ Shutting down...');
tester.close();
process.exit(0);
});
================================================
FILE: MCP/test-server.js
================================================
#!/usr/bin/env node
import Database from 'sqlite3';
import Fuse from 'fuse.js';
console.log('🧪 Testing iCSS MCP Server functionality...\n');
// 测试数据库连接
function testDatabase() {
return new Promise((resolve, reject) => {
console.log('1️⃣ Testing database connection...');
const db = new Database.Database('./data/icss.db', (err) => {
if (err) {
console.error('❌ Database connection failed:', err.message);
reject(err);
return;
}
console.log('✅ Database connected successfully');
// 测试数据查询
db.all('SELECT COUNT(*) as total FROM issues', (err, rows) => {
if (err) {
console.error('❌ Database query failed:', err.message);
reject(err);
return;
}
console.log(`✅ Found ${rows[0].total} articles in database`);
// 测试搜索功能
testSearch(db, resolve, reject);
});
});
});
}
// 测试搜索功能
function testSearch(db, resolve, reject) {
console.log('\n2️⃣ Testing search functionality...');
db.all('SELECT * FROM issues LIMIT 10', (err, rows) => {
if (err) {
console.error('❌ Search test failed:', err.message);
reject(err);
return;
}
if (rows.length === 0) {
console.error('❌ No data found for search test');
reject(new Error('No data found'));
return;
}
console.log('✅ Sample data retrieved successfully');
console.log(`✅ First article: "${rows[0].title}"`);
// 测试Fuse.js搜索
const fuseOptions = {
keys: [
{ name: 'title', weight: 0.4 },
{ name: 'search_content', weight: 0.4 },
{ name: 'labels', weight: 0.2 }
],
threshold: 0.3,
includeScore: true
};
const fuse = new Fuse(rows, fuseOptions);
const results = fuse.search('flex');
console.log(`✅ Search test completed: found ${results.length} results for "flex"`);
db.close();
resolve();
});
}
// 测试MCP SDK导入
function testMCPSDK() {
console.log('\n3️⃣ Testing MCP SDK...');
try {
import('@modelcontextprotocol/sdk/server/index.js').then(() => {
console.log('✅ MCP SDK imported successfully');
console.log('\n🎉 All tests passed! The server should work correctly.\n');
console.log('📋 Next steps:');
console.log('1. Make sure Cursor MCP configuration is correct');
console.log('2. Check Cursor logs for any connection issues');
console.log('3. Restart Cursor after configuration changes');
console.log('\n🔧 Cursor Configuration:');
console.log('File: ~/.config/cursor/mcp_settings.json');
console.log('Content:');
console.log(JSON.stringify({
mcpServers: {
icss: {
command: "node",
args: [process.cwd() + "/server.js"],
env: {}
}
}
}, null, 2));
}).catch(err => {
console.error('❌ MCP SDK import failed:', err.message);
console.log('\n💡 Try reinstalling dependencies: npm install');
});
} catch (err) {
console.error('❌ MCP SDK test failed:', err.message);
}
}
// 运行测试
testDatabase()
.then(() => {
testMCPSDK();
})
.catch(err => {
console.error('❌ Test failed:', err.message);
process.exit(1);
});
================================================
FILE: readme.md
================================================
## 
CSS 奇技淫巧,在这里,都有。
本 Repo 围绕 **CSS/Web动画** 展开,谈一些有趣的话题,内容天马行空,想到什么说什么,不仅是为了拓宽解决问题的思路,更涉及一些容易忽视或是十分有趣的 CSS 细节。
所有内容都在 [Issues](https://github.com/chokcoco/iCSS/issues) 中,同步更新到我的[个人博客](http://www.cnblogs.com/coco1s/),觉得不错的可以点个 `star` 收藏支持。
### 按分类进行阅读
[](https://github.com/chokcoco/iCSS/labels/Background) [](https://github.com/chokcoco/iCSS/labels/Border) [](https://github.com/chokcoco/iCSS/labels/clip-path) [](https://github.com/chokcoco/iCSS/labels/Mask) [](https://github.com/chokcoco/iCSS/labels/Shadow) [](https://github.com/chokcoco/iCSS/labels/Shape) [](https://github.com/chokcoco/iCSS/labels/混合模式) [](https://github.com/chokcoco/iCSS/labels/滤镜) [](https://github.com/chokcoco/iCSS/labels/伪类)
[](https://github.com/chokcoco/iCSS/labels/Layout) [](https://github.com/chokcoco/iCSS/labels/CSS%20Function) [](https://github.com/chokcoco/iCSS/labels/CSS%20Houdini) [](https://github.com/chokcoco/iCSS/labels/CSS%20Variable) [](https://github.com/chokcoco/iCSS/labels/CSS%20新特性) [](https://github.com/chokcoco/iCSS/labels/CSS-doodle) [](https://github.com/chokcoco/iCSS/labels/Modern%20CSS)
[](https://github.com/chokcoco/iCSS/labels/动效) [](https://github.com/chokcoco/iCSS/labels/动画) [](https://github.com/chokcoco/iCSS/labels/可访问性(Accessibility)) [](https://github.com/chokcoco/iCSS/labels/3D) [](https://github.com/chokcoco/iCSS/labels/图片效果) [](https://github.com/chokcoco/iCSS/labels/文字效果) [](https://github.com/chokcoco/iCSS/labels/边框效果)
[](https://github.com/chokcoco/iCSS/labels/SVG) [](https://github.com/chokcoco/iCSS/labels/奇技淫巧) [](https://github.com/chokcoco/iCSS/labels/性能) [](https://github.com/chokcoco/iCSS/labels/技巧) [](https://github.com/chokcoco/iCSS/labels/浏览器特性) [](https://github.com/chokcoco/iCSS/labels/特殊交互) [](https://github.com/chokcoco/iCSS/labels/用户体验) [](https://github.com/chokcoco/iCSS/labels/翻译) [](https://github.com/chokcoco/iCSS/labels/设计) [](https://github.com/chokcoco/iCSS/labels/面试) [](https://github.com/chokcoco/iCSS/labels/Bug)
## iCSS 前端趣闻
所有内容首发更新到我的**公众号**:
<img width=160 src="https://raw.githubusercontent.com/chokcoco/chokcoco/main/qrcode_big.png" />
## LIST
#### 220、[浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析](https://github.com/chokcoco/iCSS/issues/275)

#### 219、[巧用 CSS 实现高频出现的复杂怪状按钮 - 内凹平滑圆角](https://github.com/chokcoco/iCSS/issues/272)

#### 218、[巧用 CSS 实现高频出现的复杂怪状按钮 - 镂空的内凹圆角边框](https://github.com/chokcoco/iCSS/issues/271)

#### 217、[【动画进阶】单标签实现多行文本随滚动颜色变换](https://github.com/chokcoco/iCSS/issues/269)

#### 216、[【现代 CSS】更强大的 :nth-child 选择器](https://github.com/chokcoco/iCSS/issues/267)
#### 215、[全尺寸的带圆角的渐变边框](https://github.com/chokcoco/iCSS/issues/266)

#### 214、[巧妙使用多种方式实现单侧阴影](https://github.com/chokcoco/iCSS/issues/265)

#### 213、[渐变边框文字效果?CSS 轻松拿捏!](https://github.com/chokcoco/iCSS/issues/264)

#### 212、[【动画进阶】神奇的卡片 Hover 效果与 Blur 的特性探究](https://github.com/chokcoco/iCSS/issues/263)

#### 211、[【动画进阶】类 ChatGpt 多行文本打字效果](https://github.com/chokcoco/iCSS/issues/262)

#### 210、[【现代 CSS】标准滚动条控制规范 scrollbar-color 和 scrollbar-width](https://github.com/chokcoco/iCSS/issues/259)

#### 209、[【动画进阶】极具创意的鼠标交互动画](https://github.com/chokcoco/iCSS/issues/258)

#### 208、[【动画进阶】巧用 CSS/SVG 实现复杂线条光效动画](https://github.com/chokcoco/iCSS/issues/257)

#### 207、[【布局进阶】巧用 :has & drop-shadow 实现复杂布局效果](https://github.com/chokcoco/iCSS/issues/256)

#### 206、[现代 CSS 解决方案:accent-color 强调色](https://github.com/chokcoco/iCSS/issues/255)

#### 205、[【动画进阶】神奇的 3D 卡片反光闪烁动效](https://github.com/chokcoco/iCSS/issues/254)

#### 204、[现代 CSS 解决方案:文字颜色自动适配背景色!](https://github.com/chokcoco/iCSS/issues/253)

#### 203、[带圆角的虚线边框?CSS 不在话下](https://github.com/chokcoco/iCSS/issues/250)

#### 202、[【布局技巧】Flex 布局下居中溢出滚动截断问题](https://github.com/chokcoco/iCSS/issues/249)

#### 201、[CSS 也能实现 if 判断?实现动态高度下的不同样式展现](https://github.com/chokcoco/iCSS/issues/248)

#### 200、[【动画进阶】单标签下多色块随机文字随机颜色动画](https://github.com/chokcoco/iCSS/issues/247)

#### 199、[CSS 还原拉斯维加斯球数字动画](https://github.com/chokcoco/iCSS/issues/246)

#### 198、[【动画进阶】神奇的背景,生化危机4日食 Loading 动画还原 ](https://github.com/chokcoco/iCSS/issues/245)

#### 197、[【动画进阶】当路径动画遇到滚动驱动!](https://github.com/chokcoco/iCSS/issues/244)

#### 196、[现代 CSS 解决方案:原生嵌套(Nesting)](https://github.com/chokcoco/iCSS/issues/243)
#### 195、[现代 CSS 解决方案:数学函数 Round](https://github.com/chokcoco/iCSS/issues/242)

#### 194、[震惊!CSS 也能实现碰撞检测?](https://github.com/chokcoco/iCSS/issues/241)

#### 193、[抢先体验!超强的 Anchor Positioning 锚点定位](https://github.com/chokcoco/iCSS/issues/239)

#### 192、[神奇的 3D 磨砂玻璃透视效果](https://github.com/chokcoco/iCSS/issues/238)

#### 191、[【动画进阶】有意思的 Emoji 3D 表情切换效果](https://github.com/chokcoco/iCSS/issues/237)

#### 190、[【动画进阶】有意思的网格下落渐次加载效果](https://github.com/chokcoco/iCSS/issues/235)

#### 189、[解放生产力!transform 支持单独赋值改变](https://github.com/chokcoco/iCSS/issues/236)
#### 188、[单标签下的日间/黑夜模式切换按钮效果](https://github.com/chokcoco/iCSS/issues/234)

#### 187、[现代 CSS 解决方案:CSS 原生支持的三角函数](https://github.com/chokcoco/iCSS/issues/233)

#### 186、[有意思的气泡 Loading 效果](https://github.com/chokcoco/iCSS/issues/231)

#### 185、[有趣的六芒星能力图动画](https://github.com/chokcoco/iCSS/issues/228)

#### 184、[CSS 高阶小技巧 - 角向渐变的妙用!](https://github.com/chokcoco/iCSS/issues/227)

#### 183、[巧用 CSS 变量,实现动画函数复用,制作高级感拉满的网格动画](https://github.com/chokcoco/iCSS/issues/226)

#### 182、[CSS 高阶技巧 -- 不定宽文本溢出跑马灯效果完美解决方案](https://github.com/chokcoco/iCSS/issues/225)

#### 181、[由小见大!不规则造型按钮解决方案](https://github.com/chokcoco/iCSS/issues/224)

#### 180、[动态视口单位之 dvh、svh、lvh](https://github.com/chokcoco/iCSS/issues/223)

#### 179、[开局一张图,构建神奇的 CSS 效果](https://github.com/chokcoco/iCSS/issues/218)

#### 178、[巧用视觉障眼法,还原 3D 文字特效](https://github.com/chokcoco/iCSS/issues/219)

#### 177、[不规则图形背景排版高阶技巧 -- 酷炫的六边形网格背景图](https://github.com/chokcoco/iCSS/issues/215)

#### 176、[现代 CSS 高阶技巧,不规则边框解决方案](https://github.com/chokcoco/iCSS/issues/221)

#### 175、[现代 CSS 高阶技巧,完美的波浪进度条效果!](https://github.com/chokcoco/iCSS/issues/220)

#### 174、[现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式!](https://github.com/chokcoco/iCSS/issues/217)

#### 173、[现代 CSS 之高阶图片渐隐消失术](https://github.com/chokcoco/iCSS/issues/214)

#### 172、[除了 filter 还有什么置灰网站的方式?](https://github.com/chokcoco/iCSS/issues/212)

#### 171、[快速构建 3D Visualization of DOM](https://github.com/chokcoco/iCSS/issues/210)

#### 170、[CSS at-rules(@) 规则扫盲](https://github.com/chokcoco/iCSS/issues/204)
#### 169、[CSS 渐变锯齿消失术](https://github.com/chokcoco/iCSS/issues/209)

#### 168、[超强的苹果官网滚动文字特效实现](https://github.com/chokcoco/iCSS/issues/208)

#### 167、[超强的纯 CSS 鼠标点击拖拽效果](https://github.com/chokcoco/iCSS/issues/207)

#### 166、[两道超有意思的 CSS 面试题,试试你的基础](https://github.com/chokcoco/iCSS/issues/206)
#### 165、[单标签实现复杂的棋盘布局](https://github.com/chokcoco/iCSS/issues/203)

#### 164、[新时代布局新特性 -- 容器查询](https://github.com/chokcoco/iCSS/issues/201)

#### 163、[有意思的水平横向溢出滚动](https://github.com/chokcoco/iCSS/issues/200)

#### 162、[高阶 CSS 技巧在复杂动效中的应用](https://github.com/chokcoco/iCSS/issues/202)
<img src="https://user-images.githubusercontent.com/8554143/187671481-5e075209-44d3-44a6-b540-4f457999ed74.gif" width="600px"/>
#### 161、[有意思的方向裁切 overflow: clip](https://github.com/chokcoco/iCSS/issues/199)

#### 160、[巧用 transition 实现短视频 APP 点赞动画](https://github.com/chokcoco/iCSS/issues/198)

#### 159、[妙啊!纯 CSS 实现拼图游戏](https://github.com/chokcoco/iCSS/issues/197)

#### 158、[多行文本下的文字渐隐消失术](https://github.com/chokcoco/iCSS/issues/196)

#### 157、[使用 CSS 构建强大且酷炫的粒子动画](https://github.com/chokcoco/iCSS/issues/195)

#### 156、[妙用 CSS 构建花式透视背景效果](https://github.com/chokcoco/iCSS/issues/194)

#### 155、[圆角大杀器,使用滤镜构建圆角及波浪效果!](https://github.com/chokcoco/iCSS/issues/192)

#### 154、[超酷炫的转场动画?CSS 轻松拿下!](https://github.com/chokcoco/iCSS/issues/191)

#### 153、[利用噪声构建美妙的 CSS 图形](https://github.com/chokcoco/iCSS/issues/190)

#### 152、[高阶切图技巧!基于单张图片的任意颜色转换](https://github.com/chokcoco/iCSS/issues/189)

#### 151、[使用纯 CSS 实现超酷炫的粘性气泡效果](https://github.com/chokcoco/iCSS/issues/188)

#### 150、[超 Nice 的表格响应式布局小技巧](https://github.com/chokcoco/iCSS/issues/187)

#### 149、[有意思的鼠标指针交互探究](https://github.com/chokcoco/iCSS/issues/186)

#### 148、[使用 content-visibility 优化渲染性能](https://github.com/chokcoco/iCSS/issues/185)
#### 147、[文字轮播与图片轮播?CSS 不在话下](https://github.com/chokcoco/iCSS/issues/184)

#### 146、[动画小技巧,通过 hover 让动画只运行一次且停留在最后一帧](https://github.com/chokcoco/iCSS/issues/182)

#### 145、[浅谈逻辑选择器 is、where、not、has](https://github.com/chokcoco/iCSS/issues/181)
#### 144、[现代 CSS 解决方案:CSS 数学函数](https://github.com/chokcoco/iCSS/issues/177)
#### 143、[离谱的 CSS!从表盘刻度到艺术剪纸](https://github.com/chokcoco/iCSS/issues/180)

#### 142、[让交互更加生动!有意思的鼠标跟随 3D 旋转动效](https://github.com/chokcoco/iCSS/issues/179)

#### 141、[Amazing!巧用 CSS 视差实现酷炫交互动效](https://github.com/chokcoco/iCSS/issues/178)

#### 140、[现代 CSS 解决方案:Modern CSS Reset](https://github.com/chokcoco/iCSS/issues/176)
#### 139、[巧用 background-clip 实现超强的文字动效 ](https://github.com/chokcoco/iCSS/issues/175)

#### 138、[一道有意思的 CSS 面试题,FizzBuzz ~](https://github.com/chokcoco/iCSS/issues/174)
#### 137、[2022 年最受瞩目的新特性 CSS @layer 到底是个啥?](https://github.com/chokcoco/iCSS/issues/171)
#### 136、[CSS 阴影进阶,实现更加的立体的阴影效果!](https://github.com/chokcoco/iCSS/issues/170)

#### 135、[利用混合模式,让文字智能适配背景颜色](https://github.com/chokcoco/iCSS/issues/169)

#### 134、[系统性学习 CSS 指南及全 DEMO 练习](https://github.com/chokcoco/iCSS/issues/168)
#### 133、[巧用 CSS 构建渐变彩色二维码](https://github.com/chokcoco/iCSS/issues/167)

#### 132、[来了来了,它终于来了,动画杀手锏 @scroll-timeline](https://github.com/chokcoco/iCSS/issues/166)

#### 131、[突破限制,CSS font-variation 可变字体的魅力](https://github.com/chokcoco/iCSS/issues/164)

#### 130、[小技巧 | 渐变消失遮罩的多种实现方式](https://github.com/chokcoco/iCSS/issues/163)

#### 129、[巧用 CSS 实现炫彩三角边框动画](https://github.com/chokcoco/iCSS/issues/162)

#### 128、[扫盲贴:2021 CSS 最冷门特性都是些啥?](https://github.com/chokcoco/iCSS/issues/161)

#### 127、[疑难杂症:运用 transform 导致文本模糊的现象探究](https://github.com/chokcoco/iCSS/issues/160)
#### 126、[LPL Ban/Pick 选人阶段的遮罩效果是如何实现的?](https://github.com/chokcoco/iCSS/issues/159)

#### 125、[巧用 CSS 实现动态线条 Loading 动画](https://github.com/chokcoco/iCSS/issues/158)

#### 124、[深入浅出 CSS 动画](https://github.com/chokcoco/iCSS/issues/141)

#### 123、[妙用滤镜构建高级感拉满的磨砂玻璃渐变背景](https://github.com/chokcoco/iCSS/issues/157)

#### 122、[深入探讨 filter 与 backdrop-filter 的异同](https://github.com/chokcoco/iCSS/issues/147)
#### 121、[Amazing!!CSS 也能实现烟雾效果?](https://github.com/chokcoco/iCSS/issues/156)

#### 120、[Amazing!!CSS 也能实现极光?](https://github.com/chokcoco/iCSS/issues/155)

#### 119、[神奇的滤镜!巧妙实现内凹的平滑圆角](https://github.com/chokcoco/iCSS/issues/154)

#### 118、[利用 clip-path 实现动态区域裁剪](https://github.com/chokcoco/iCSS/issues/153)
#### 117、[使用 CSS 轻松实现一些高频出现的奇形怪状按钮](https://github.com/chokcoco/iCSS/issues/152)

#### 116、[巧用渐变实现高级感拉满的背景光动画](https://github.com/chokcoco/iCSS/issues/150)

#### 115、[巧用滤镜实现高级感拉满的文字快闪切换效果](https://github.com/chokcoco/iCSS/issues/149)
<img width=400 src="https://user-images.githubusercontent.com/8554143/140746534-93b02f03-7624-4d1a-b832-9269f7c4f848.gif" />
#### 114、[3D 穿梭效果?使用 CSS 轻松搞定](https://github.com/chokcoco/iCSS/issues/148)

#### 113、[仅仅使用 HTML/CSS 实现进度条的 N 种方式](https://github.com/chokcoco/iCSS/issues/146)

#### 112、[CSS 奇技淫巧 | 巧妙实现文字二次加粗再加边框](https://github.com/chokcoco/iCSS/issues/145)
#### 111、[利用 CSS Overview 面板重构优化你的网站](https://github.com/chokcoco/iCSS/issues/144)
#### 110、[小技巧 | 一行代码实现头像与国旗的融合](https://github.com/chokcoco/iCSS/issues/143)

#### 109、[CSS 奇技淫巧 | 妙用 drop-shadow 实现线条光影效果](https://github.com/chokcoco/iCSS/issues/142)

#### 108、[CSS 奇技淫巧 | 妙用混合模式实现文字镂空波浪效果](https://github.com/chokcoco/iCSS/issues/140)

#### 107、[妙用 background 实现花式文字效果](https://github.com/chokcoco/iCSS/issues/138)

#### 106、[实现一个会动的鸿蒙 LOGO](https://github.com/chokcoco/iCSS/issues/137)

#### 105、[巧用模糊实现文字的 3D 效果](https://github.com/chokcoco/iCSS/issues/135)

#### 104、[奇思妙想 CSS 3D 动画 | 仅使用 CSS 能制作出多惊艳的动画?](https://github.com/chokcoco/iCSS/issues/132)

#### 103、[CSS 奇思妙想 | 使用 resize 实现强大的图片拖拽切换预览功能](https://github.com/chokcoco/iCSS/issues/133)

#### 102、[CSS 即将支持嵌套,SASS/LESS 等预处理器已无用武之地?](https://github.com/chokcoco/iCSS/issues/130)
#### 101、[【Web动画】科技感十足的暗黑字符雨动画](https://github.com/chokcoco/iCSS/issues/129)

#### 100、[CSS 世界中的方位与顺序](https://github.com/chokcoco/iCSS/issues/127)

#### 99、[巧妙的实现带圆角的三角形](https://github.com/chokcoco/iCSS/issues/126)

#### 98、[CSS 奇思妙想 | 全兼容的毛玻璃效果](https://github.com/chokcoco/iCSS/issues/124)

#### 97、[试试酷炫的 3D 视角](https://github.com/chokcoco/iCSS/issues/122)

#### 96、[Web 动画原则及技巧浅析](https://github.com/chokcoco/iCSS/issues/121)

#### 95、[CSS ::marker 让文字序号更有意思](https://github.com/chokcoco/iCSS/issues/119)

#### 94、[Single Div 绘图技巧](https://github.com/chokcoco/iCSS/issues/120)

#### 93、[新时代创意布局不完全指南](https://github.com/chokcoco/iCSS/issues/70)

#### 92、[有意思的 ::maker 伪元素](https://github.com/chokcoco/iCSS/issues/119)
#### 91、[使用 CSS prefers-* 规范,提升网站的可访问性与健壮性](https://github.com/chokcoco/iCSS/issues/118)
#### 90、[小技巧!CSS 提取图片主题色功能探索](https://github.com/chokcoco/iCSS/issues/114)

#### 89、[一种巧妙的使用 CSS 制作波浪效果的思路](https://github.com/chokcoco/iCSS/issues/112)

#### 88、[探秘神奇的曲线动画 `motion-path`](https://github.com/chokcoco/iCSS/issues/113)

#### 87、[新时代布局中一些有意思的特性](https://github.com/chokcoco/iCSS/issues/111)

#### 86、[CSS 还能这样玩?奇思妙想渐变的艺术](https://github.com/chokcoco/iCSS/issues/110)

#### 85、[CSS @property,让不可能变可能](https://github.com/chokcoco/iCSS/issues/109)

#### 84、[CSS 文字装饰 text-decoration & text-emphasis](https://github.com/chokcoco/iCSS/issues/103)

#### 83、[老生常谈之 CSS 实现三角形](https://github.com/chokcoco/iCSS/issues/108)

#### 82、[巧用 SVG 滤镜制作有意思动效](https://github.com/chokcoco/iCSS/issues/107)

#### 81、[有意思!不规则边框的生成方案](https://github.com/chokcoco/iCSS/issues/106)

#### 80、[小技巧!CSS 整块文本溢出省略特性探究](https://github.com/chokcoco/iCSS/issues/102)

#### 79、[奇思妙想 CSS 文字动画](https://github.com/chokcoco/iCSS/issues/101)

#### 78、[巧用 `-webkit-box-reflect` 倒影实现各类动效](https://github.com/chokcoco/iCSS/issues/100)

#### 77、[使用 mask 实现视频弹幕人物遮罩过滤](https://github.com/chokcoco/iCSS/issues/98)

#### 76、[你可能不知道的 transition 技巧与细节](https://github.com/chokcoco/iCSS/issues/96)

#### 75、[CSS奇思妙想 -- 使用 CSS 创造艺术图案](https://github.com/chokcoco/iCSS/issues/94)

#### 74、[生僻标签 fieldset 与 legend 的妙用](https://github.com/chokcoco/iCSS/issues/93)
<img width="200" src="https://user-images.githubusercontent.com/8554143/105197984-2c28b300-5b78-11eb-96e2-26213af4cd90.png">
#### 73、[CSS 奇思妙想边框动画](https://github.com/chokcoco/iCSS/issues/92)
<img width="600" src="https://user-images.githubusercontent.com/8554143/104848230-f9d04900-591e-11eb-8ecf-7915010f7bcd.gif">
#### 72、[CSS 技巧一则:动态高度过渡动画](https://github.com/chokcoco/iCSS/issues/91)
#### 71、[如何不使用 `overflow: hidden` 实现 `overflow: hidden`?](https://github.com/chokcoco/iCSS/issues/90)
#### 70、[水平垂直居中深入挖掘](https://github.com/chokcoco/iCSS/issues/89)
#### 69、[一行 CSS 代码的魅力](https://github.com/chokcoco/iCSS/issues/87)

#### 68、[使用纯 CSS 实现滚动阴影效果](https://github.com/chokcoco/iCSS/issues/86)

#### 67、[探究 position-sticky 失效问题](https://github.com/chokcoco/iCSS/issues/85)
#### 66、[CSS 艺术 -- 使用 background 创造各种美妙的背景](https://github.com/chokcoco/iCSS/issues/84)

#### 65、[使用 tabindex 配合 focus-within 巧妙实现父选择器](https://github.com/chokcoco/iCSS/issues/83)
#### 64、[CSS 技巧一则 -- 不定宽溢出文本适配滚动](https://github.com/chokcoco/iCSS/issues/81)

#### 63、[奇妙的 CSS MASK](https://github.com/chokcoco/iCSS/issues/80)

#### 62、[使用 display: contents 增强页面语义](https://github.com/chokcoco/iCSS/issues/79)
#### 61、[CSS 故障艺术](https://github.com/chokcoco/iCSS/issues/78)

#### 60、[巧妙实现带圆角的渐变边框](https://github.com/chokcoco/iCSS/issues/77)

#### 59、[深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)](https://github.com/chokcoco/iCSS/issues/76)
#### 58、[巧用 CSS 实现酷炫的充电动画](https://github.com/chokcoco/iCSS/issues/75)

#### 57、[使用 sroll-snap-type 优化滚动](https://github.com/chokcoco/iCSS/issues/74)

#### 56、[在 CSS 中使用三角函数绘制曲线图形及展示动画](https://github.com/chokcoco/iCSS/issues/72)

#### 55、[CSS 阴影动画优化技巧一则](https://github.com/chokcoco/iCSS/issues/71)
#### 54、[Web 字体 font-family 再探秘](https://github.com/chokcoco/iCSS/issues/69)
#### 53、[你所不知道的 CSS 负值技巧与细节](https://github.com/chokcoco/iCSS/issues/68)

#### 52、[A Guide to CSS Rules](https://github.com/chokcoco/iCSS/issues/67)
#### 51、[CSS 属性选择器的深入挖掘](https://github.com/chokcoco/iCSS/issues/65)
#### 50、[探秘 flex 上下文中神奇的自动 margin](https://github.com/chokcoco/iCSS/issues/64)
#### 49、[巧妙使用 CSS 控制动画行进](https://github.com/chokcoco/iCSS/issues/63)

#### 48、[CSS 火焰,不在话下](https://github.com/chokcoco/iCSS/issues/62)

#### 47、[不可思议的纯 CSS 实现鼠标跟随](https://github.com/chokcoco/iCSS/issues/46)

#### 46、[有趣的 `box-decoration-break`](https://github.com/chokcoco/iCSS/issues/45)
#### 45、[不可思议的纯 CSS 进度条效果](https://github.com/chokcoco/iCSS/issues/43)
#### 44、[探究 CSS 混合模式\滤镜导致 CSS 3D 失效问题](https://github.com/chokcoco/iCSS/issues/41)
#### 43、[你所不知道的 CSS 阴影技巧与细节](https://github.com/chokcoco/iCSS/issues/39)

#### 42、[滚动视差? CSS不在话下](https://github.com/chokcoco/iCSS/issues/37)

#### 41、[神奇的选择器 `:focus-within`](https://github.com/chokcoco/iCSS/issues/36)

#### 40、[Pure CSS Button Effect](//codepen.io/Chokcoco/pen/MGPwLg)
#### 39、[妙用 scale 与 transfrom-origin,精准控制动画方向](https://github.com/chokcoco/iCSS/issues/34)
#### 38、[不可思议的纯 CSS 导航栏下划线跟随效果](https://github.com/chokcoco/iCSS/issues/33)
如何使用纯 CSS 制作下述下划线跟随效果?

#### 37、[两行 CSS 代码实现图片任意颜色赋色技术](https://github.com/chokcoco/iCSS/issues/32)
#### 36、[`text-fill-color` 与 `color` 的异同](https://github.com/chokcoco/iCSS/issues/17)
#### 35、[你所不知道的 CSS 滤镜技巧与细节](https://github.com/chokcoco/iCSS/issues/30)

#### 34、[你所不知道的 CSS 动画技巧与细节](https://github.com/chokcoco/iCSS/issues/27)

#### 33、[fixed 定位失效 || 不受控制的 `position:fixed`](https://github.com/chokcoco/iCSS/issues/24)
#### 32、[CSS 新特性`contain`,控制页面的重绘与重排](https://github.com/chokcoco/iCSS/issues/23)
#### 31、[纯 CSS 实现波浪效果!](https://github.com/chokcoco/iCSS/issues/22)

#### 30、[奇妙的 CSS shapes(CSS图形)](https://github.com/chokcoco/iCSS/issues/18)

#### 29、[不可思议的混合模式 `background-blend-mode`](https://github.com/chokcoco/iCSS/issues/31)

#### 28、[不可思议的混合模式 `mix-blend-mode` ](https://github.com/chokcoco/iCSS/issues/16)

#### 27、[神奇的 `conic-gradient` 角向渐变](https://github.com/chokcoco/iCSS/issues/19)

#### 26、[奇妙的`-webkit-background-clip: text`](https://github.com/chokcoco/iCSS/issues/14)
#### 25、[vh、vw、vmin、vmax 知多少](https://github.com/chokcoco/iCSS/issues/15)
#### 24、[纯 CSS 实现瀑布流布局](https://github.com/chokcoco/iCSS/issues/40)
#### 23、[谈谈 CSS 关键字 initial、inherit 和 unset](https://github.com/chokcoco/iCSS/issues/13)
#### 22、[纯 CSS 方式实现 CSS 动画的暂停与播放](https://github.com/chokcoco/iCSS/issues/12)
#### 21、[提高 CSS 动画性能的正确姿势 | 盒子端 CSS 动画性能提升研究](https://github.com/chokcoco/iCSS/issues/11)
#### 20、[巧妙地制作背景色渐变动画!](https://github.com/chokcoco/iCSS/issues/10)
如何实现下述的背景色渐变动画?

#### 19、[深入探讨 CSS 特性检测 @supports 与 Modernizr](https://github.com/chokcoco/iCSS/issues/9)
#### 18、[使用 `position:sticky` 实现粘性布局](https://github.com/chokcoco/iCSS/issues/8)

#### 17、[再探究字体的渲染规则及 fallback 机制](https://github.com/chokcoco/iCSS/issues/7)
#### 16、[你该知道的字体 `font-family`](https://github.com/chokcoco/iCSS/issues/6)
#### 15、[`reset.css` 知多少 ](https://github.com/chokcoco/iCSS/issues/5)
#### 14、[CSS命名方式是否有必要规范](https://github.com/chokcoco/iCSS/issues/59)
#### 13、[引人瞩目的 CSS 自定义属性(CSS Variable)](https://github.com/chokcoco/iCSS/issues/58)
#### 12、[结构性伪类选择器](https://github.com/chokcoco/iCSS/issues/57)
#### 11、[IFC、BFC、GFC 与 FFC 知多少](https://github.com/chokcoco/iCSS/issues/56)
#### 10、[巧妙的实现 CSS 斜线](https://github.com/chokcoco/iCSS/issues/2)
使用单个标签,如何实现下图所示的斜线效果:

#### 9、[巧妙的多列等高布局](https://github.com/chokcoco/iCSS/issues/55)
规定下面的布局,实现多列等高布局,要求两列背景色等高。
``` HTML
<div class="container">
<div class="left">多列等高布局左</div>
<div class="right">多列等高布局右</div>
</div>
```
#### 8、[纯CSS的导航栏Tab切换方案](https://github.com/chokcoco/iCSS/issues/54)
不用 `Javascript`,使用纯 `CSS` 方案,实现类似下图的导航栏 Tab 切换:

#### 7、[全兼容的最后一条边界线问题](https://github.com/chokcoco/iCSS/issues/53)
看看下图,常见于一些导航栏中,要求每行中最后一列的右边框消失,如何在所有浏览器中最便捷最优雅的实现?
#### 6、[全兼容的多列均匀布局问题](https://github.com/chokcoco/iCSS/issues/52)
如何实现下列这种多列均匀布局:

#### 5、[纯 CSS 实现单行居中显示文字,多行居左显示,最多两行超过用省略号结尾](https://github.com/chokcoco/iCSS/issues/50)

#### 4、[从倒影说起,谈谈 CSS 继承 inherit](https://github.com/chokcoco/iCSS/issues/49)
#### 3、[层叠顺序(stacking level)与堆栈上下文(stacking context)知多少?](https://github.com/chokcoco/iCSS/issues/48)
#### 2、[类似下面这样的条纹边框,只使用一个标签,可以有多少种实现方式 -- 从条纹边框的实现谈盒子模型:](https://github.com/chokcoco/iCSS/issues/1)

#### 1、[下面这个左边竖条图形,只使用一个标签,可以有多少种实现方式:](https://github.com/chokcoco/iCSS/issues/51)

## Stargazers over time
[](https://starchart.cc/chokcoco/iCSS)
================================================
FILE: website/README.md
================================================
# iCSS 网站
基于 GitHub 上的 iCSS 仓库构建的现代化网站,展示 CSS 奇技淫巧。
## 功能特性
### 🎨 主题切换
- **亮色主题**: 适合日间使用
- **暗色主题**: 适合夜间使用,护眼
- **跟随系统**: 自动跟随系统主题设置
- **持久化**: 主题选择会保存到本地存储
### 🌍 多语言支持
- **中文**: 简体中文界面
- **English**: 英文界面
- **持久化**: 语言选择会保存到本地存储
### 📱 响应式设计
- 支持桌面端、平板和移动端
- 自适应布局,提供最佳用户体验
### 🎯 核心功能
- **文章列表**: 展示所有 CSS 技巧文章
- **分类筛选**: 按分类筛选文章
- **搜索功能**: 支持文章标题搜索
- **文章详情**: 完整的文章内容展示
- **代码高亮**: 支持语法高亮的代码块
- **CodePen 集成**: 直接嵌入 CodePen 演示
- **上一篇/下一篇**: 文章导航功能
## 技术栈
- **框架**: Next.js 14 (App Router)
- **语言**: TypeScript
- **样式**: Tailwind CSS
- **状态管理**: React Context
- **动画**: Framer Motion
- **图标**: Lucide React
- **代码高亮**: react-syntax-highlighter
## 快速开始
### 安装依赖
```bash
pnpm install
```
### 启动开发服务器
```bash
pnpm dev
```
### 构建生产版本
```bash
pnpm build
```
### 启动生产服务器
```bash
pnpm start
```
## 项目结构
```
icss-website/
├── app/
│ ├── api/ # API 路由
│ ├── article/ # 文章详情页
│ ├── components/ # 可复用组件
│ ├── contexts/ # React Context
│ ├── lib/ # 工具函数
│ ├── globals.css # 全局样式
│ ├── layout.tsx # 根布局
│ └── page.tsx # 首页
├── public/ # 静态资源
└── package.json
```
## 主题系统
### 主题配置
主题系统基于 CSS 变量和 Tailwind CSS 的暗色模式实现:
- **CSS 变量**: 定义主题色彩
- **Tailwind 配置**: 支持 `dark:` 前缀的类名
- **Context API**: 管理主题状态
- **localStorage**: 持久化主题选择
### 自定义主题
可以通过修改 `app/globals.css` 中的 CSS 变量来自定义主题色彩:
```css
:root {
--primary: 221.2 83.2% 53.3%;
--background: 0 0% 100%;
/* 更多变量... */
}
.dark {
--primary: 217.2 91.2% 59.8%;
--background: 222.2 84% 4.9%;
/* 更多变量... */
}
```
## 多语言系统
### 翻译文件
翻译内容定义在 `app/lib/translations.ts` 中:
```typescript
export const translations: Record<Language, Translations> = {
zh: {
loading: '加载中...',
error: '错误',
// 更多翻译...
},
en: {
loading: 'Loading...',
error: 'Error',
// 更多翻译...
}
};
```
### 使用翻译
在组件中使用 `useApp` hook 获取翻译函数:
```typescript
import { useApp } from '../contexts/AppContext';
function MyComponent() {
const { t } = useApp();
return <div>{t('loading')}</div>;
}
```
## API 接口
### 文章列表
```
GET /api/articles?page=1&per_page=12&category=CSS&search=关键词
```
### 文章详情
```
GET /api/articles/[id]
```
### 分类列表
```
GET /api/categories
```
## 测试页面
访问以下页面测试功能:
- **首页**: `http://localhost:3000`
- **主题语言测试**: `http://localhost:3000/test-theme-lang`
- **API 测试**: `http://localhost:3000/test-api`
- **Demo 测试**: `http://localhost:3000/test-demo`
## 部署
### Vercel 部署
1. 将代码推送到 GitHub
2. 在 Vercel 中导入项目
3. 配置环境变量(如需要)
4. 自动部署
### 其他平台
项目支持部署到任何支持 Next.js 的平台:
- Netlify
- Railway
- DigitalOcean App Platform
- 自托管服务器
## 贡献
欢迎提交 Issue 和 Pull Request!
## 许可证
MIT License
================================================
FILE: website/THEME_LANG_FEATURES.md
================================================
# 主题和语言切换功能说明
## 🎨 主题切换功能
### 功能特性
- **亮色主题**: 适合日间使用,白色背景
- **暗色主题**: 适合夜间使用,深色背景,护眼
- **跟随系统**: 自动跟随系统主题设置
- **持久化**: 主题选择会保存到 localStorage
### 实现方式
1. **CSS 变量系统**: 使用 CSS 自定义属性定义主题色彩
2. **Tailwind 暗色模式**: 支持 `dark:` 前缀的类名
3. **Context API**: React Context 管理主题状态
4. **localStorage**: 持久化用户选择
### 文件结构
```
app/
├── lib/
│ └── theme.ts # 主题管理工具
├── contexts/
│ └── AppContext.tsx # 应用上下文
├── components/
│ └── ThemeToggle.tsx # 主题切换组件
└── globals.css # 全局样式和主题变量
```
### 使用方法
```typescript
import { useApp } from '../contexts/AppContext';
function MyComponent() {
const { theme, setTheme } = useApp();
return (
<div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
<button onClick={() => setTheme('dark')}>
切换到暗色主题
</button>
</div>
);
}
```
## 🌍 多语言支持
### 功能特性
- **中文**: 简体中文界面
- **English**: 英文界面
- **持久化**: 语言选择会保存到 localStorage
- **实时切换**: 无需刷新页面即可切换语言
### 实现方式
1. **翻译文件**: 集中管理所有翻译内容
2. **Context API**: React Context 管理语言状态
3. **翻译函数**: 提供 `t()` 函数获取翻译
4. **localStorage**: 持久化用户选择
### 文件结构
```
app/
├── lib/
│ ├── language.ts # 语言管理工具
│ └── translations.ts # 翻译文件
├── contexts/
│ └── AppContext.tsx # 应用上下文
└── components/
└── LanguageToggle.tsx # 语言切换组件
```
### 使用方法
```typescript
import { useApp } from '../contexts/AppContext';
function MyComponent() {
const { t, language, setLanguage } = useApp();
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
<button onClick={() => setLanguage('en')}>
切换到英文
</button>
</div>
);
}
```
## 🎯 核心组件
### ThemeToggle 组件
- 下拉菜单式主题选择
- 图标和文字显示
- 点击外部自动关闭
- 支持键盘导航
### LanguageToggle 组件
- 下拉菜单式语言选择
- 国旗图标显示
- 点击外部自动关闭
- 支持键盘导航
### AppContext 上下文
- 统一管理主题和语言状态
- 提供翻译函数
- 处理服务端渲染兼容性
- 防止闪烁问题
## 🎨 样式系统
### CSS 变量
```css
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
/* 更多变量... */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
/* 更多变量... */
}
```
### Tailwind 配置
```javascript
module.exports = {
darkMode: 'class',
theme: {
extend: {
colors: {
back
gitextract_o4i__mil/
├── .gitattributes
├── MCP/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.en.md
│ ├── README.md
│ ├── bin/
│ │ ├── icss-mcp.js
│ │ └── install.js
│ ├── debug-interactive.js
│ ├── debug-local.js
│ ├── debug-query.js
│ ├── debug.js
│ ├── diagnose-mcp.js
│ ├── package.json
│ ├── scripts/
│ │ ├── cursor-config.json
│ │ ├── fetch-inspiration.js
│ │ ├── fetch-issues.js
│ │ └── publish-check.js
│ ├── server.js
│ ├── setup.js
│ ├── test-inspiration.js
│ └── test-server.js
├── readme.md
└── website/
├── README.md
├── THEME_LANG_FEATURES.md
├── app/
│ ├── api/
│ │ ├── articles/
│ │ │ ├── [id]/
│ │ │ │ └── route.ts
│ │ │ └── route.ts
│ │ └── categories/
│ │ └── route.ts
│ ├── article/
│ │ └── [id]/
│ │ └── page.tsx
│ ├── components/
│ │ ├── CodeBlock.tsx
│ │ ├── LanguageToggle.tsx
│ │ └── ThemeToggle.tsx
│ ├── contexts/
│ │ └── AppContext.tsx
│ ├── globals.css
│ ├── layout.tsx
│ ├── lib/
│ │ ├── cache.ts
│ │ ├── github.ts
│ │ ├── language.ts
│ │ ├── theme.ts
│ │ └── translations.ts
│ ├── page.tsx
│ ├── test-api/
│ │ └── page.tsx
│ ├── test-demo/
│ │ └── page.tsx
│ ├── test-fixes/
│ │ └── page.tsx
│ └── test-theme-lang/
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── public/
│ └── index.md
├── tailwind.config.js
├── test-features.md
├── tsconfig.json
└── vercel.json
SYMBOL INDEX (186 symbols across 32 files)
FILE: MCP/bin/install.js
function getCursorConfigPath (line 14) | function getCursorConfigPath() {
function getPackagePath (line 31) | function getPackagePath() {
function updateMcpConfig (line 37) | function updateMcpConfig() {
function verifyInstallation (line 88) | function verifyInstallation() {
function showUsageInstructions (line 127) | function showUsageInstructions(configFile) {
function main (line 161) | async function main() {
FILE: MCP/debug-interactive.js
function showPrompt (line 40) | function showPrompt() {
function sendCommand (line 110) | function sendCommand(command) {
FILE: MCP/debug-local.js
constant DEBUG (line 20) | const DEBUG = true;
class IcssDebugServer (line 27) | class IcssDebugServer {
method constructor (line 28) | constructor() {
method setupDatabase (line 53) | setupDatabase() {
method loadSearchIndex (line 69) | loadSearchIndex() {
method waitForReady (line 146) | async waitForReady(timeout = 10000) {
method setupHandlers (line 168) | setupHandlers() {
method searchCssTechniques (line 241) | async searchCssTechniques({ query, categories = [], tags = [], min_wei...
method extractPreview (line 322) | extractPreview(body, maxLength = 200) {
method run (line 338) | async run() {
method cleanup (line 359) | cleanup() {
FILE: MCP/debug-query.js
function queryServer (line 72) | function queryServer(command) {
function runTests (line 144) | async function runTests() {
FILE: MCP/debug.js
class DebugTester (line 8) | class DebugTester {
method constructor (line 9) | constructor() {
method init (line 15) | async init() {
method loadSearchIndex (line 32) | async loadSearchIndex() {
method testSearchFunction (line 64) | async testSearchFunction(query = "透明 边框") {
method testSpecificArticle (line 104) | async testSpecificArticle(issueNumber = 1) {
method testCategories (line 136) | async testCategories() {
method close (line 181) | close() {
function runDebugTests (line 190) | async function runDebugTests() {
FILE: MCP/diagnose-mcp.js
function checkCursorConfigs (line 10) | function checkCursorConfigs() {
function checkServerExecutability (line 50) | function checkServerExecutability() {
function testMCPProtocol (line 76) | function testMCPProtocol() {
function generateCorrectConfig (line 136) | function generateCorrectConfig() {
function provideTroubleshootingTips (line 190) | function provideTroubleshootingTips() {
function runDiagnosis (line 210) | async function runDiagnosis() {
FILE: MCP/scripts/fetch-inspiration.js
class InspirationFetcher (line 13) | class InspirationFetcher {
method constructor (line 14) | constructor() {
method initializeDatabase (line 60) | initializeDatabase() {
method fetchDirectoryContents (line 122) | async fetchDirectoryContents(category) {
method fetchFileContent (line 146) | async fetchFileContent(filePath) {
method parseMarkdownContent (line 162) | parseMarkdownContent(content, category, filename) {
method generateTags (line 245) | generateTags(title, description, cssContent, category) {
method assessDifficulty (line 277) | assessDifficulty(cssContent, htmlContent) {
method assessBrowserSupport (line 306) | assessBrowserSupport(cssContent) {
method saveToDatabase (line 334) | async saveToDatabase(category, filename, parsedContent) {
method extractAndSaveCodeSnippets (line 382) | async extractAndSaveCodeSnippets(inspirationId, htmlContent, cssConten...
method generateCompleteDemo (line 433) | async generateCompleteDemo(inspirationId, title, htmlContent, cssConte...
method fetchAllInspirations (line 488) | async fetchAllInspirations() {
method generateStats (line 552) | generateStats() {
method close (line 597) | close() {
FILE: MCP/scripts/fetch-issues.js
class IssuesFetcher (line 13) | class IssuesFetcher {
method constructor (line 14) | constructor() {
method initializeDatabase (line 156) | initializeDatabase() {
method initializeLabelCategories (line 232) | async initializeLabelCategories() {
method analyzeLabelRelations (line 299) | async analyzeLabelRelations(issues) {
method analyzeArticleLabels (line 361) | async analyzeArticleLabels(issue) {
method calculateLabelWeights (line 417) | calculateLabelWeights(labels, content) {
method buildLabelHierarchy (line 460) | async buildLabelHierarchy() {
method saveAnalysisToDatabase (line 511) | async saveAnalysisToDatabase(issueNumber, analysis) {
method saveIssuesToDatabase (line 541) | async saveIssuesToDatabase(issues) {
method updateRelatedArticles (line 614) | async updateRelatedArticles() {
method calculateRelationScore (line 654) | calculateRelationScore(article1, article2) {
method generateEnhancedStats (line 677) | generateEnhancedStats() {
method fetchAllIssues (line 726) | async fetchAllIssues() {
method createSearchContent (line 790) | createSearchContent(issue) {
method generateStats (line 825) | generateStats() {
method close (line 861) | close() {
method analyzeCodePatterns (line 865) | analyzeCodePatterns(content) {
method analyzeAnimationPattern (line 902) | analyzeAnimationPattern(code) {
method analyzeAnimationPerformance (line 918) | analyzeAnimationPerformance(code) {
method getAnimationBrowserSupport (line 939) | getAnimationBrowserSupport(code) {
method analyzeLayoutPattern (line 962) | analyzeLayoutPattern(code) {
method analyzeLayoutPerformance (line 978) | analyzeLayoutPerformance(code) {
method getLayoutBrowserSupport (line 999) | getLayoutBrowserSupport(code) {
method analyzePerformance (line 1021) | analyzePerformance(content, cssProperties) {
method checkGPUAcceleration (line 1033) | checkGPUAcceleration(properties) {
method analyzePaintComplexity (line 1041) | analyzePaintComplexity(properties) {
method checkLayoutTriggers (line 1054) | checkLayoutTriggers(properties) {
method analyzeMemoryImpact (line 1059) | analyzeMemoryImpact(properties) {
method generateOptimizationTips (line 1072) | generateOptimizationTips(properties) {
method analyzeCSSPropertyCategories (line 1088) | analyzeCSSPropertyCategories(properties) {
method getCSSPropertyCategory (line 1101) | getCSSPropertyCategory(prop) {
method getCSSPropertySubCategory (line 1117) | getCSSPropertySubCategory(prop) {
method getPropertyDescription (line 1126) | getPropertyDescription(prop) {
method getPropertyPerformanceImpact (line 1138) | getPropertyPerformanceImpact(prop) {
method getPropertyBestPractices (line 1147) | getPropertyBestPractices(prop) {
method getPropertyCommonPitfalls (line 1162) | getPropertyCommonPitfalls(prop) {
method getPropertyBrowserNotes (line 1177) | getPropertyBrowserNotes(prop) {
method saveCodePatterns (line 1190) | async saveCodePatterns(issueNumber, patterns) {
method savePropertyCategories (line 1220) | async savePropertyCategories(categories) {
method savePerformanceAnalysis (line 1250) | async savePerformanceAnalysis(issueNumber, analysis) {
method generateLabelStatistics (line 1276) | async generateLabelStatistics() {
FILE: MCP/scripts/publish-check.js
function checkFailed (line 15) | function checkFailed(message) {
function checkPassed (line 20) | function checkPassed(message) {
FILE: MCP/server.js
class IcssServer (line 28) | class IcssServer {
method constructor (line 29) | constructor() {
method setupDatabase (line 52) | setupDatabase() {
method initializeDatabase (line 70) | initializeDatabase() {
method loadSearchIndex (line 98) | loadSearchIndex() {
method waitForReady (line 132) | async waitForReady(timeout = 10000) {
method setupHandlers (line 158) | setupHandlers() {
method searchCssTechniques (line 329) | async searchCssTechniques(query, limit = 5) {
method getCssArticle (line 399) | async getCssArticle(issueNumber) {
method searchCssDemos (line 441) | async searchCssDemos(query, category, difficulty, limit = 5) {
method getCssDemo (line 510) | async getCssDemo(demoId) {
method listCssCategories (line 574) | async listCssCategories(source = 'all') {
method getRandomCssTip (line 688) | async getRandomCssTip(source = 'both') {
method extractPreview (line 764) | extractPreview(body, maxLength = 200) {
method run (line 780) | async run() {
FILE: MCP/setup.js
class ProjectSetup (line 10) | class ProjectSetup {
method constructor (line 11) | constructor() {
method setup (line 16) | async setup() {
method createDirectories (line 29) | createDirectories() {
method createEnvFile (line 46) | createEnvFile() {
method showNextSteps (line 71) | showNextSteps() {
FILE: MCP/test-inspiration.js
class InspirationTester (line 10) | class InspirationTester {
method constructor (line 11) | constructor() {
method testDatabaseIntegrity (line 21) | async testDatabaseIntegrity() {
method checkTable (line 37) | checkTable(tableName) {
method testSearchFunctionality (line 54) | async testSearchFunctionality() {
method testQuery (line 76) | testQuery(testName, sql) {
method testCodeSnippets (line 99) | async testCodeSnippets() {
method testDemoStyles (line 113) | async testDemoStyles() {
method generateReport (line 133) | async generateReport() {
method runAllTests (line 174) | async runAllTests() {
method close (line 192) | close() {
FILE: MCP/test-server.js
function testDatabase (line 9) | function testDatabase() {
function testSearch (line 40) | function testSearch(db, resolve, reject) {
function testMCPSDK (line 81) | function testMCPSDK() {
FILE: website/app/api/articles/[id]/route.ts
function GET (line 4) | async function GET(
FILE: website/app/api/articles/route.ts
function GET (line 4) | async function GET(request: NextRequest) {
FILE: website/app/api/categories/route.ts
function GET (line 4) | async function GET() {
FILE: website/app/article/[id]/page.tsx
type Article (line 11) | interface Article {
type IssueData (line 19) | interface IssueData {
function ArticleDetailPage (line 608) | function ArticleDetailPage() {
FILE: website/app/components/CodeBlock.tsx
type CodeBlockProps (line 7) | interface CodeBlockProps {
function CodePenDemo (line 13) | function CodePenDemo({ html, css, js }: { html: string; css: string; js:...
function CodeBlock (line 54) | function CodeBlock({ children, language = 'text' }: CodeBlockProps) {
FILE: website/app/components/LanguageToggle.tsx
function LanguageToggle (line 8) | function LanguageToggle() {
FILE: website/app/components/ThemeToggle.tsx
function ThemeToggle (line 9) | function ThemeToggle() {
FILE: website/app/contexts/AppContext.tsx
type AppContextType (line 8) | interface AppContextType {
function AppProvider (line 18) | function AppProvider({ children }: { children: React.ReactNode }) {
function useApp (line 70) | function useApp() {
FILE: website/app/layout.tsx
function RootLayout (line 14) | function RootLayout({
FILE: website/app/lib/cache.ts
type CacheItem (line 1) | interface CacheItem<T> {
class Cache (line 7) | class Cache {
method constructor (line 11) | private constructor() {}
method getInstance (line 13) | static getInstance(): Cache {
method set (line 20) | set<T>(key: string, data: T, ttl: number = 5 * 60 * 1000): void {
method get (line 28) | get<T>(key: string): T | null {
method delete (line 43) | delete(key: string): void {
method clear (line 47) | clear(): void {
method cleanup (line 52) | cleanup(): void {
FILE: website/app/lib/github.ts
type GitHubIssue (line 3) | interface GitHubIssue {
type Article (line 24) | interface Article {
class GitHubAPI (line 36) | class GitHubAPI {
method getGitHubToken (line 42) | private static getGitHubToken(): string | undefined {
method getHeaders (line 47) | private static getHeaders(): HeadersInit {
method extractImageFromBody (line 62) | private static extractImageFromBody(body: string): string | undefined {
method extractCategoryFromBody (line 81) | private static extractCategoryFromBody(body: string): string | undefin...
method transformIssueToArticle (line 100) | private static transformIssueToArticle(issue: GitHubIssue): Article {
method getIssues (line 118) | static async getIssues(page: number = 1, perPage: number = 30): Promis...
method getIssue (line 187) | static async getIssue(issueNumber: number): Promise<{
method getAllArticles (line 263) | static async getAllArticles(): Promise<Article[]> {
method fetchWithRetry (line 308) | private static async fetchWithRetry(url: string, options: RequestInit,...
FILE: website/app/lib/language.ts
type Language (line 1) | type Language = 'zh' | 'en';
type LanguageConfig (line 3) | interface LanguageConfig {
function getStoredLanguage (line 22) | function getStoredLanguage(): Language {
function setStoredLanguage (line 27) | function setStoredLanguage(language: Language) {
FILE: website/app/lib/theme.ts
type Theme (line 1) | type Theme = 'light' | 'dark' | 'system';
type ThemeConfig (line 3) | interface ThemeConfig {
function getSystemTheme (line 27) | function getSystemTheme(): 'light' | 'dark' {
function applyTheme (line 32) | function applyTheme(theme: Theme) {
function getStoredTheme (line 52) | function getStoredTheme(): Theme {
function initializeTheme (line 57) | function initializeTheme() {
FILE: website/app/lib/translations.ts
type Translations (line 3) | interface Translations {
function getTranslation (line 127) | function getTranslation(language: Language, key: keyof Translations): st...
FILE: website/app/page.tsx
type Article (line 12) | interface Article {
function HomePage (line 24) | function HomePage() {
FILE: website/app/test-api/page.tsx
type Article (line 5) | interface Article {
type ArticlesResponse (line 17) | interface ArticlesResponse {
function TestAPIPage (line 29) | function TestAPIPage() {
FILE: website/app/test-demo/page.tsx
function TestDemoPage (line 3) | function TestDemoPage() {
FILE: website/app/test-fixes/page.tsx
function TestFixesPage (line 444) | function TestFixesPage() {
FILE: website/app/test-theme-lang/page.tsx
function TestThemeLangPage (line 7) | function TestThemeLangPage() {
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (342K chars).
[
{
"path": ".gitattributes",
"chars": 55,
"preview": "*.md linguist-language=CSS\n*.png linguist-language=CSS\n"
},
{
"path": "MCP/.gitignore",
"chars": 1179,
"preview": "# Dependencies\nnode_modules/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Environment variables\n.env\n.env.local\n.en"
},
{
"path": "MCP/LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2024 iCSS MCP Server\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "MCP/README.en.md",
"chars": 6728,
"preview": "# iCSS MCP Server\n\n> 🎨 A comprehensive Model Context Protocol (MCP) server that integrates both [iCSS repository](https:"
},
{
"path": "MCP/README.md",
"chars": 2878,
"preview": "# iCSS MCP Server 中文使用指南\n\n> iCSS MCP Server 是一个基于 Model Context Protocol (MCP) 的服务端,整合了 iCSS 技巧库和 CSS-Inspiration 演示案例,提"
},
{
"path": "MCP/bin/icss-mcp.js",
"chars": 1680,
"preview": "#!/usr/bin/env node\n\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { spawn } from 'c"
},
{
"path": "MCP/bin/install.js",
"chars": 5800,
"preview": "#!/usr/bin/env node\n\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\nimport { fileURLToPath } from 'u"
},
{
"path": "MCP/debug-interactive.js",
"chars": 3046,
"preview": "#!/usr/bin/env node\n\nimport { spawn } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url'"
},
{
"path": "MCP/debug-local.js",
"chars": 10560,
"preview": "#!/usr/bin/env node\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport }"
},
{
"path": "MCP/debug-query.js",
"chars": 4054,
"preview": "#!/usr/bin/env node\n\nimport { spawn } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url'"
},
{
"path": "MCP/debug.js",
"chars": 5903,
"preview": "#!/usr/bin/env node\n\nimport Database from 'sqlite3';\nimport Fuse from 'fuse.js';\n\nconsole.log('🔍 MCP Server Debug Tool\\n"
},
{
"path": "MCP/diagnose-mcp.js",
"chars": 6028,
"preview": "#!/usr/bin/env node\n\nimport fs from 'fs';\nimport path from 'path';\nimport { spawn } from 'child_process';\n\nconsole.log('"
},
{
"path": "MCP/package.json",
"chars": 2190,
"preview": "{\n \"name\": \"icss-mcp-server\",\n \"version\": \"1.1.1\",\n \"description\": \"Comprehensive MCP Server integrating iCSS techniq"
},
{
"path": "MCP/scripts/cursor-config.json",
"chars": 965,
"preview": "{\n \"mcpServers\": {\n \"icss\": {\n \"command\": \"node\",\n \"args\": [\"/Users/qi.qiao/Documents/Git/icss/MCP/server."
},
{
"path": "MCP/scripts/fetch-inspiration.js",
"chars": 17284,
"preview": "import axios from 'axios';\nimport Database from 'sqlite3';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileUR"
},
{
"path": "MCP/scripts/fetch-issues.js",
"chars": 37049,
"preview": "import axios from 'axios';\nimport Database from 'sqlite3';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileUR"
},
{
"path": "MCP/scripts/publish-check.js",
"chars": 8196,
"preview": "#!/usr/bin/env node\n\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filenam"
},
{
"path": "MCP/server.js",
"chars": 25659,
"preview": "#!/usr/bin/env node\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport }"
},
{
"path": "MCP/setup.js",
"chars": 2792,
"preview": "#!/usr/bin/env node\n\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filenam"
},
{
"path": "MCP/test-inspiration.js",
"chars": 5652,
"preview": "#!/usr/bin/env node\n\nimport Database from 'sqlite3';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\ncons"
},
{
"path": "MCP/test-server.js",
"chars": 3301,
"preview": "#!/usr/bin/env node\n\nimport Database from 'sqlite3';\nimport Fuse from 'fuse.js';\n\nconsole.log('🧪 Testing iCSS MCP Server"
},
{
"path": "readme.md",
"chars": 39973,
"preview": "## \r\n\r\nCSS 奇技淫巧,在这里,都有。\r\n\r\n本 Repo 围绕 **CSS/Web动画*"
},
{
"path": "website/README.md",
"chars": 2689,
"preview": "# iCSS 网站\n\n基于 GitHub 上的 iCSS 仓库构建的现代化网站,展示 CSS 奇技淫巧。\n\n## 功能特性\n\n### 🎨 主题切换\n- **亮色主题**: 适合日间使用\n- **暗色主题**: 适合夜间使用,护眼\n- **跟"
},
{
"path": "website/THEME_LANG_FEATURES.md",
"chars": 3759,
"preview": "# 主题和语言切换功能说明\n\n## 🎨 主题切换功能\n\n### 功能特性\n- **亮色主题**: 适合日间使用,白色背景\n- **暗色主题**: 适合夜间使用,深色背景,护眼\n- **跟随系统**: 自动跟随系统主题设置\n- **持久化**"
},
{
"path": "website/app/api/articles/[id]/route.ts",
"chars": 687,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport { GitHubAPI } from '@/app/lib/github';\n\nexport async fun"
},
{
"path": "website/app/api/articles/route.ts",
"chars": 2725,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport { GitHubAPI } from '@/app/lib/github';\n\nexport async fun"
},
{
"path": "website/app/api/categories/route.ts",
"chars": 932,
"preview": "import { NextResponse } from 'next/server';\nimport { GitHubAPI } from '@/app/lib/github';\n\nexport async function GET() {"
},
{
"path": "website/app/article/[id]/page.tsx",
"chars": 28501,
"preview": "'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useParams, useRouter } from 'next/navigation';\nimpo"
},
{
"path": "website/app/components/CodeBlock.tsx",
"chars": 4982,
"preview": "'use client';\n\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { tomorrow } from 'react-sy"
},
{
"path": "website/app/components/LanguageToggle.tsx",
"chars": 2658,
"preview": "'use client';\n\nimport { useState, useRef, useEffect } from 'react';\nimport { useApp } from '../contexts/AppContext';\nimp"
},
{
"path": "website/app/components/ThemeToggle.tsx",
"chars": 3023,
"preview": "'use client';\n\nimport { useState, useRef, useEffect } from 'react';\nimport { useApp } from '../contexts/AppContext';\nimp"
},
{
"path": "website/app/contexts/AppContext.tsx",
"chars": 1985,
"preview": "'use client';\n\nimport React, { createContext, useContext, useEffect, useState } from 'react';\nimport { Theme, getStoredT"
},
{
"path": "website/app/globals.css",
"chars": 4714,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --f"
},
{
"path": "website/app/layout.tsx",
"chars": 1083,
"preview": "import type { Metadata } from 'next'\nimport { Inter } from 'next/font/google'\nimport './globals.css'\nimport { AppProvide"
},
{
"path": "website/app/lib/cache.ts",
"chars": 1307,
"preview": "interface CacheItem<T> {\n data: T;\n timestamp: number;\n ttl: number; // Time to live in milliseconds\n}\n\nclass Cache {"
},
{
"path": "website/app/lib/github.ts",
"chars": 9263,
"preview": "import { cache } from './cache';\n\ninterface GitHubIssue {\n id: number;\n number: number;\n title: string;\n body: strin"
},
{
"path": "website/app/lib/language.ts",
"chars": 607,
"preview": "export type Language = 'zh' | 'en';\n\nexport interface LanguageConfig {\n name: string;\n value: Language;\n flag: string"
},
{
"path": "website/app/lib/theme.ts",
"chars": 1500,
"preview": "export type Theme = 'light' | 'dark' | 'system';\n\nexport interface ThemeConfig {\n name: string;\n value: Theme;\n icon:"
},
{
"path": "website/app/lib/translations.ts",
"chars": 2823,
"preview": "import { Language } from './language';\n\nexport interface Translations {\n // 通用\n loading: string;\n error: string;\n ba"
},
{
"path": "website/app/page.tsx",
"chars": 10451,
"preview": "'use client';\n\nimport { useState, useEffect } from 'react';\nimport { motion } from 'framer-motion';\nimport { Search, Fil"
},
{
"path": "website/app/test-api/page.tsx",
"chars": 5613,
"preview": "'use client';\n\nimport { useState, useEffect } from 'react';\n\ninterface Article {\n id: number;\n title: string;\n url: s"
},
{
"path": "website/app/test-demo/page.tsx",
"chars": 11903,
"preview": "import CodeBlock from '../components/CodeBlock';\n\nexport default function TestDemoPage() {\n const demoCode = `<!-- Code"
},
{
"path": "website/app/test-fixes/page.tsx",
"chars": 14520,
"preview": "import CodeBlock from '../components/CodeBlock';\n\n// 解析行内 Markdown\nconst parseInlineMarkdown = (text: string): React.Rea"
},
{
"path": "website/app/test-theme-lang/page.tsx",
"chars": 9348,
"preview": "'use client';\n\nimport { useApp } from '../contexts/AppContext';\nimport ThemeToggle from '../components/ThemeToggle';\nimp"
},
{
"path": "website/next-env.d.ts",
"chars": 228,
"preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edite"
},
{
"path": "website/next.config.js",
"chars": 1269,
"preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n images: {\n remotePatterns: [\n {\n protocol"
},
{
"path": "website/package.json",
"chars": 861,
"preview": "{\n \"name\": \"icss-website\",\n \"version\": \"1.0.0\",\n \"description\": \"iCSS 文章展示网站\",\n \"private\": true,\n \"engines\": {\n "
},
{
"path": "website/postcss.config.js",
"chars": 82,
"preview": "module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n} "
},
{
"path": "website/public/index.md",
"chars": 5,
"preview": "## 测试"
},
{
"path": "website/tailwind.config.js",
"chars": 3576,
"preview": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\n './pages/**/*.{js,ts,jsx,tsx,mdx}',\n "
},
{
"path": "website/test-features.md",
"chars": 1664,
"preview": "# 功能测试指南\n\n## 🎯 测试目标\n验证主题切换和多语言切换功能是否正常工作。\n\n## 🧪 测试步骤\n\n### 1. 基础功能测试\n访问以下页面,确保都能正常加载:\n- ✅ 首页: `http://localhost:3000`\n- ✅"
},
{
"path": "website/tsconfig.json",
"chars": 612,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"es5\",\n \"lib\": [\"dom\", \"dom.iterable\", \"es6\"],\n \"allowJs\": true,\n \"skipL"
},
{
"path": "website/vercel.json",
"chars": 202,
"preview": "{\n \"buildCommand\": \"pnpm build\",\n \"devCommand\": \"pnpm dev\",\n \"installCommand\": \"pnpm install\",\n \"regions\": ["
}
]
About this extraction
This page contains the full source code of the chokcoco/iCSS GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (318.0 KB), approximately 92.2k tokens, and a symbol index with 186 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.