ad95658a11
- Add NavGrid.vue and NavCard.vue components for better navigation layout - Restructure stage-0 index pages across languages into intro.md with new navigation components - Remove old stage-0 index.md files and update stage-3 pages similarly - Add new dependencies 'claude' and 'codex' to package.json - Improve code formatting in multiple Vue components for better readability - Update documentation content and structure for better user experience
995 lines
22 KiB
Vue
995 lines
22 KiB
Vue
<template>
|
||
<div class="language-ecosystem-demo">
|
||
<div class="demo-header">
|
||
<h4>生态系统对比</h4>
|
||
<p class="subtitle">不同语言的包管理器、框架和社区活跃度</p>
|
||
</div>
|
||
|
||
<div class="ecosystem-tabs">
|
||
<button
|
||
v-for="tab in tabs"
|
||
:key="tab.id"
|
||
class="tab-btn"
|
||
:class="{ active: selectedTab === tab.id }"
|
||
@click="selectedTab = tab.id"
|
||
>
|
||
{{ tab.label }}
|
||
</button>
|
||
</div>
|
||
|
||
<transition name="fade" mode="out-in">
|
||
<div :key="selectedTab" class="tab-content">
|
||
<!-- Package Managers -->
|
||
<div v-if="selectedTab === 'packages'" class="packages-section">
|
||
<div class="packages-grid">
|
||
<div
|
||
v-for="pkg in packageManagers"
|
||
:key="pkg.name"
|
||
class="package-card"
|
||
>
|
||
<div class="pkg-header">
|
||
<span class="pkg-icon">{{ pkg.icon }}</span>
|
||
<div class="pkg-info">
|
||
<h5>{{ pkg.name }}</h5>
|
||
<span class="pkg-lang">{{ pkg.language }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="pkg-stats">
|
||
<div class="stat">
|
||
<span class="stat-label">包数量</span>
|
||
<span class="stat-value">{{ formatNumber(pkg.count) }}</span>
|
||
</div>
|
||
<div class="stat">
|
||
<span class="stat-label">周下载量</span>
|
||
<span class="stat-value">{{
|
||
formatDownloads(pkg.downloads)
|
||
}}</span>
|
||
</div>
|
||
</div>
|
||
<div class="pkg-command">
|
||
<code>{{ pkg.command }}</code>
|
||
</div>
|
||
<div class="pkg-features">
|
||
<div
|
||
v-for="feature in pkg.features"
|
||
:key="feature"
|
||
class="feature-tag"
|
||
>
|
||
{{ feature }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Web Frameworks -->
|
||
<div
|
||
v-else-if="selectedTab === 'frameworks'"
|
||
class="frameworks-section"
|
||
>
|
||
<div class="frameworks-table-wrapper">
|
||
<table class="frameworks-table">
|
||
<thead>
|
||
<tr>
|
||
<th>框架</th>
|
||
<th>语言</th>
|
||
<th>性能</th>
|
||
<th>学习曲线</th>
|
||
<th>特点</th>
|
||
<th>适用场景</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="fw in frameworks" :key="fw.name">
|
||
<td class="fw-name">
|
||
<span class="fw-icon">{{ fw.icon }}</span>
|
||
{{ fw.name }}
|
||
</td>
|
||
<td>{{ fw.language }}</td>
|
||
<td>
|
||
<div class="rating-bar">
|
||
<div
|
||
class="rating-fill"
|
||
:style="{ width: fw.performance + '%' }"
|
||
></div>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="rating-bar learning">
|
||
<div
|
||
class="rating-fill"
|
||
:style="{ width: fw.learning + '%' }"
|
||
></div>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="tags">
|
||
<span
|
||
v-for="tag in fw.tags"
|
||
:key="tag"
|
||
class="tag"
|
||
:class="`tag-${tag.type}`"
|
||
>
|
||
{{ tag.label }}
|
||
</span>
|
||
</div>
|
||
</td>
|
||
<td>{{ fw.useCase }}</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Community -->
|
||
<div v-else-if="selectedTab === 'community'" class="community-section">
|
||
<div class="community-metrics">
|
||
<div class="metric-card">
|
||
<div class="metric-header">
|
||
<span class="metric-icon">📦</span>
|
||
<h5>GitHub Stars</h5>
|
||
</div>
|
||
<div class="metric-chart">
|
||
<div
|
||
v-for="lang in communityStats"
|
||
:key="lang.name"
|
||
class="chart-bar"
|
||
>
|
||
<div class="bar-label">{{ lang.name }}</div>
|
||
<div class="bar-container">
|
||
<div
|
||
class="bar-fill"
|
||
:style="{ width: lang.stars / 100 + '%' }"
|
||
>
|
||
<span class="bar-value">{{ lang.stars }}M</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="metric-card">
|
||
<div class="metric-header">
|
||
<span class="metric-icon">💬</span>
|
||
<h5>Stack Overflow 问题</h5>
|
||
</div>
|
||
<div class="metric-chart">
|
||
<div
|
||
v-for="lang in communityStats"
|
||
:key="lang.name"
|
||
class="chart-bar"
|
||
>
|
||
<div class="bar-label">{{ lang.name }}</div>
|
||
<div class="bar-container">
|
||
<div
|
||
class="bar-fill questions"
|
||
:style="{ width: lang.questions / 30 + '%' }"
|
||
>
|
||
<span class="bar-value">{{ lang.questions }}M</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="community-insights">
|
||
<h5>社区活跃度分析</h5>
|
||
<div class="insight-grid">
|
||
<div class="insight-card">
|
||
<h6>最活跃</h6>
|
||
<p>
|
||
JavaScript/Node.js 社区最活跃,NPM
|
||
每周新增数万个包,问题响应速度最快。
|
||
</p>
|
||
</div>
|
||
<div class="insight-card">
|
||
<h6>最专业</h6>
|
||
<p>
|
||
Java 社区最专业,企业级问题讨论深入,Stack Overflow 质量最高。
|
||
</p>
|
||
</div>
|
||
<div class="insight-card">
|
||
<h6>增长最快</h6>
|
||
<p>
|
||
Rust 和 Go 社区增长最快,新一代开发者涌入,问题讨论质量高。
|
||
</p>
|
||
</div>
|
||
<div class="insight-card">
|
||
<h6>最友好</h6>
|
||
<p>Python 和 Ruby 社区对新手最友好,问题回复耐心,文档详尽。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Learning Resources -->
|
||
<div v-else-if="selectedTab === 'learning'" class="learning-section">
|
||
<div class="resources-grid">
|
||
<div
|
||
v-for="resource in learningResources"
|
||
:key="resource.language"
|
||
class="resource-card"
|
||
>
|
||
<div class="resource-header">
|
||
<span class="resource-icon">{{ resource.icon }}</span>
|
||
<h5>{{ resource.language }}</h5>
|
||
</div>
|
||
<div class="resource-content">
|
||
<div class="resource-section">
|
||
<h6>官方文档</h6>
|
||
<div class="doc-rating">
|
||
<span
|
||
v-for="i in 5"
|
||
:key="i"
|
||
class="star"
|
||
:class="{ filled: i <= resource.docQuality }"
|
||
>
|
||
★
|
||
</span>
|
||
</div>
|
||
<p class="doc-comment">{{ resource.docComment }}</p>
|
||
</div>
|
||
<div class="resource-section">
|
||
<h6>推荐书籍</h6>
|
||
<ul>
|
||
<li v-for="book in resource.books" :key="book">
|
||
{{ book }}
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="resource-section">
|
||
<h6>在线课程</h6>
|
||
<div class="courses">
|
||
<span
|
||
v-for="course in resource.courses"
|
||
:key="course"
|
||
class="course-tag"
|
||
>
|
||
{{ course }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="resource-section">
|
||
<h6>学习曲线</h6>
|
||
<div class="learning-curve">
|
||
<div
|
||
class="curve-bar"
|
||
:style="{ width: resource.learningCurve + '%' }"
|
||
></div>
|
||
</div>
|
||
<p class="curve-label">{{ resource.curveLabel }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</transition>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
|
||
const selectedTab = ref('packages')
|
||
|
||
const tabs = [
|
||
{ id: 'packages', label: '包管理器' },
|
||
{ id: 'frameworks', label: 'Web 框架' },
|
||
{ id: 'community', label: '社区活跃度' },
|
||
{ id: 'learning', label: '学习资源' }
|
||
]
|
||
|
||
const packageManagers = [
|
||
{
|
||
name: 'NPM',
|
||
icon: '💚',
|
||
language: 'Node.js',
|
||
count: 2000000,
|
||
downloads: '50B/week',
|
||
command: 'npm install express',
|
||
features: ['最大生态', '版本管理灵活', '依赖地狱风险']
|
||
},
|
||
{
|
||
name: 'PyPI',
|
||
icon: '🐍',
|
||
language: 'Python',
|
||
count: 500000,
|
||
downloads: '10B/week',
|
||
command: 'pip install django',
|
||
features: ['虚拟环境', '依赖管理清晰', '打包部署复杂']
|
||
},
|
||
{
|
||
name: 'Maven',
|
||
icon: '☕',
|
||
language: 'Java',
|
||
count: 300000,
|
||
downloads: '5B/week',
|
||
command: 'mvn install',
|
||
features: ['企业级', '依赖管理严格', 'XML 配置冗长']
|
||
},
|
||
{
|
||
name: 'Go Modules',
|
||
icon: '🐹',
|
||
language: 'Go',
|
||
count: 100000,
|
||
downloads: '500M/week',
|
||
command: 'go get github.com/gin-gonic/gin',
|
||
features: ['简洁', '无依赖地狱', '版本支持完善']
|
||
},
|
||
{
|
||
name: 'Cargo',
|
||
icon: '🦀',
|
||
language: 'Rust',
|
||
count: 100000,
|
||
downloads: '200M/week',
|
||
command: 'cargo add serde',
|
||
features: ['现代化', '构建工具集成', '编译时间长']
|
||
},
|
||
{
|
||
name: 'RubyGems',
|
||
icon: '💎',
|
||
language: 'Ruby',
|
||
count: 150000,
|
||
downloads: '300M/week',
|
||
command: 'gem install rails',
|
||
features: ['Bundler 管理', 'Gemfile 简洁', '版本冲突问题']
|
||
}
|
||
]
|
||
|
||
const frameworks = [
|
||
{
|
||
name: 'Express',
|
||
icon: '💚',
|
||
language: 'Node.js',
|
||
performance: 70,
|
||
learning: 90,
|
||
tags: [
|
||
{ type: 'success', label: '简洁' },
|
||
{ type: 'info', label: '灵活' }
|
||
],
|
||
useCase: '快速原型、API 服务'
|
||
},
|
||
{
|
||
name: 'Django',
|
||
icon: '🐍',
|
||
language: 'Python',
|
||
performance: 40,
|
||
learning: 85,
|
||
tags: [
|
||
{ type: 'success', label: '大而全' },
|
||
{ type: 'info', label: 'ORM' }
|
||
],
|
||
useCase: '数据驱动应用、快速开发'
|
||
},
|
||
{
|
||
name: 'Spring Boot',
|
||
icon: '☕',
|
||
language: 'Java',
|
||
performance: 75,
|
||
learning: 50,
|
||
tags: [
|
||
{ type: 'success', label: '企业级' },
|
||
{ type: 'warning', label: '复杂' }
|
||
],
|
||
useCase: '企业级应用、微服务'
|
||
},
|
||
{
|
||
name: 'Gin',
|
||
icon: '🐹',
|
||
language: 'Go',
|
||
performance: 95,
|
||
learning: 80,
|
||
tags: [
|
||
{ type: 'success', label: '高性能' },
|
||
{ type: 'info', label: '轻量' }
|
||
],
|
||
useCase: '高性能 API、微服务'
|
||
},
|
||
{
|
||
name: 'Rails',
|
||
icon: '💎',
|
||
language: 'Ruby',
|
||
performance: 35,
|
||
learning: 85,
|
||
tags: [
|
||
{ type: 'success', label: '约定优于配置' },
|
||
{ type: 'info', label: 'MVC' }
|
||
],
|
||
useCase: '初创公司、快速迭代'
|
||
},
|
||
{
|
||
name: 'Flask',
|
||
icon: '🐍',
|
||
language: 'Python',
|
||
performance: 45,
|
||
learning: 95,
|
||
tags: [
|
||
{ type: 'success', label: '轻量' },
|
||
{ type: 'info', label: '灵活' }
|
||
],
|
||
useCase: '小型项目、学习'
|
||
},
|
||
{
|
||
name: 'FastAPI',
|
||
icon: '🐍',
|
||
language: 'Python',
|
||
performance: 65,
|
||
learning: 85,
|
||
tags: [
|
||
{ type: 'success', label: '异步' },
|
||
{ type: 'info', label: '类型安全' }
|
||
],
|
||
useCase: '现代 API、异步任务'
|
||
},
|
||
{
|
||
name: 'Actix',
|
||
icon: '🦀',
|
||
language: 'Rust',
|
||
performance: 98,
|
||
learning: 30,
|
||
tags: [
|
||
{ type: 'success', label: '极致性能' },
|
||
{ type: 'danger', label: '难学' }
|
||
],
|
||
useCase: '高性能服务、系统编程'
|
||
}
|
||
]
|
||
|
||
const communityStats = [
|
||
{ name: 'JavaScript', stars: 85, questions: 28 },
|
||
{ name: 'Python', stars: 75, questions: 25 },
|
||
{ name: 'Java', stars: 65, questions: 22 },
|
||
{ name: 'Go', stars: 55, questions: 8 },
|
||
{ name: 'Rust', stars: 60, questions: 5 },
|
||
{ name: 'Ruby', stars: 40, questions: 6 },
|
||
{ name: 'C#', stars: 50, questions: 12 },
|
||
{ name: 'C++', stars: 70, questions: 18 }
|
||
]
|
||
|
||
const learningResources = [
|
||
{
|
||
language: 'Python',
|
||
icon: '🐍',
|
||
docQuality: 5,
|
||
docComment: '官方文档极其详尽,教程丰富',
|
||
books: ['Fluent Python', 'Python Cookbook'],
|
||
courses: ['Coursera', 'edX', 'Udemy'],
|
||
learningCurve: 95,
|
||
curveLabel: '最简单'
|
||
},
|
||
{
|
||
language: 'Go',
|
||
icon: '🐹',
|
||
docQuality: 5,
|
||
docComment: '官方教程优秀,A Tour of Go 经典',
|
||
books: ['The Go Programming Language', 'Go in Action'],
|
||
courses: ['Udemy', 'Coursera', '官方文档'],
|
||
learningCurve: 80,
|
||
curveLabel: '简单'
|
||
},
|
||
{
|
||
language: 'JavaScript',
|
||
icon: '💚',
|
||
docQuality: 4,
|
||
docComment: 'MDN 文档权威,但碎片化',
|
||
books: ['Eloquent JavaScript', "You Don't Know JS"],
|
||
courses: ['freeCodeCamp', 'Udemy', 'Codecademy'],
|
||
learningCurve: 75,
|
||
curveLabel: '中等'
|
||
},
|
||
{
|
||
language: 'Java',
|
||
icon: '☕',
|
||
docQuality: 4,
|
||
docComment: 'Oracle 官方文档完善,但冗长',
|
||
books: ['Effective Java', 'Java Concurrency'],
|
||
courses: ['Coursera', 'Udemy', 'Oracle 官方'],
|
||
learningCurve: 40,
|
||
curveLabel: '较难'
|
||
},
|
||
{
|
||
language: 'Rust',
|
||
icon: '🦀',
|
||
docQuality: 5,
|
||
docComment: 'The Rust Book 极其详细',
|
||
books: ['The Rust Programming Language', 'Rust in Action'],
|
||
courses: ['Udemy', 'Exercism', '官方文档'],
|
||
learningCurve: 20,
|
||
curveLabel: '极难'
|
||
},
|
||
{
|
||
language: 'C#',
|
||
icon: '💜',
|
||
docQuality: 5,
|
||
docComment: 'Microsoft 文档极其详细',
|
||
books: ['C# in Depth', 'Pro C#'],
|
||
courses: ['Microsoft Learn', 'Udemy', 'Pluralsight'],
|
||
learningCurve: 50,
|
||
curveLabel: '中等'
|
||
}
|
||
]
|
||
|
||
const formatNumber = (num) => {
|
||
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M+'
|
||
if (num >= 1000) return (num / 1000).toFixed(0) + 'K+'
|
||
return num.toString()
|
||
}
|
||
|
||
const formatDownloads = (downloads) => {
|
||
return downloads
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.language-ecosystem-demo {
|
||
background: var(--vp-c-bg);
|
||
border-radius: 12px;
|
||
padding: 2rem;
|
||
margin: 2rem 0;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
||
border: 1px solid var(--vp-c-divider);
|
||
}
|
||
|
||
.demo-header {
|
||
text-align: center;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.demo-header h4 {
|
||
margin: 0 0 0.5rem 0;
|
||
color: var(--vp-c-brand);
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.subtitle {
|
||
margin: 0;
|
||
color: var(--vp-c-text-2);
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.ecosystem-tabs {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
margin-bottom: 2rem;
|
||
overflow-x: auto;
|
||
padding-bottom: 0.5rem;
|
||
}
|
||
|
||
.tab-btn {
|
||
padding: 0.75rem 1.5rem;
|
||
background: var(--vp-c-bg-soft);
|
||
border: 2px solid transparent;
|
||
border-radius: 8px;
|
||
color: var(--vp-c-text-1);
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tab-btn:hover {
|
||
border-color: var(--vp-c-brand);
|
||
}
|
||
|
||
.tab-btn.active {
|
||
background: var(--vp-c-brand);
|
||
color: white;
|
||
border-color: var(--vp-c-brand);
|
||
}
|
||
|
||
.tab-content {
|
||
animation: fade-in 0.3s ease;
|
||
}
|
||
|
||
.packages-grid,
|
||
.resources-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.package-card,
|
||
.resource-card {
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
border: 1px solid var(--vp-c-divider);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.package-card:hover,
|
||
.resource-card:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.pkg-header,
|
||
.resource-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.pkg-icon,
|
||
.resource-icon {
|
||
font-size: 2.5rem;
|
||
}
|
||
|
||
.pkg-info h5,
|
||
.resource-header h5 {
|
||
margin: 0;
|
||
color: var(--vp-c-text-1);
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.pkg-lang {
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.pkg-stats {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.stat {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.25rem;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 0.75rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
color: var(--vp-c-brand);
|
||
}
|
||
|
||
.pkg-command {
|
||
background: #1e1e1e;
|
||
border-radius: 6px;
|
||
padding: 0.75rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.pkg-command code {
|
||
color: #4ec9b0;
|
||
font-family: 'Monaco', 'Menlo', monospace;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.pkg-features,
|
||
.courses {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.feature-tag,
|
||
.course-tag {
|
||
padding: 0.25rem 0.75rem;
|
||
background: var(--vp-c-bg);
|
||
border-radius: 12px;
|
||
font-size: 0.75rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.frameworks-table-wrapper {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.frameworks-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.frameworks-table th {
|
||
background: var(--vp-c-bg-soft);
|
||
padding: 1rem;
|
||
text-align: left;
|
||
font-weight: 600;
|
||
color: var(--vp-c-text-1);
|
||
border-bottom: 2px solid var(--vp-c-divider);
|
||
}
|
||
|
||
.frameworks-table td {
|
||
padding: 1rem;
|
||
border-bottom: 1px solid var(--vp-c-divider);
|
||
}
|
||
|
||
.fw-name {
|
||
font-weight: 600;
|
||
color: var(--vp-c-text-1);
|
||
}
|
||
|
||
.fw-icon {
|
||
margin-right: 0.5rem;
|
||
}
|
||
|
||
.rating-bar {
|
||
width: 100px;
|
||
height: 8px;
|
||
background: var(--vp-c-bg);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.rating-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--vp-c-brand), #8b5cf6);
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.rating-bar.learning .rating-fill {
|
||
background: linear-gradient(90deg, #10b981, #059669);
|
||
}
|
||
|
||
.tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.tag {
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 12px;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.tag-success {
|
||
background: #dcfce7;
|
||
color: #15803d;
|
||
}
|
||
|
||
.tag-info {
|
||
background: #e0e7ff;
|
||
color: #4338ca;
|
||
}
|
||
|
||
.tag-warning {
|
||
background: #fef3c7;
|
||
color: #b45309;
|
||
}
|
||
|
||
.tag-danger {
|
||
background: #fee2e2;
|
||
color: #b91c1c;
|
||
}
|
||
|
||
.community-metrics {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
gap: 2rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.metric-card {
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
border: 1px solid var(--vp-c-divider);
|
||
}
|
||
|
||
.metric-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.metric-icon {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.metric-header h5 {
|
||
margin: 0;
|
||
color: var(--vp-c-text-1);
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.metric-chart {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.chart-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.bar-label {
|
||
min-width: 80px;
|
||
font-weight: 600;
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-1);
|
||
}
|
||
|
||
.bar-container {
|
||
flex: 1;
|
||
height: 24px;
|
||
background: var(--vp-c-bg);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.bar-fill {
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding-right: 0.5rem;
|
||
background: linear-gradient(90deg, var(--vp-c-brand), #8b5cf6);
|
||
color: white;
|
||
font-weight: 600;
|
||
font-size: 0.75rem;
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.bar-fill.questions {
|
||
background: linear-gradient(90deg, #f59e0b, #d97706);
|
||
}
|
||
|
||
.community-insights h5 {
|
||
margin: 0 0 1.5rem 0;
|
||
color: var(--vp-c-text-1);
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.insight-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.insight-card {
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 8px;
|
||
padding: 1.5rem;
|
||
border-left: 4px solid var(--vp-c-brand);
|
||
}
|
||
|
||
.insight-card h6 {
|
||
margin: 0 0 0.75rem 0;
|
||
color: var(--vp-c-brand);
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.insight-card p {
|
||
margin: 0;
|
||
font-size: 0.9rem;
|
||
line-height: 1.6;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.resource-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.resource-section h6 {
|
||
margin: 0 0 0.75rem 0;
|
||
color: var(--vp-c-text-1);
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.doc-rating {
|
||
display: flex;
|
||
gap: 0.25rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.star {
|
||
color: var(--vp-c-divider);
|
||
}
|
||
|
||
.star.filled {
|
||
color: #fbbf24;
|
||
}
|
||
|
||
.doc-comment {
|
||
margin: 0;
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-2);
|
||
font-style: italic;
|
||
}
|
||
|
||
.resource-section ul {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.resource-section li {
|
||
padding: 0.25rem 0;
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-2);
|
||
position: relative;
|
||
padding-left: 1rem;
|
||
}
|
||
|
||
.resource-section li::before {
|
||
content: '▸';
|
||
position: absolute;
|
||
left: 0;
|
||
color: var(--vp-c-brand);
|
||
}
|
||
|
||
.learning-curve {
|
||
height: 8px;
|
||
background: var(--vp-c-bg);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.curve-bar {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #10b981, #059669);
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.curve-label {
|
||
margin: 0;
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.fade-enter-active,
|
||
.fade-leave-active {
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.fade-enter-from,
|
||
.fade-leave-to {
|
||
opacity: 0;
|
||
}
|
||
|
||
@keyframes fade-in {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(10px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.ecosystem-tabs {
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.packages-grid,
|
||
.resources-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.community-metrics {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.frameworks-table {
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.frameworks-table th,
|
||
.frameworks-table td {
|
||
padding: 0.5rem;
|
||
}
|
||
}
|
||
</style>
|