1
+ <!-- eslint-disable @typescript-eslint/indent -->
1
2
<script setup lang="ts">
2
3
import ' @/assets/css/linked.sass'
3
4
import ' @/assets/css/slide-enter.sass'
4
5
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'
6
8
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
+ */
8
25
9
26
const postsLatestQuery = useLazyAsyncData (
10
27
' posts-latest-data-4' ,
@@ -37,7 +54,87 @@ const postsCreatedQuery = useLazyAsyncData(
37
54
const postsCreatedIntoPostData = computed (() => postsCreatedQuery .data .value ?.map (intoPostData ) ?? [])
38
55
39
56
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 )
41
138
42
139
useSeoMetaHelper ({
43
140
title: ' Blog' ,
@@ -47,38 +144,86 @@ useSeoMetaHelper({
47
144
48
145
<template >
49
146
<div
50
- m-a flex flex-row justify-center
147
+ m-a flex flex-col justify-center gap-8
51
148
lt-md:w-90vw md:w-80ch
52
149
>
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
56
187
>
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
64
191
>
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
77
203
</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 >
82
227
</div >
83
228
</template >
84
229
0 commit comments