feat: scaffold initial Cheatsheet Hub application
This commit establishes the foundational structure for the Cheatsheet Hub project. It includes the setup of a Vue 3, Vite, and TailwindCSS stack, along with core application features: - **Routing:** Configures `vue-router` for Home, Cheatsheet List, and Cheatsheet Detail pages. - **State Management:** Implements a `pinia` store for theme management (dark/light mode) and mock data. - **UI Components:** Adds reusable components like `NavBar`, `CheatsheetCard`, and `PrintButton`. - **Styling:** Integrates TailwindCSS with custom base styles, dark mode support, and print-friendly optimizations. - **Dependencies:** Adds key libraries including `marked` for content rendering.
This commit is contained in:
6432
package-lock.json
generated
Normal file
6432
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,11 @@
|
|||||||
"format": "prettier --write src/"
|
"format": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"marked": "^16.3.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"vue": "^3.5.18",
|
"vue": "^3.5.18",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1",
|
||||||
|
"axios": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node22": "^22.0.2",
|
"@tsconfig/node22": "^22.0.2",
|
||||||
@@ -35,6 +37,9 @@
|
|||||||
"typescript": "~5.8.0",
|
"typescript": "~5.8.0",
|
||||||
"vite": "^7.0.6",
|
"vite": "^7.0.6",
|
||||||
"vite-plugin-vue-devtools": "^8.0.0",
|
"vite-plugin-vue-devtools": "^8.0.0",
|
||||||
"vue-tsc": "^3.0.4"
|
"vue-tsc": "^3.0.4",
|
||||||
|
"tailwindcss": "^3.3.3",
|
||||||
|
"autoprefixer": "^10.4.14",
|
||||||
|
"postcss": "^8.4.24"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
589
pnpm-lock.yaml
generated
589
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
67
prompt.md
Normal file
67
prompt.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Cheatsheet 网站项目 Scaffold
|
||||||
|
|
||||||
|
你是一名资深前端架构师,熟悉 **Vue 3 + Vite + TailwindCSS** 的现代前端开发栈。
|
||||||
|
请帮我生成一个 **Cheatsheet 网站** 的基础工程结构,要求如下:
|
||||||
|
|
||||||
|
## 1. 技术栈
|
||||||
|
|
||||||
|
* **框架**:Vue 3 (Composition API)
|
||||||
|
* **构建工具**:Vite
|
||||||
|
* **样式**:TailwindCSS + 自定义 base.css / main.css
|
||||||
|
* **组件库**:官方 Vue 生态优先(可选 shadcn-vue / headlessui / radix-vue)
|
||||||
|
* **工具库**:
|
||||||
|
|
||||||
|
* `vue-router` (多视图切换:主页 / Cheatsheet 列表 / 单个 Cheatsheet 页面)
|
||||||
|
* `pinia` (全局状态管理,用于存储 Cheatsheet 配置、主题偏好)
|
||||||
|
* `axios` 或 `fetch`(数据获取,预留接口位)
|
||||||
|
|
||||||
|
## 2. 项目结构
|
||||||
|
|
||||||
|
请生成一个基础目录结构,包含:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
assets/ # 静态资源
|
||||||
|
components/ # 通用组件(按钮、卡片、导航栏)
|
||||||
|
views/ # 页面视图(HomeView, CheatsheetListView, CheatsheetDetailView)
|
||||||
|
store/ # Pinia 状态管理
|
||||||
|
router/ # vue-router 配置
|
||||||
|
styles/
|
||||||
|
base.css # Tailwind 基础覆盖样式
|
||||||
|
main.css # 全局样式入口
|
||||||
|
App.vue
|
||||||
|
main.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 基础样式
|
||||||
|
|
||||||
|
* 在 `base.css` 中:
|
||||||
|
|
||||||
|
* 定义打印优化样式(例如:去掉多余边框、背景)
|
||||||
|
* 定义默认字体、字号(便于打印的 A4 规格)
|
||||||
|
* 在 `main.css` 中:
|
||||||
|
|
||||||
|
* 引入 Tailwind
|
||||||
|
* 定义全局主题色(默认浅色 / 深色模式切换)
|
||||||
|
|
||||||
|
## 4. 默认页面
|
||||||
|
|
||||||
|
请提供基础模板代码:
|
||||||
|
|
||||||
|
* **HomeView**:展示官方 Cheatsheet(Docker, Vim)+ 推荐的自定义入口
|
||||||
|
* **CheatsheetListView**:显示所有 Cheatsheet 的卡片列表
|
||||||
|
* **CheatsheetDetailView**:单个 Cheatsheet 的内容,支持「打印模式」按钮
|
||||||
|
|
||||||
|
## 5. 通用组件
|
||||||
|
|
||||||
|
请生成:
|
||||||
|
|
||||||
|
* `NavBar.vue`(带首页 / Cheatsheet 列表 / 主题切换按钮)
|
||||||
|
* `CheatsheetCard.vue`(显示标题、简介、打印按钮)
|
||||||
|
* `PrintButton.vue`(触发浏览器打印)
|
||||||
|
|
||||||
|
## 6. 额外要求
|
||||||
|
|
||||||
|
* 所有组件保持简洁、易扩展,留出注释
|
||||||
|
* 尽量用 Tailwind Utility Class,而不是额外 CSS
|
||||||
|
* 确保项目可以直接运行(npm run dev)
|
||||||
36
src/App.vue
36
src/App.vue
@@ -1,11 +1,31 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1>You did it!</h1>
|
<div :class="{ 'dark': isDark }">
|
||||||
<p>
|
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||||
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
|
<NavBar />
|
||||||
documentation
|
<main class="container mx-auto px-4 py-8">
|
||||||
</p>
|
<router-view />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<script lang="ts">
|
||||||
|
import { mapState, mapWritableState } from 'pinia'
|
||||||
|
import { useAppStore } from './stores'
|
||||||
|
import NavBar from './components/NavBar.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
NavBar
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useAppStore, ['isDark']),
|
||||||
|
...mapWritableState(useAppStore, ['theme'])
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化主题
|
||||||
|
document.documentElement.setAttribute('data-theme', this.theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
29
src/components/CheatsheetCard.vue
Normal file
29
src/components/CheatsheetCard.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card hover:shadow-lg transition-shadow duration-200">
|
||||||
|
<h3 class="text-xl font-semibold mb-2">{{ cheatsheet.title }}</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mb-4">{{ cheatsheet.description }}</p>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<router-link :to="`/cheatsheet/${cheatsheet.id}`" class="text-primary-500 hover:text-primary-600 font-medium">
|
||||||
|
View Details
|
||||||
|
</router-link>
|
||||||
|
<PrintButton :cheatsheet="cheatsheet" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import PrintButton from './PrintButton.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CheatsheetCard',
|
||||||
|
components: {
|
||||||
|
PrintButton
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cheatsheet: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
46
src/components/NavBar.vue
Normal file
46
src/components/NavBar.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="bg-white dark:bg-gray-800 shadow-sm no-print">
|
||||||
|
<div class="container mx-auto px-4">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<router-link to="/" class="text-xl font-bold text-primary-500">
|
||||||
|
Cheatsheet Hub
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<router-link to="/" class="text-gray-700 dark:text-gray-300 hover:text-primary-500 transition-colors"
|
||||||
|
:class="{ 'text-primary-500 font-medium': $route.name === 'home' }">
|
||||||
|
Home
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<router-link to="/cheatsheets"
|
||||||
|
class="text-gray-700 dark:text-gray-300 hover:text-primary-500 transition-colors"
|
||||||
|
:class="{ 'text-primary-500 font-medium': $route.name === 'cheatsheets' }">
|
||||||
|
Cheatsheets
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<button @click="toggleTheme"
|
||||||
|
class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
|
aria-label="Toggle theme">
|
||||||
|
<span v-if="isDark">🌙</span>
|
||||||
|
<span v-else>☀️</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { mapState, mapActions } from 'pinia'
|
||||||
|
import { useAppStore } from '../stores'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NavBar',
|
||||||
|
computed: {
|
||||||
|
...mapState(useAppStore, ['isDark'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useAppStore, ['toggleTheme'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
27
src/components/PrintButton.vue
Normal file
27
src/components/PrintButton.vue
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<button @click="handlePrint"
|
||||||
|
class="p-2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors no-print"
|
||||||
|
aria-label="Print cheatsheet">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m4 4h6a2 2 0 002-2v-4a2 2 0 00-2-2h-6a2 2 0 00-2 2v4a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'PrintButton',
|
||||||
|
props: {
|
||||||
|
cheatsheet: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handlePrint() {
|
||||||
|
window.print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import './styles/main.css'
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import HomeView from '../views/HomeView.vue'
|
||||||
|
import CheatsheetListView from '../views/CheatsheetListView.vue'
|
||||||
|
import CheatsheetDetailView from '../views/CheatsheetDetailView.vue'
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
component: HomeView,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/cheatsheets',
|
||||||
|
name: 'cheatsheets',
|
||||||
|
component: CheatsheetListView,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/cheatsheet/:id',
|
||||||
|
name: 'cheatsheet',
|
||||||
|
component: CheatsheetDetailView,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(),
|
||||||
routes: [],
|
routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
42
src/stores/index.ts
Normal file
42
src/stores/index.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useAppStore = defineStore('app', {
|
||||||
|
state: () => ({
|
||||||
|
theme: 'light',
|
||||||
|
cheatsheets: [
|
||||||
|
{
|
||||||
|
id: 'docker',
|
||||||
|
title: 'Docker Cheatsheet',
|
||||||
|
description: 'Essential Docker commands and tips',
|
||||||
|
content:
|
||||||
|
'# Docker Commands\n\n## Container Management\n- `docker run [image]` - Start a new container\n- `docker ps` - List running containers\n- `docker stop [container]` - Stop a container',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vim',
|
||||||
|
title: 'Vim Cheatsheet',
|
||||||
|
description: 'Vim commands for efficient editing',
|
||||||
|
content:
|
||||||
|
'# Vim Commands\n\n## Navigation\n- `h,j,k,l` - Move left, down, up, right\n- `w` - Move to next word\n- `b` - Move to previous word',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'git',
|
||||||
|
title: 'Git Cheatsheet',
|
||||||
|
description: 'Common Git commands for version control',
|
||||||
|
content:
|
||||||
|
'# Git Commands\n\n## Basics\n- `git init` - Initialize a new repository\n- `git add [file]` - Stage changes\n- `git commit -m "message"` - Commit changes',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
isDark: (state) => state.theme === 'dark',
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
toggleTheme() {
|
||||||
|
this.theme = this.theme === 'light' ? 'dark' : 'light'
|
||||||
|
document.documentElement.setAttribute('data-theme', this.theme)
|
||||||
|
},
|
||||||
|
getCheatsheetById(id) {
|
||||||
|
return this.cheatsheets.find((c) => c.id === id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
53
src/styles/base.css
Normal file
53
src/styles/base.css
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* 打印优化样式 */
|
||||||
|
@media print {
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
background: transparent !important;
|
||||||
|
color: black !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
text-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 12pt;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-family: 'Times New Roman', Times, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保链接在打印时显示URL */
|
||||||
|
a[href]:after {
|
||||||
|
content: ' (' attr(href) ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 避免在内容中间分页 */
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
page-break-after: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
blockquote {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 默认字体和排版 */
|
||||||
|
body {
|
||||||
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A4规格尺寸参考 */
|
||||||
|
.a4-container {
|
||||||
|
width: 210mm;
|
||||||
|
min-height: 297mm;
|
||||||
|
}
|
||||||
32
src/styles/main.css
Normal file
32
src/styles/main.css
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* These Tailwind directives must be processed by Tailwind CSS build tools like PostCSS.
|
||||||
|
If you see "Unknown at rule @tailwind", make sure your build pipeline includes Tailwind CSS.
|
||||||
|
If you want to use plain CSS, remove these lines and use the generated output from Tailwind. */
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* 全局主题变量 */
|
||||||
|
:root {
|
||||||
|
--color-primary: #3b82f6;
|
||||||
|
--color-primary-dark: #2563eb;
|
||||||
|
--color-background: #ffffff;
|
||||||
|
--color-text: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] {
|
||||||
|
--color-primary: #60a5fa;
|
||||||
|
--color-primary-dark: #3b82f6;
|
||||||
|
--color-background: #111827;
|
||||||
|
--color-text: #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义组件样式 */
|
||||||
|
@layer components {
|
||||||
|
.btn-primary {
|
||||||
|
@apply bg-primary-500 hover:bg-primary-600 text-white font-medium py-2 px-4 rounded transition-colors duration-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@apply bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 border border-gray-200 dark:border-gray-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/views/CheatsheetDetailView.vue
Normal file
54
src/views/CheatsheetDetailView.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="cheatsheet" class="a4-container mx-auto">
|
||||||
|
<div class="card mb-6 no-print">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h1 class="text-3xl font-bold">{{ cheatsheet.title }}</h1>
|
||||||
|
<PrintButton :cheatsheet="cheatsheet" />
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mt-2">{{ cheatsheet.description }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-md">
|
||||||
|
<div v-html="renderedContent" class="prose dark:prose-invert max-w-none"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="text-center py-12">
|
||||||
|
<p class="text-xl">Cheatsheet not found</p>
|
||||||
|
<router-link to="/cheatsheets" class="text-primary-500 hover:underline mt-4 inline-block">
|
||||||
|
Back to all cheatsheets
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { marked } from 'marked'
|
||||||
|
import { mapActions } from 'pinia'
|
||||||
|
import { useAppStore } from '../stores'
|
||||||
|
import PrintButton from '../components/PrintButton.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CheatsheetDetailView',
|
||||||
|
components: {
|
||||||
|
PrintButton
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cheatsheet: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
renderedContent() {
|
||||||
|
if (!this.cheatsheet?.content) return ''
|
||||||
|
return marked(this.cheatsheet.content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
const cheatsheetId = this.$route.params.id
|
||||||
|
this.cheatsheet = this.getCheatsheetById(cheatsheetId)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useAppStore, ['getCheatsheetById'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
25
src/views/CheatsheetListView.vue
Normal file
25
src/views/CheatsheetListView.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold mb-8">All Cheatsheets</h1>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<CheatsheetCard v-for="cheatsheet in cheatsheets" :key="cheatsheet.id" :cheatsheet="cheatsheet" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { useAppStore } from '../stores'
|
||||||
|
import CheatsheetCard from '../components/CheatsheetCard.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CheatsheetListView',
|
||||||
|
components: {
|
||||||
|
CheatsheetCard
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useAppStore, ['cheatsheets'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
44
src/views/HomeView.vue
Normal file
44
src/views/HomeView.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<section class="mb-12">
|
||||||
|
<h1 class="text-4xl font-bold text-center mb-6">Welcome to Cheatsheet Hub</h1>
|
||||||
|
<p class="text-xl text-center text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||||
|
Your one-stop destination for all programming cheatsheets. Find, create, and share useful references.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 class="text-2xl font-semibold mb-6">Popular Cheatsheets</h2>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<CheatsheetCard v-for="cheatsheet in featuredCheatsheets" :key="cheatsheet.id" :cheatsheet="cheatsheet" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mt-12">
|
||||||
|
<div class="card text-center">
|
||||||
|
<h2 class="text-2xl font-semibold mb-4">Can't find what you're looking for?</h2>
|
||||||
|
<p class="mb-6">Suggest a new cheatsheet or contribute to our growing collection.</p>
|
||||||
|
<button class="btn-primary">Suggest a Cheatsheet</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { useAppStore } from '../stores'
|
||||||
|
import CheatsheetCard from '../components/CheatsheetCard.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HomeView',
|
||||||
|
components: {
|
||||||
|
CheatsheetCard
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useAppStore, ['cheatsheets']),
|
||||||
|
featuredCheatsheets() {
|
||||||
|
return this.cheatsheets.slice(0, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
24
tailwind.config.js
Normal file
24
tailwind.config.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// tailwind.config.js
|
||||||
|
export default {
|
||||||
|
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
50: '#eff6ff',
|
||||||
|
100: '#dbeafe',
|
||||||
|
200: '#bfdbfe',
|
||||||
|
300: '#93c5fd',
|
||||||
|
400: '#60a5fa',
|
||||||
|
500: '#3b82f6',
|
||||||
|
600: '#2563eb', // This defines bg-primary-600
|
||||||
|
700: '#1d4ed8',
|
||||||
|
800: '#1e40af',
|
||||||
|
900: '#1e3a8a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
darkMode: 'class',
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user