Skip to content

Commit 24bfcc1

Browse files
committed
feat: added project page and organized github cards into components
1 parent 49a5e66 commit 24bfcc1

File tree

13 files changed

+305
-89
lines changed

13 files changed

+305
-89
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script setup lang="ts">
2+
import type { HTMLAttributes } from 'vue'
3+
import GitHubGridCard, { type GitHubGridCardProps } from './GitHubGridCard.vue'
4+
5+
interface GitHubGrid {
6+
items: GitHubGridCardProps[]
7+
itemsToShow?: number
8+
spotlight: boolean
9+
spotlightClass?: HTMLAttributes['class']
10+
loading?: boolean
11+
}
12+
13+
const props = defineProps<GitHubGrid>()
14+
</script>
15+
16+
<template>
17+
<UPageGrid>
18+
<template v-if="props?.loading">
19+
<USkeleton
20+
v-for="index in props?.itemsToShow || 6"
21+
:key="'project-' + index"
22+
class="h-[220px] rounded-xl"
23+
/>
24+
</template>
25+
26+
<template v-else>
27+
<GitHubGridCard
28+
v-for="(item, index) in props?.items"
29+
:key="index"
30+
v-bind="item"
31+
:spotlight="props?.spotlight"
32+
:spotlight-class="props?.spotlightClass"
33+
/>
34+
</template>
35+
</UPageGrid>
36+
</template>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<script setup lang="ts">
2+
import type { HTMLAttributes } from 'vue'
3+
import type { ProjectExportItem } from '#shared/utils/useProjects'
4+
5+
export interface GitHubGridCardProps extends ProjectExportItem {
6+
spotlight?: boolean
7+
spotlightClass?: HTMLAttributes['class']
8+
}
9+
10+
const props = defineProps<GitHubGridCardProps>()
11+
</script>
12+
13+
<template>
14+
<UPageCard
15+
variant="ghost"
16+
:to="props.to"
17+
target="_blank"
18+
:ui="{
19+
footer: 'pt-4 mt-auto self-stretch'
20+
}"
21+
:spotlight="props.spotlight"
22+
:class="props.spotlightClass"
23+
>
24+
<template #body>
25+
<UUser
26+
:name="useStyleName(props.name)"
27+
:description="props.description"
28+
:avatar="{ src: props.owner.src, alt: props.owner.alt }"
29+
class="relative"
30+
orientation="horizontal"
31+
:ui="{
32+
root: 'flex items-start gap-2.5',
33+
avatar: 'size-5 mb-0',
34+
name: 'text-base text-pretty font-semibold text-highlighted',
35+
description: 'text-[15px] text-pretty text-muted'
36+
}"
37+
/>
38+
</template>
39+
40+
<template #footer>
41+
<div class="flex items-center justify-between text-sm text-muted">
42+
<span
43+
v-if="props.updatedAt"
44+
class="self-stretch"
45+
>
46+
{{ useStyleDate(props.updatedAt) }}
47+
</span>
48+
49+
<div class="space-x-2 flex items-center">
50+
<span
51+
class="flex items-center"
52+
>
53+
<UIcon
54+
name="i-lucide-star"
55+
class="mr-1 size-3"
56+
/>
57+
{{ useStyleCount(props.stars) }}
58+
</span>
59+
<span
60+
class="flex items-center"
61+
>
62+
<UIcon
63+
name="i-lucide-git-fork"
64+
class="mr-1 size-3"
65+
/>
66+
{{ useStyleCount(props.forks) }}
67+
</span>
68+
</div>
69+
</div>
70+
</template>
71+
</UPageCard>
72+
</template>

