Skip to content

Commit

Permalink
Individual Transcript Page (#52)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people committed Nov 29, 2024
1 parent b400651 commit 6bbe171
Show file tree
Hide file tree
Showing 26 changed files with 1,949 additions and 147 deletions.
142 changes: 114 additions & 28 deletions contentlayer.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import path from "path";
import * as fs from "fs";
import { createSlug, SpeakerData, TopicsData, unsluggify } from "./src/utils";
import { defineDocumentType, defineNestedType, makeSource } from "contentlayer2/source-files";
import { Transcript as ContentTranscriptType, Source as ContentSourceType } from "./.contentlayer/generated/types";
import {
defineDocumentType,
defineNestedType,
makeSource,
} from "contentlayer2/source-files";
import {
Transcript as ContentTranscriptType,
Source as ContentSourceType,
} from "./.contentlayer/generated/types";
import { LanguageCodes } from "./src/config";

const Resources = defineNestedType(() => ({
name: "Resources",
Expand Down Expand Up @@ -94,7 +102,11 @@ function organizeTags(transcripts: ContentTranscriptType[]) {
});

// Process all tags at once
const allTags = new Set(transcripts.flatMap((transcript) => transcript.tags?.map((tag) => tag) || []));
const allTags = new Set(
transcripts.flatMap(
(transcript) => transcript.tags?.map((tag) => tag) || []
)
);

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

// Add "Miscellaneous" category with remaining uncategorized tags
if (tagsWithoutCategory.size > 0) {
tagsByCategory["Miscellaneous"] = Array.from(tagsWithoutCategory).map((tag) => ({
name: tag,
slug: tag,
count: tagCounts[tag] || 0,
}));
tagsByCategory["Miscellaneous"] = Array.from(tagsWithoutCategory).map(
(tag) => ({
name: tag,
slug: tag,
count: tagCounts[tag] || 0,
})
);
}

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

function generateSourcesCount(transcripts: ContentTranscriptType[], sources: ContentSourceType[]) {
function generateSourcesCount(
transcripts: ContentTranscriptType[],
sources: ContentSourceType[]
) {
const sourcesArray: TagInfo[] = [];
const slugSources: Record<string, number> = {};

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

const getSourceName = (slug: string) =>
sources.find((source) => source.language === "en" && source.slugAsParams[0] === slug)?.title ?? unsluggify(slug);
sources.find(
(source) =>
source.language === "en" && source.slugAsParams[0] === slug
)?.title ?? unsluggify(slug);

sourcesArray[sourcesLength] = {
slug,
Expand All @@ -214,12 +234,21 @@ function generateSourcesCount(transcripts: ContentTranscriptType[], sources: Con
}
});

fs.writeFileSync("./public/source-count-data.json", JSON.stringify(sourcesArray));
fs.writeFileSync(
"./public/source-count-data.json",
JSON.stringify(sourcesArray)
);
return { sourcesArray, slugSources };
}

const createTypesCount = (transcripts: ContentTranscriptType[], sources: ContentSourceType[]) => {
const { sourcesArray, slugSources } = generateSourcesCount(transcripts, sources);
const createTypesCount = (
transcripts: ContentTranscriptType[],
sources: ContentSourceType[]
) => {
const { sourcesArray, slugSources } = generateSourcesCount(
transcripts,
sources
);
const nestedTypes: any = {};

sources.forEach((transcript) => {
Expand All @@ -234,7 +263,8 @@ const createTypesCount = (transcripts: ContentTranscriptType[], sources: Content
if (!nestedTypes[slugType]) {
nestedTypes[slugType] = [];
} else {
if (nestedTypes[slugType].includes(getSource) || getSource === null) return;
if (nestedTypes[slugType].includes(getSource) || getSource === null)
return;
nestedTypes[slugType].push(getSource);
}
});
Expand All @@ -244,11 +274,27 @@ const createTypesCount = (transcripts: ContentTranscriptType[], sources: Content
fs.writeFileSync("./public/types-data.json", JSON.stringify(nestedTypes));
};

function organizeContent(transcripts: ContentTranscriptType[], sources: ContentSourceType[]) {
function organizeContent(
transcripts: ContentTranscriptType[],
sources: ContentSourceType[]
) {
const tree: any = {};

sources.forEach((source) => {
const { _id, slugAsParams, language, _raw, weight, body, hosts, transcription_coverage, url, type, types, ...metaData } = source;
const {
_id,
slugAsParams,
language,
_raw,
weight,
body,
hosts,
transcription_coverage,
url,
type,
types,
...metaData
} = source;
const params = source.slugAsParams;
const topParam = params[0] as string;
const nestedSource = params.length > 1;
Expand All @@ -257,16 +303,21 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
tree[topParam] = {};
}
const allTranscriptsForSourceLanguage = transcripts.filter(
(transcript) => transcript._raw.sourceFileDir === source._raw.sourceFileDir && transcript.language === language
(transcript) =>
transcript._raw.sourceFileDir === source._raw.sourceFileDir &&
transcript.language === language
);

const allTranscriptsForSourceLanguageURLs = allTranscriptsForSourceLanguage.map((transcript) => transcript.url);
const allTranscriptsForSourceLanguageURLs =
allTranscriptsForSourceLanguage.map((transcript) => transcript.url);

if (!nestedSource) {
tree[topParam] = {
...tree[topParam],
[language]: {
data: allTranscriptsForSourceLanguageURLs.length ? allTranscriptsForSourceLanguageURLs : {},
data: allTranscriptsForSourceLanguageURLs.length
? allTranscriptsForSourceLanguageURLs
: {},
metadata: {
...metaData,
},
Expand All @@ -276,7 +327,9 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
tree[topParam][language].data = {
...tree[topParam][language].data,
[params[1]]: {
data: allTranscriptsForSourceLanguageURLs.length ? allTranscriptsForSourceLanguageURLs : {},
data: allTranscriptsForSourceLanguageURLs.length
? allTranscriptsForSourceLanguageURLs
: {},
metadata: {
...metaData,
},
Expand All @@ -288,6 +341,8 @@ function organizeContent(transcripts: ContentTranscriptType[], sources: ContentS
fs.writeFileSync("./public/sources-data.json", JSON.stringify(tree, null, 2));
}

const getLanCode = /[.]\w{2}$/gi // Removes the last two characters if there's a dot

export const Transcript = defineDocumentType(() => ({
name: "Transcript",
filePathPattern: `**/*.md`,
Expand Down Expand Up @@ -322,16 +377,45 @@ export const Transcript = defineDocumentType(() => ({
type: "string",
resolve: (doc) => `/${doc._raw.flattenedPath}`,
},
slugAsParams: {
type: "list",
resolve: (doc) => doc._raw.flattenedPath.split("/"),
},
language: {
type: "string",
resolve: (doc) => {
const transcript = doc._raw.flattenedPath.split("/").pop();
const lan = transcript?.split(".").length === 2 ? transcript?.split(".")[1] : "en";
return lan;
const lan = transcript?.match(getLanCode);
const languageCode = (lan?.[lan.length - 1] || "").replace(".", "");
const finalLanguage = LanguageCodes.includes(languageCode)
? languageCode
: "en";
return finalLanguage;
},
},
languageURL: {
type: "string",
resolve: (doc) => {
const transcript = doc._raw.flattenedPath.split("/").pop();
const fullPathWithoutDot = doc._raw.flattenedPath.replace(
getLanCode,
""
);

const lan = transcript?.match(getLanCode);
const languageCode = (lan?.[0] || "").replace(".", "")

if (LanguageCodes.includes(languageCode)) {
return `/${languageCode}/${fullPathWithoutDot}`;
}

return `/${fullPathWithoutDot}`;
},
},
slugAsParams: {
type: "list",
resolve: (doc) => {
const pathWithoutDot = doc._raw.flattenedPath.replace(
getLanCode,
""
);
return pathWithoutDot.split("/");
},
},
},
Expand All @@ -354,13 +438,15 @@ export const Source = defineDocumentType(() => ({
computedFields: {
url: {
type: "string",
resolve: (doc) => `/${doc._raw.flattenedPath.split("/").slice(0, -1).join("/")}`,
resolve: (doc) =>
`/${doc._raw.flattenedPath.split("/").slice(0, -1).join("/")}`,
},
language: {
type: "string",
resolve: (doc) => {
const index = doc._raw.flattenedPath.split("/").pop();
const lan = index?.split(".").length === 2 ? index?.split(".")[1] : "en";
const lan =
index?.split(".").length === 2 ? index?.split(".")[1] : "en";
return lan;
},
},
Expand Down
32 changes: 22 additions & 10 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,36 @@ const nextConfig = {
return {
fallback: [
{
source: "/:path*.:ext([^/]+)", // intercept all paths ending with a file extension
destination: "/gh-pages/:path*.:ext", // rewrite to gh-pages/[path_here].ext
source: "/:path*.:ext([a-zA-Z0-9_+]{1,4})", // Match extensions that are 1-4 AlphaNumeric characters long
destination: "/gh-pages/:path*.:ext", // Rewrite to gh-pages/[path_here].ext
},
{
source: "/transcripts",
destination: "/gh-pages/index.html",
source: "/tags/:path",
destination: "/gh-pages/tags/:path/index.html",
},
{
source: "/types",
destination: "/gh-pages/categories/index.html",
source: "/speakers/:path",
destination: "/gh-pages/speakers/:path/index.html",
},
{
source: "/:path*",
destination: "/gh-pages/:path*/index.html",
source: "/es",
destination: "/gh-pages/es/index.html",
},
{
source: "/zh",
destination: "/gh-pages/zh/index.html",
},
{
source: "/pt",
destination: "/gh-pages/pt/index.html",
},
{
source: "/:path((?!.*\\.[a-zA-Z0-9]{1,4}$).*)", // Matches paths without a valid file extension
destination: "/transcript/:path*", // Rewrite to /transcripts/[path...]
},
{
source: "/sources/:path((?!.*\\.[^/]+).*)", // Matches /source/[any path without a file extension]
destination: "/[...slug]/:path*", // Replace with your catch-all route
source: "/:path*",
destination: "/gh-pages/:path*/index.html",
},
],
};
Expand Down
Loading

0 comments on commit 6bbe171

Please sign in to comment.