Skip to content

Commit 45dad29

Browse files
committed
更改插件页面
1 parent f1ee5e4 commit 45dad29

File tree

6 files changed

+189
-14
lines changed

6 files changed

+189
-14
lines changed

.markdownlint-cli2.jsonc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"globs": ["**.md"],
3+
"ignores": ["node_modules/**"],
4+
"config": {
5+
"no-inline-html": false,
6+
"line-length": false,
7+
"no-duplicate-heading": false
8+
}
9+
}

.vitepress/components/CustomLayout.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import PluginInfoBar from './PluginInfoBar.vue';
1111
const { Layout } = DefaultTheme;
1212
1313
const frontmatter = useData().frontmatter;
14-
const plugin = computed<PluginDetailedInfo | undefined>(() => data[useData().frontmatter.value.id]);
14+
const plugin = computed<PluginDetailedInfo | undefined>(() => data.all[useData().frontmatter.value.id]);
1515
1616
</script>
1717

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<script setup lang="ts">
2+
// @ts-expect-error
3+
import { data } from '../../gallery.data.ts';
4+
import { computed, ref } from 'vue';
5+
import { PluginDetailedInfo } from '../libs/type.ts';
6+
import { useRouter } from 'vitepress';
7+
8+
const router = useRouter();
9+
const plugins = Object.entries(
10+
data.all as { [key: string]: PluginDetailedInfo }
11+
);
12+
13+
const search = ref('');
14+
const filteredPlugins = computed(() => {
15+
if (!search.value) return plugins;
16+
17+
const searchLower = search.value.toLowerCase();
18+
return plugins.filter(
19+
([id, plugin]) =>
20+
id.toLowerCase().includes(searchLower) ||
21+
plugin.name.toLowerCase().includes(searchLower) ||
22+
plugin.description.toLowerCase().includes(searchLower)
23+
);
24+
});
25+
</script>
26+
27+
<template>
28+
<div class="container">
29+
<h1>插件列表</h1>
30+
31+
<div class="search-box-container">
32+
<input
33+
type="text"
34+
id="search-box"
35+
v-model="search"
36+
placeholder="通过Id、名称、介绍搜索插件..."
37+
autocapitalize="off"
38+
autocomplete="off"
39+
autocorrect="off"
40+
/>
41+
</div>
42+
43+
<div class="plugin-count">
44+
当前共{{ plugins.length }}个插件
45+
<span v-if="search">,搜索结果:{{ filteredPlugins.length }}个</span>
46+
</div>
47+
48+
<div class="plugin-list">
49+
<div
50+
class="plugin-card"
51+
v-for="plugin in filteredPlugins"
52+
:key="plugin[0]"
53+
@click="router.go(`/plugins/${plugin[0]}`)"
54+
>
55+
<div class="plugin-name">
56+
<b>{{ plugin[1].name }}</b> <Badge v-text="plugin[0]" type="info" />
57+
</div>
58+
<div class="plugin-description">{{ plugin[1].description }}</div>
59+
<div class="plugin-tags">
60+
<Badge
61+
v-for="tag of plugin[1].tags"
62+
type="tip"
63+
:text="
64+
{
65+
entertainment: '娱乐',
66+
development: '开发',
67+
tool: '工具',
68+
information: '信息',
69+
management: '管理',
70+
api: 'API',
71+
}[tag]
72+
"
73+
/>
74+
</div>
75+
<div class="plugin-downloads">
76+
下载量:{{ plugin[1].repo.downloads }}
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
</template>
82+
83+
<style scoped>
84+
h1 {
85+
letter-spacing: -0.02em;
86+
line-height: 40px;
87+
font-size: 32px;
88+
font-weight: 600;
89+
margin-bottom: 20px;
90+
text-align: center;
91+
}
92+
93+
.container {
94+
padding: 50px;
95+
}
96+
97+
#search-box {
98+
width: 100%;
99+
padding: 15px;
100+
font-size: 15px;
101+
border: 1px solid;
102+
border-radius: 8px;
103+
border-color: transparent;
104+
background: var(--vp-c-bg-alt);
105+
cursor: pointer;
106+
outline: none;
107+
transition: border-color 0.25s;
108+
}
109+
110+
#search-box:hover {
111+
border-color: var(--vp-c-brand-1);
112+
}
113+
114+
.search-box-container {
115+
margin: 20px 0;
116+
}
117+
.plugin-count {
118+
width: 100%;
119+
text-align: center;
120+
font-size: smaller;
121+
margin: 10px;
122+
}
123+
124+
.plugin-list {
125+
display: grid;
126+
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
127+
gap: 20px;
128+
margin: 20px 5px;
129+
}
130+
131+
.plugin-card {
132+
padding: 20px;
133+
border-radius: 8px;
134+
border: 1px solid;
135+
border-color: var(--vp-c-gray-3);
136+
transition: border-color 0.25s;
137+
cursor: pointer;
138+
139+
display: flex;
140+
flex-direction: column;
141+
min-height: 180px;
142+
}
143+
144+
.plugin-card:hover {
145+
border-color: var(--vp-c-brand-1);
146+
}
147+
148+
.plugin-description,
149+
.plugin-downloads {
150+
font-size: 14px;
151+
margin-top: 3px;
152+
}
153+
154+
.plugin-tags {
155+
margin-top: auto;
156+
display: flex;
157+
flex-wrap: wrap;
158+
gap: 4px;
159+
}
160+
</style>

.vitepress/config.mts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ export default defineConfig({
5252
useFolderLinkFromIndexFile: true,
5353
useTitleFromFrontmatter: true,
5454
useFolderTitleFromIndexFile: true,
55-
sortMenusByFrontmatterDate: true,
56-
sortMenusOrderByDescending: true,
55+
sortMenusByFrontmatterOrder: true,
5756
},
5857
]),
5958

.vitepress/theme/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import giscusTalk from 'vitepress-plugin-comment-with-giscus';
66
import DefaultTheme from 'vitepress/theme';
77
import { toRefs } from 'vue';
88
import CustomLayout from '../components/CustomLayout.vue';
9+
import PluginListPage from '../components/PluginListPage.vue';
910
import './backToTop.css';
1011
import './style.css';
1112

1213
export default {
1314
extends: DefaultTheme,
15+
1416
Layout: CustomLayout,
15-
enhanceApp({ app, router, siteData }) {
16-
// ...
17+
18+
enhanceApp({ app }) {
19+
app.component('PluginListPage', PluginListPage);
1720
vitepressBackToTop({ threshold: 300 });
1821
},
22+
1923
setup() {
2024
const { frontmatter } = toRefs(useData());
2125
const route = useRoute();

gallery.data.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import { readFileSync } from 'fs';
22
import path from 'path';
3-
import { PluginDetailedInfo } from './.vitepress/libs/type';
43

54
export default {
65
load() {
7-
const data = JSON.parse(
8-
readFileSync(
9-
path.join(__dirname, 'public', 'gallery', 'plugins', '@all.json'),
10-
'utf-8'
11-
)
12-
) as { time: string; data: { [key: string]: PluginDetailedInfo } };
13-
14-
return data.data;
6+
return {
7+
all: read('@all.json'),
8+
authors: read('@authors.json'),
9+
tags: read('@tags.json'),
10+
meta: read('@meta.json'),
11+
};
1512
},
1613
};
14+
15+
function read(fileName: string) {
16+
return JSON.parse(
17+
readFileSync(path.join('public', 'gallery', 'plugins', fileName), 'utf-8')
18+
).data;
19+
}

0 commit comments

Comments
 (0)