app/pages/download.vue

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script setup lang="ts">
2+
const { data: page } = await useAsyncData('page-download', () => queryCollection('download').first())
3+
4+
const title = page.value?.seo?.title || page.value?.title
5+
const description = page.value?.seo?.description || page.value?.description
6+
7+
useSeoMeta({
8+
titleTemplate: '',
9+
title,
10+
ogTitle: title,
11+
description,
12+
ogDescription: description
13+
})
14+
</script>
15+
16+
<template>
17+
<div v-if="page">
18+
<UPageSection
19+
v-if="page.download"
20+
v-bind="page.download"
21+
:ui="{
22+
container: 'pb-8 sm:pb-12 lg:pb-20'
23+
}"
24+
>
25+
<!-- -->
26+
</UPageSection>
27+
</div>
28+
</template>

app/pages/download/[...slug].vue

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/pages/index.vue

Lines changed: 11 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { VideoPlayer } from '@videojs-player/vue'
33
import 'video.js/dist/video-js.css'
44
5-
const { data: page } = await useAsyncData('index', () => queryCollection('index').first())
5+
const { data: page } = await useAsyncData('page-index', () => queryCollection('index').first())
66
77
const title = page.value?.seo?.title || page.value?.title
88
const description = page.value?.seo?.description || page.value?.description
@@ -19,7 +19,7 @@ const { isMobile } = useDevice()
1919
2020
const videoReady = ref(false)
2121
22-
const projects = ref<ProjectItem[]>([])
22+
const projects = ref<ProjectExportItem[]>([])
2323
const contributors = ref<ContributorItem[]>([])
2424
2525
const loadingProjects = ref(true)
@@ -57,6 +57,8 @@ onMounted(async () => {
5757
5858
projects.value = projectData
5959
60+
console.log('Projects loaded:', projects.value)
61+
6062
await new Promise(resolve => setTimeout(resolve, 300))
6163
} catch (error) {
6264
console.error('Error loading projects:', error)
@@ -130,77 +132,13 @@ onMounted(async () => {
130132
container: 'pb-8 sm:pb-12 lg:pb-20'
131133
}"
132134
>
133-
<UPageGrid>
134-
<template v-if="loadingProjects">
135-
<USkeleton
136-
v-for="index in 6"
137-
:key="'project-' + index"
138-
class="h-[198px] rounded-xl"
139-
/>
140-
</template>
141-
142-
<template v-else>
143-
<UPageCard
144-
v-for="(project, index) in projects"
145-
:key="index"
146-
variant="ghost"
147-
:to="project.html_url"
148-
target="_blank"
149-
:ui="{
150-
footer: 'pt-4 mt-auto self-stretch'
151-
}"
152-
>
153-
<template #body>
154-
<UUser
155-
:name="useStyleName(project.name)"
156-
:description="project.description"
157-
:avatar="{ src: project.owner.avatar_url, alt: project.owner.login }"
158-
size="lg"
159-
class="relative"
160-
orientation="vertical"
161-
:ui="{
162-
description: 'text-xs pt-1'
163-
164-
}"
165-
/>
166-
</template>
167-
168-
<template #footer>
169-
<div class="flex items-center justify-between text-xs text-gray-500">
170-
<span
171-
v-if="project.updated_at"
172-
class="self-stretch"
173-
>
174-
{{ useStyleDate(project.updated_at) }}
175-
</span>
176-
177-
<div class="space-x-2 flex items-center">
178-
<span
179-
v-if="project.stargazers_count > 0"
180-
class="flex items-center"
181-
>
182-
<UIcon
183-
name="i-lucide-star"
184-
class="mr-1 size-3"
185-
/>
186-
{{ useStyleCount(project.stargazers_count) }}
187-
</span>
188-
<span
189-
v-if="project.forks_count > 0"
190-
class="flex items-center"
191-
>
192-
<UIcon
193-
name="i-lucide-git-fork"
194-
class="mr-1 size-3"
195-
/>
196-
{{ useStyleCount(project.forks_count) }}
197-
</span>
198-
</div>
199-
</div>
200-
</template>
201-
</UPageCard>
202-
</template>
203-
</UPageGrid>
135+
<ProjectsGitHubGrid
136+
:items="projects"
137+
:items-to-show="page.projects.itemsToShow"
138+
:spotlight="true"
139+
spotlight-class="[--spotlight-color:var(--ui-primary)] [--spotlight-size:360px]"
140+
:loading="loadingProjects"
141+
/>
204142
</UPageSection>
205143

206144
<UContainer

app/pages/projects.vue

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,59 @@
11
<script setup lang="ts">
2+
const { data: page } = await useAsyncData('page-projects', () => queryCollection('projects').first())
23
4+
const title = page.value?.seo?.title || page.value?.title
5+
const description = page.value?.seo?.description || page.value?.description
6+
7+
useSeoMeta({
8+
titleTemplate: '',
9+
title,
10+
ogTitle: title,
11+
description,
12+
ogDescription: description
13+
})
14+
15+
const projects = ref<ProjectExportItem[]>([])
16+
const loadingProjects = ref(true)
17+
18+
onMounted(async () => {
19+
try {
20+
const projectData = await useProjects({
21+
itemsToShow: page.value?.projects?.itemsToShow || 0,
22+
featured: page.value?.projects?.featured || [],
23+
sortBy: page.value?.projects?.sortBy || 'stars'
24+
})
25+
26+
projects.value = projectData
27+
28+
await new Promise(resolve => setTimeout(resolve, 300))
29+
} catch (error) {
30+
console.error('Error loading projects:', error)
31+
} finally {
32+
if (projects.value.length > 0) {
33+
loadingProjects.value = false
34+
} else {
35+
console.warn('No projects found.')
36+
}
37+
}
38+
})
339
</script>
440

541
<template>
6-
<div>
7-
<!-- -->
42+
<div v-if="page">
43+
<UPageSection
44+
v-if="page.projects"
45+
v-bind="page.projects"
46+
:ui="{
47+
container: 'pb-8 sm:pb-12 lg:pb-20'
48+
}"
49+
>
50+
<ProjectsGitHubGrid
51+
:items="projects"
52+
:items-to-show="page.projects.itemsToShow"
53+
:spotlight="true"
54+
spotlight-class="[--spotlight-color:var(--ui-primary)] [--spotlight-size:360px]"
55+
:loading="loadingProjects"
56+
/>
57+
</UPageSection>
858
</div>
959
</template>

