Skip to content

Commit 52c8937

Browse files
0tuedonIgboPharaohEmmanuel-Develops
authored
Individual Transcript Page (#52)
* refactor setup algorithm * chore: remove slug from transcript card * feat: Individual transcript page render * feat: icons and tab functionality * feat: individual transcript page functionality * fix: markdown # headings * fix: spacing between link and design nit * feat: Individual transcript page render * feat: icons and tab functionality * feat: individual transcript page functionality * fix: markdown # headings * fix: h1,h2 check and code tag adjustment * chore(version): updated bitcoin-dev-project version * fix(refactor): code readbility --------- Co-authored-by: IgboPharaoh <[email protected]> Co-authored-by: Emmanuel Itakpe <[email protected]>
1 parent dc81aed commit 52c8937

26 files changed

+1949
-147
lines changed

contentlayer.config.ts

Lines changed: 114 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import path from "path";
22
import * as fs from "fs";
33
import { createSlug, SpeakerData, TopicsData, unsluggify } from "./src/utils";
4-
import { defineDocumentType, defineNestedType, makeSource } from "contentlayer2/source-files";
5-
import { Transcript as ContentTranscriptType, Source as ContentSourceType } from "./.contentlayer/generated/types";
4+
import {
5+
defineDocumentType,
6+
defineNestedType,
7+
makeSource,
8+
} from "contentlayer2/source-files";
9+
import {
10+
Transcript as ContentTranscriptType,
11+
Source as ContentSourceType,
12+
} from "./.contentlayer/generated/types";
13+
import { LanguageCodes } from "./src/config";
614

715
const Resources = defineNestedType(() => ({
816
name: "Resources",
@@ -94,7 +102,11 @@ function organizeTags(transcripts: ContentTranscriptType[]) {
94102
});
95103

96104
// Process all tags at once
97-
const allTags = new Set(transcripts.flatMap((transcript) => transcript.tags?.map((tag) => tag) || []));
105+
const allTags = new Set(
106+
transcripts.flatMap(
107+
(transcript) => transcript.tags?.map((tag) => tag) || []
108+
)
109+
);
98110

99111
allTags.forEach((tag) => {
100112
const catInfo = categoryMap.get(tag);
@@ -116,11 +128,13 @@ function organizeTags(transcripts: ContentTranscriptType[]) {
116128

117129
// Add "Miscellaneous" category with remaining uncategorized tags
118130
if (tagsWithoutCategory.size > 0) {
119-
tagsByCategory["Miscellaneous"] = Array.from(tagsWithoutCategory).map((tag) => ({
120-
name: tag,
121-
slug: tag,
122-
count: tagCounts[tag] || 0,
123-
}));
131+
tagsByCategory["Miscellaneous"] = Array.from(tagsWithoutCategory).map(
132+
(tag) => ({
133+
name: tag,
134+
slug: tag,
135+
count: tagCounts[tag] || 0,
136+
})
137+
);
124138
}
125139

126140
// Sort tags alphabetically within each category
@@ -190,7 +204,10 @@ function createSpeakers(transcripts: ContentTranscriptType[]) {
190204
fs.writeFileSync("./public/speaker-data.json", JSON.stringify(speakerArray));
191205
}
192206

193-
function generateSourcesCount(transcripts: ContentTranscriptType[], sources: ContentSourceType[]) {
207+
function generateSourcesCount(
208+
transcripts: ContentTranscriptType[],
209+
sources: ContentSourceType[]
210+
) {
194211
const sourcesArray: TagInfo[] = [];
195212
const slugSources: Record<string, number> = {};
196213

@@ -204,7 +221,10 @@ function generateSourcesCount(transcripts: ContentTranscriptType[], sources: Con
204221
slugSources[slug] = sourcesLength;
205222

206223
const getSourceName = (slug: string) =>
207-
sources.find((source) => source.language === "en" && source.slugAsParams[0] === slug)?.title ?? unsluggify(slug);
224+
sources.find(
225+
(source) =>
226+
source.language === "en" && source.slugAsParams[0] === slug
227+
)?.title ?? unsluggify(slug);
208228

209229
sourcesArray[sourcesLength] = {
210230
slug,
@@ -214,12 +234,21 @@ function generateSourcesCount(transcripts: ContentTranscriptType[], sources: Con
214234
}
215235
});
216236

217-
fs.writeFileSync("./public/source-count-data.json", JSON.stringify(sourcesArray));
237+
fs.writeFileSync(
238+
"./public/source-count-data.json",
239+
JSON.stringify(sourcesArray)
240+
);
218241
return { sourcesArray, slugSources };
219242
}
220243

221-
const createTypesCount = (transcripts: ContentTranscriptType[], sources: ContentSourceType[]) => {
222-
const { sourcesArray, slugSources } = generateSourcesCount(transcripts, sources);
244+
const createTypesCount = (
245+
transcripts: ContentTranscriptType[],
246+
sources: ContentSourceType[]
247+
) => {
248+
const { sourcesArray, slugSources } = generateSourcesCount(
249+
transcripts,
250+
sources
251+
);
223252
const nestedTypes: any = {};
224253

225254
sources.forEach((transcript) => {
@@ -234,7 +263,8 @@ const createTypesCount = (transcripts: ContentTranscriptType[], sources: Content
234263
if (!nestedTypes[slugType]) {
235264
nestedTypes[slugType] = [];
236265
} else {
237-
if (nestedTypes[slugType].includes(getSource) || getSource === null) return;
266+
if (nestedTypes[slugType].includes(getSource) || getSource === null)
267+
return;
238268
nestedTypes[slugType].push(getSource);
239269
}
240270
});
@@ -244,11 +274,27 @@ const createTypesCount = (transcripts: ContentTranscriptType[], sources: Content
244274
fs.writeFileSync("./public/types-data.json", JSON.stringify(nestedTypes));
245275
};
246276

247-
function organizeContent(transcripts: ContentTranscriptType[], sources: ContentSourceType[]) {
277+
function organizeContent(
278+
transcripts: ContentTranscriptType[],
279+
sources: ContentSourceType[]
280+
) {
248281
const tree: any = {};
249282

250283
sources.forEach((source) => {
251-
const { _id, slugAsParams, language, _raw, weight, body, hosts, transcription_coverage, url, type, types, ...metaData } = source;
284+
const {
285+
_id,
286+
slugAsParams,
287+
language,
288+
_raw,
289+
weight,
290+
body,
291+
hosts,
292+
transcription_coverage,
293+
url,
294+
type,
295+
types,
296+
...metaData
297+
} = source;
252298
const params = source.slugAsParams;
253299
const topParam = params[0] as string;
254300
const nestedSource = params.length > 1;
@@ -257,16 +303,21 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
257303
tree[topParam] = {};
258304
}
259305
const allTranscriptsForSourceLanguage = transcripts.filter(
260-
(transcript) => transcript._raw.sourceFileDir === source._raw.sourceFileDir && transcript.language === language
306+
(transcript) =>
307+
transcript._raw.sourceFileDir === source._raw.sourceFileDir &&
308+
transcript.language === language
261309
);
262310

263-
const allTranscriptsForSourceLanguageURLs = allTranscriptsForSourceLanguage.map((transcript) => transcript.url);
311+
const allTranscriptsForSourceLanguageURLs =
312+
allTranscriptsForSourceLanguage.map((transcript) => transcript.url);
264313

265314
if (!nestedSource) {
266315
tree[topParam] = {
267316
...tree[topParam],
268317
[language]: {
269-
data: allTranscriptsForSourceLanguageURLs.length ? allTranscriptsForSourceLanguageURLs : {},
318+
data: allTranscriptsForSourceLanguageURLs.length
319+
? allTranscriptsForSourceLanguageURLs
320+
: {},
270321
metadata: {
271322
...metaData,
272323
},
@@ -276,7 +327,9 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
276327
tree[topParam][language].data = {
277328
...tree[topParam][language].data,
278329
[params[1]]: {
279-
data: allTranscriptsForSourceLanguageURLs.length ? allTranscriptsForSourceLanguageURLs : {},
330+
data: allTranscriptsForSourceLanguageURLs.length
331+
? allTranscriptsForSourceLanguageURLs
332+
: {},
280333
metadata: {
281334
...metaData,
282335
},
@@ -288,6 +341,8 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
288341
fs.writeFileSync("./public/sources-data.json", JSON.stringify(tree, null, 2));
289342
}
290343

344+
const getLanCode = /[.]\w{2}$/gi // Removes the last two characters if there's a dot
345+
291346
export const Transcript = defineDocumentType(() => ({
292347
name: "Transcript",
293348
filePathPattern: `**/*.md`,
@@ -322,16 +377,45 @@ export const Transcript = defineDocumentType(() => ({
322377
type: "string",
323378
resolve: (doc) => `/${doc._raw.flattenedPath}`,
324379
},
325-
slugAsParams: {
326-
type: "list",
327-
resolve: (doc) => doc._raw.flattenedPath.split("/"),
328-
},
329380
language: {
330381
type: "string",
331382
resolve: (doc) => {
332383
const transcript = doc._raw.flattenedPath.split("/").pop();
333-
const lan = transcript?.split(".").length === 2 ? transcript?.split(".")[1] : "en";
334-
return lan;
384+
const lan = transcript?.match(getLanCode);
385+
const languageCode = (lan?.[lan.length - 1] || "").replace(".", "");
386+
const finalLanguage = LanguageCodes.includes(languageCode)
387+
? languageCode
388+
: "en";
389+
return finalLanguage;
390+
},
391+
},
392+
languageURL: {
393+
type: "string",
394+
resolve: (doc) => {
395+
const transcript = doc._raw.flattenedPath.split("/").pop();
396+
const fullPathWithoutDot = doc._raw.flattenedPath.replace(
397+
getLanCode,
398+
""
399+
);
400+
401+
const lan = transcript?.match(getLanCode);
402+
const languageCode = (lan?.[0] || "").replace(".", "")
403+
404+
if (LanguageCodes.includes(languageCode)) {
405+
return `/${languageCode}/${fullPathWithoutDot}`;
406+
}
407+
408+
return `/${fullPathWithoutDot}`;
409+
},
410+
},
411+
slugAsParams: {
412+
type: "list",
413+
resolve: (doc) => {
414+
const pathWithoutDot = doc._raw.flattenedPath.replace(
415+
getLanCode,
416+
""
417+
);
418+
return pathWithoutDot.split("/");
335419
},
336420
},
337421
},
@@ -354,13 +438,15 @@ export const Source = defineDocumentType(() => ({
354438
computedFields: {
355439
url: {
356440
type: "string",
357-
resolve: (doc) => `/${doc._raw.flattenedPath.split("/").slice(0, -1).join("/")}`,
441+
resolve: (doc) =>
442+
`/${doc._raw.flattenedPath.split("/").slice(0, -1).join("/")}`,
358443
},
359444
language: {
360445
type: "string",
361446
resolve: (doc) => {
362447
const index = doc._raw.flattenedPath.split("/").pop();
363-
const lan = index?.split(".").length === 2 ? index?.split(".")[1] : "en";
448+
const lan =
449+
index?.split(".").length === 2 ? index?.split(".")[1] : "en";
364450
return lan;
365451
},
366452
},

next.config.mjs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,36 @@ const nextConfig = {
55
return {
66
fallback: [
77
{
8-
source: "/:path*.:ext([^/]+)", // intercept all paths ending with a file extension
9-
destination: "/gh-pages/:path*.:ext", // rewrite to gh-pages/[path_here].ext
8+
source: "/:path*.:ext([a-zA-Z0-9_+]{1,4})", // Match extensions that are 1-4 AlphaNumeric characters long
9+
destination: "/gh-pages/:path*.:ext", // Rewrite to gh-pages/[path_here].ext
1010
},
1111
{
12-
source: "/transcripts",
13-
destination: "/gh-pages/index.html",
12+
source: "/tags/:path",
13+
destination: "/gh-pages/tags/:path/index.html",
1414
},
1515
{
16-
source: "/types",
17-
destination: "/gh-pages/categories/index.html",
16+
source: "/speakers/:path",
17+
destination: "/gh-pages/speakers/:path/index.html",
1818
},
1919
{
20-
source: "/:path*",
21-
destination: "/gh-pages/:path*/index.html",
20+
source: "/es",
21+
destination: "/gh-pages/es/index.html",
22+
},
23+
{
24+
source: "/zh",
25+
destination: "/gh-pages/zh/index.html",
26+
},
27+
{
28+
source: "/pt",
29+
destination: "/gh-pages/pt/index.html",
30+
},
31+
{
32+
source: "/:path((?!.*\\.[a-zA-Z0-9]{1,4}$).*)", // Matches paths without a valid file extension
33+
destination: "/transcript/:path*", // Rewrite to /transcripts/[path...]
2234
},
2335
{
24-
source: "/sources/:path((?!.*\\.[^/]+).*)", // Matches /source/[any path without a file extension]
25-
destination: "/[...slug]/:path*", // Replace with your catch-all route
36+
source: "/:path*",
37+
destination: "/gh-pages/:path*/index.html",
2638
},
2739
],
2840
};

0 commit comments

Comments
 (0)