Skip to content

Commit ead96e7

Browse files
committed
Added: Project support
1 parent f62bee8 commit ead96e7

File tree

5 files changed

+526
-30
lines changed

5 files changed

+526
-30
lines changed

components/Header.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ useNuxtApp().$headerHeight = headerHeight
3232
<span lt-md:hidden>Blog</span>
3333
<div i-carbon:blog md:hidden title="Blog" />
3434
</NuxtLink>
35+
<NuxtLink class="linked" to="/projects">
36+
<span lt-md:hidden>Projects</span>
37+
<div i-carbon:ibm-cloud-projects md:hidden title="Projects" />
38+
</NuxtLink>
3539
<NuxtLink lt-md:hidden class="linked" to="/posts">
3640
Posts
3741
</NuxtLink>

pages/blog.vue

Lines changed: 175 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
1+
<!-- eslint-disable @typescript-eslint/indent -->
12
<script setup lang="ts">
23
import '@/assets/css/linked.sass'
34
import '@/assets/css/slide-enter.sass'
45
5-
import { POST_MODEL_FIELDS, intoPostModelAsserted } from '~/code/models/post'
6+
import { POST_MODEL_FIELDS, type PostModel, intoPostModelAsserted } from '~/code/models/post'
7+
import { PROJECT_MODEL_FIELDS, type ProjectModel, intoProjectModelAsserted } from '~/code/models/projects'
68
7-
const intoPostData = (raw: Record<string, string>) => ({ route: raw._path, model: intoPostModelAsserted(raw) })
9+
interface PostData {
10+
route: string
11+
model: PostModel
12+
}
13+
14+
interface ProjectData {
15+
route: string
16+
model: ProjectModel
17+
}
18+
19+
const intoPostData = (raw: Record<string, string>): PostData => ({ route: raw._path, model: intoPostModelAsserted(raw) })
20+
const intoProjectData = (raw: Record<string, string>): ProjectData => ({ route: raw._path, model: intoProjectModelAsserted(raw) })
21+
22+
/**
23+
* POSTS QUERIES AND PARSING
24+
*/
825
926
const postsLatestQuery = useLazyAsyncData(
1027
'posts-latest-data-4',
@@ -37,7 +54,87 @@ const postsCreatedQuery = useLazyAsyncData(
3754
const postsCreatedIntoPostData = computed(() => postsCreatedQuery.data.value?.map(intoPostData) ?? [])
3855
3956
const postsPending = computed(() =>
40-
postsCreatedQuery.pending.value || postsLatestQuery.pending.value)
57+
[postsCreatedQuery.status.value, postsLatestQuery.status.value].includes('pending'))
58+
59+
/**
60+
* PROJECTS QUERIES AND PARSING
61+
*/
62+
63+
const projectsPostsLatestQuery = useLazyAsyncData(
64+
'projects-posts-latest-data',
65+
() => queryContent('projects')
66+
// Selects only two kinds of paths:
67+
// /posts/**
68+
// /posts/**/index
69+
.where({ _path: /^(?:\/[^\/]+){3}$/ })
70+
.only(['_path', ...POST_MODEL_FIELDS])
71+
.sort({ modified: -1 })
72+
.find(),
73+
)
74+
75+
const projectsPostsCreatedQuery = useLazyAsyncData(
76+
'projects-posts-created-data',
77+
() => queryContent('projects')
78+
// Selects only two kinds of paths:
79+
// /posts/**
80+
// /posts/**/index
81+
.where({ _path: /^(?:\/[^\/]+){3}$/ })
82+
.only(['_path', ...POST_MODEL_FIELDS])
83+
.sort({ created: -1 })
84+
.find(),
85+
)
86+
87+
const projectsAllQuery = useLazyAsyncData(
88+
'projects-all-data',
89+
() => queryContent('projects')
90+
// Selects only two kinds of paths:
91+
// /posts/**
92+
// /posts/**/index
93+
.where({ _path: /^(?:\/[^\/]+){2}$/ })
94+
.only(['_path', ...PROJECT_MODEL_FIELDS])
95+
.sort({ created: -1 })
96+
.find(),
97+
)
98+
99+
const projectsSortedData = (projectsAll: ProjectData[], postAll: PostData[], selector: (post: PostData) => Date) => {
100+
const projectsLatestByPost = []
101+
for (const project of projectsAll) {
102+
let latestModifiedPost
103+
let latestModifiedPostDate = new Date(0)
104+
105+
for (const post of postAll.filter(({ route }) => route.startsWith(`${project.route}/`))) {
106+
const postModifiedPostDate = selector(post)
107+
if (latestModifiedPostDate > postModifiedPostDate)
108+
break
109+
110+
latestModifiedPostDate = postModifiedPostDate
111+
latestModifiedPost = post
112+
}
113+
114+
projectsLatestByPost.push([project, latestModifiedPost])
115+
}
116+
117+
const projectsLatestByPostChecked = projectsLatestByPost.filter(([_, post]) => post !== undefined) as [ProjectData, PostData][]
118+
return projectsLatestByPostChecked.sort(([_left, leftPost], [_right, rightPost]) => +selector(rightPost) - +selector(leftPost)).slice(0, 2)
119+
}
120+
121+
const projectsLatestData = computed(() => {
122+
const projectsPostsLatest = projectsPostsLatestQuery.data.value?.map(intoPostData) ?? []
123+
const projectsAll = projectsAllQuery.data.value?.map(intoProjectData) ?? []
124+
125+
return projectsSortedData(projectsAll, projectsPostsLatest, post => new Date(post.model.modified))
126+
})
127+
128+
const projectsCreatedData = computed(() => {
129+
const projectsPostsLatest = projectsPostsCreatedQuery.data.value?.map(intoPostData) ?? []
130+
const projectsAll = projectsAllQuery.data.value?.map(intoProjectData) ?? []
131+
132+
return projectsSortedData(projectsAll, projectsPostsLatest, post => new Date(post.model.created))
133+
})
134+
135+
const projectsPending = computed(() =>
136+
projectsLatestData.value.length === 0
137+
|| projectsCreatedData.value.length === 0)
41138
42139
useSeoMetaHelper({
43140
title: 'Blog',
@@ -47,38 +144,86 @@ useSeoMetaHelper({
47144

48145
<template>
49146
<div
50-
m-a flex flex-row justify-center
147+
m-a flex flex-col justify-center gap-8
51148
lt-md:w-90vw md:w-80ch
52149
>
53-
<section
54-
:class="postsPending ? 'invisible' : 'slide-enter'"
55-
flex flex-col
150+
<div
151+
flex flex-row justify-center
152+
lt-md:w-90vw md:w-80ch
153+
>
154+
<section
155+
:class="postsPending ? 'invisible' : 'slide-enter'"
156+
flex flex-col
157+
>
158+
<TierList
159+
:default-option="0"
160+
:available-options="['Latest', 'Created']"
161+
:available-groups="[
162+
postsLatestIntoPostData,
163+
postsCreatedIntoPostData,
164+
]"
165+
>
166+
<template #title>
167+
<NuxtLink text-2xl class="linked" to="/posts">
168+
Posts
169+
</NuxtLink>
170+
</template>
171+
<template #item="{ route, model }">
172+
<div
173+
class="linked"
174+
p-2 border="~ solid rounded gray-200 dark:gray-700"
175+
>
176+
<NuxtLink :to="route">
177+
<PostCard v-bind="model" />
178+
</NuxtLink>
179+
</div>
180+
</template>
181+
</TierList>
182+
</section>
183+
</div>
184+
<div
185+
flex flex-row justify-center
186+
lt-md:w-90vw md:w-80ch
56187
>
57-
<TierList
58-
:default-option="0"
59-
:available-options="['Latest', 'Created']"
60-
:available-groups="[
61-
postsLatestIntoPostData,
62-
postsCreatedIntoPostData,
63-
]"
188+
<section
189+
:class="projectsPending ? 'invisible' : 'slide-enter'"
190+
flex flex-col
64191
>
65-
<template #title>
66-
<NuxtLink text-2xl class="linked" to="/posts">
67-
Posts
68-
</NuxtLink>
69-
</template>
70-
<template #item="{ route, model }">
71-
<div
72-
class="linked"
73-
p-2 border="~ solid rounded gray-200 dark:gray-700"
74-
>
75-
<NuxtLink :to="route">
76-
<PostCard v-bind="model" />
192+
<TierList
193+
:default-option="0"
194+
:available-options="['Latest', 'Created']"
195+
:available-groups="[
196+
projectsLatestData,
197+
projectsCreatedData,
198+
]"
199+
>
200+
<template #title>
201+
<NuxtLink text-2xl class="linked" to="/projects">
202+
Projects
77203
</NuxtLink>
78-
</div>
79-
</template>
80-
</TierList>
81-
</section>
204+
</template>
205+
<template #item="pair">
206+
<div
207+
class="linked"
208+
p-2 border="~ solid rounded gray-200 dark:gray-700"
209+
>
210+
<ProjectCard :project="pair[0].model" :route="pair[0].route">
211+
<template #item>
212+
<div
213+
class="linked"
214+
p-2 border="~ solid rounded gray-200 dark:gray-700"
215+
>
216+
<NuxtLink :to="pair[1].route">
217+
<PostCard v-bind="pair[1].model" />
218+
</NuxtLink>
219+
</div>
220+
</template>
221+
</ProjectCard>
222+
</div>
223+
</template>
224+
</TierList>
225+
</section>
226+
</div>
82227
</div>
83228
</template>
84229

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup lang="ts">
2+
import MarkdownReader from '~/components/MarkdownReader.vue'
3+
</script>
4+
5+
<template>
6+
<MarkdownReader />
7+
</template>

0 commit comments

Comments
 (0)