content.config.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,36 @@ const collections = {
110110
docs: defineCollection({
111111
type: 'page',
112112
source: '1.docs/**/*'
113+
}),
114+
download: defineCollection({
115+
type: 'page',
116+
source: '2.download.yml',
117+
schema: z.object({
118+
download: createBaseSchema().extend({
119+
reverse: z.boolean().optional(),
120+
orientation: z.enum(orientationEnum).optional(),
121+
icon: z.string().optional()
122+
}).optional()
123+
})
124+
}),
125+
projects: defineCollection({
126+
type: 'page',
127+
source: '3.projects.yml',
128+
schema: z.object({
129+
projects: createBaseSchema().extend({
130+
reverse: z.boolean().optional(),
131+
orientation: z.enum(orientationEnum).optional(),
132+
icon: z.string().optional(),
133+
itemsToShow: z.number().optional(),
134+
sortBy: z.enum(['name', 'updated', 'stars', 'forks']).optional(),
135+
featured: z.array(z.string()).optional()
136+
}).optional()
137+
})
138+
}),
139+
blog: defineCollection({
140+
type: 'page',
141+
source: '4.blog/**/*',
142+
schema: z.object({})
113143
})
114144
}
115145

content/2.download.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
title:
2+
description:
3+
seo:
4+
title:
5+
description:
6+
navigation.icon: i-lucide-download
7+
8+
download:
9+
reverse: false
10+
orientation: vertical
11+
icon: i-lucide-folder-root
12+
title: Download
13+
description: Find the latest releases of our software and tools.
14+
features:
15+
- title: Applications
16+
description: Download our software packages.
17+
icon: i-lucide-package
18+
link: /download/application
19+
- title: Library
20+
description: Download our command-line tools.
21+
icon: i-lucide-terminal
22+
link: /download/library

0 commit comments

Comments
 (0)