Skip to content

Commit 358e47a

Browse files
0tuedonEmmanuel-Develops
authored andcommitted
fix: Transcript Page feedback (#70)
* fix: issues with nested list showing dark gray * fix(tagsDetailed): added a new compute field to have name and slug
1 parent e3b5b4f commit 358e47a

File tree

10 files changed

+110
-76
lines changed

10 files changed

+110
-76
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
/public/topics-by-category-counts.json
2525
/public/aliases.json
2626
/public/topics-counts.json
27+
/public/topics.json
2728
/public/speaker-data.json
2829
/public/source-count-data.json
2930
/public/sources-data.json

contentlayer.config.ts

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import path from "path";
22
import * as fs from "fs";
3-
import { createSlug, SpeakerData, TopicsData, unsluggify } from "./src/utils";
3+
import {
4+
ContentData,
5+
createSlug,
6+
SpeakerData,
7+
TopicsData,
8+
unsluggify,
9+
} from "./src/utils";
410
import {
511
defineDocumentType,
612
defineNestedType,
@@ -30,10 +36,10 @@ export interface Topic {
3036

3137
// The full processed topic we use internally
3238
interface ProcessedTopic {
33-
name: string; // Display name (from topic.title or original tag)
34-
slug: string; // Slugified identifier
35-
count: number; // Number of occurrences
36-
categories: string[]; // List of categories it belongs to
39+
name: string; // Display name (from topic.title or original tag)
40+
slug: string; // Slugified identifier
41+
count: number; // Number of occurrences
42+
categories: string[]; // List of categories it belongs to
3743
}
3844

3945
interface TagInfo {
@@ -46,7 +52,6 @@ interface ContentTree {
4652
[key: string]: ContentTree | ContentTranscriptType[];
4753
}
4854

49-
5055
const getTranscriptAliases = (allTranscripts: ContentTranscriptType[]) => {
5156
const aliases: Record<string, string> = {};
5257

@@ -69,20 +74,24 @@ const getTopics = () => {
6974
return JSON.parse(fileContents);
7075
};
7176

72-
function buildTopicsMap(transcripts: ContentTranscriptType[], topics: Topic[]): Map<string, ProcessedTopic> {
77+
78+
function buildTopicsMap(
79+
transcripts: ContentTranscriptType[],
80+
topics: Topic[]
81+
): Map<string, ProcessedTopic> {
7382
// Create topics lookup map (includes aliases)
7483
const topicsLookup = new Map<string, Topic>();
75-
topics.forEach(topic => {
84+
topics.forEach((topic) => {
7685
topicsLookup.set(topic.slug, topic);
77-
topic.aliases?.forEach(alias => topicsLookup.set(alias, topic));
86+
topic.aliases?.forEach((alias) => topicsLookup.set(alias, topic));
7887
});
7988

8089
// Build the main topics map
8190
const processedTopics = new Map<string, ProcessedTopic>();
8291

8392
// Process all transcripts
84-
transcripts.forEach(transcript => {
85-
transcript.tags?.forEach(tag => {
93+
transcripts.forEach((transcript) => {
94+
transcript.tags?.forEach((tag) => {
8695
const slug = createSlug(tag);
8796
const topic = topicsLookup.get(slug);
8897

@@ -99,11 +108,12 @@ function buildTopicsMap(transcripts: ContentTranscriptType[], topics: Topic[]):
99108
}
100109
});
101110
});
102-
103111
return processedTopics;
104112
}
105113

106-
function generateAlphabeticalList(processedTopics: Map<string, ProcessedTopic>): TopicsData[] {
114+
function generateAlphabeticalList(
115+
processedTopics: Map<string, ProcessedTopic>
116+
): TopicsData[] {
107117
const result: TopicsData[] = [];
108118
// The categories property is not needed for this list, so we drop it
109119
for (const { name, slug, count } of processedTopics.values()) {
@@ -112,30 +122,35 @@ function generateAlphabeticalList(processedTopics: Map<string, ProcessedTopic>):
112122
return result.sort((a, b) => a.name.localeCompare(b.name));
113123
}
114124

115-
function generateCategorizedList(processedTopics: Map<string, ProcessedTopic>): Record<string, TopicsData[]> {
125+
function generateCategorizedList(
126+
processedTopics: Map<string, ProcessedTopic>
127+
): Record<string, TopicsData[]> {
116128
const categorizedTopics: Record<string, TopicsData[]> = {};
117129

118-
Array.from(processedTopics.values()).forEach(({ name, slug, count, categories }) => {
119-
categories.forEach(category => {
120-
if (!categorizedTopics[category]) {
121-
categorizedTopics[category] = [];
122-
}
123-
124-
// Check if topic name contains category name and ends with "(Miscellaneous)"
125-
const modifiedName = name.includes(category) && name.endsWith("(Miscellaneous)")
126-
? "Miscellaneous"
127-
: name;
128-
129-
categorizedTopics[category].push({ name: modifiedName, slug, count });
130-
});
131-
});
130+
Array.from(processedTopics.values()).forEach(
131+
({ name, slug, count, categories }) => {
132+
categories.forEach((category) => {
133+
if (!categorizedTopics[category]) {
134+
categorizedTopics[category] = [];
135+
}
136+
137+
// Check if topic name contains category name and ends with "(Miscellaneous)"
138+
const modifiedName =
139+
name.includes(category) && name.endsWith("(Miscellaneous)")
140+
? "Miscellaneous"
141+
: name;
142+
143+
categorizedTopics[category].push({ name: modifiedName, slug, count });
144+
});
145+
}
146+
);
132147

133148
// Sort topics within each category
134-
Object.values(categorizedTopics).forEach(topics => {
149+
Object.values(categorizedTopics).forEach((topics) => {
135150
topics.sort((a, b) => {
136151
if (a.name == "Miscellaneous") return 1;
137152
if (b.name == "Miscellaneous") return -1;
138-
return a.name.localeCompare(b.name)
153+
return a.name.localeCompare(b.name);
139154
});
140155
});
141156

@@ -331,7 +346,7 @@ function organizeContent(
331346
fs.writeFileSync("./public/sources-data.json", JSON.stringify(tree, null, 2));
332347
}
333348

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

336351
export const Transcript = defineDocumentType(() => ({
337352
name: "Transcript",
@@ -363,6 +378,32 @@ export const Transcript = defineDocumentType(() => ({
363378
source_file: { type: "string" },
364379
},
365380
computedFields: {
381+
tagsDetailed: {
382+
type: "list",
383+
resolve: (doc) => {
384+
// doc?.tags doesn't give an array in contentLayer so we do _array to get it
385+
const topicsStore = doc?.tags as any || [];
386+
const topics = (topicsStore?._array as string[]) ?? [];
387+
388+
const topicsWithTitles = topics.map((topic) => {
389+
const currentTopic = getTopics().find(
390+
(topicData: ContentData) => topicData.slug === topic
391+
);
392+
393+
if(currentTopic?.title && currentTopic?.title.includes("(Miscellaneous)")) {
394+
return {
395+
name: currentTopic?.title.replace("(Miscellaneous)",""),
396+
slug: currentTopic.slug,
397+
}
398+
}
399+
return {
400+
name: currentTopic?.title || topic,
401+
slug: currentTopic?.slug || topic,
402+
};
403+
});
404+
return topicsWithTitles;
405+
},
406+
},
366407
url: {
367408
type: "string",
368409
resolve: (doc) => `/${doc._raw.flattenedPath}`,
@@ -389,7 +430,7 @@ export const Transcript = defineDocumentType(() => ({
389430
);
390431

391432
const lan = transcript?.match(getLanCode);
392-
const languageCode = (lan?.[0] || "").replace(".", "")
433+
const languageCode = (lan?.[0] || "").replace(".", "");
393434

394435
if (LanguageCodes.includes(languageCode)) {
395436
return `/${languageCode}/${fullPathWithoutDot}`;
@@ -401,10 +442,7 @@ export const Transcript = defineDocumentType(() => ({
401442
slugAsParams: {
402443
type: "list",
403444
resolve: (doc) => {
404-
const pathWithoutDot = doc._raw.flattenedPath.replace(
405-
getLanCode,
406-
""
407-
);
445+
const pathWithoutDot = doc._raw.flattenedPath.replace(getLanCode, "");
408446
return pathWithoutDot.split("/");
409447
},
410448
},

src/components/common/TranscriptDetailsCard.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import Image from "next/image";
44
import { ContentTreeArray } from "@/utils/data";
55
import DateIcon from "/public/svgs/date-icon.svg";
66
import TagsIcon from "/public/svgs/tags-icon.svg";
7-
import { createSlug, formatDate, unsluggify } from "@/utils";
7+
import { ContentData, createSlug, formatDate, unsluggify } from "@/utils";
88
import { MicIcon } from "@bitcoin-dev-project/bdp-ui/icons";
99
import Pill from "./Pill";
1010

11-
const TranscriptDetailsCard = ({ data, slug }: { data: ContentTreeArray; slug: string[] }) => {
12-
const { speakers, tags, summary, date, title, body, languageURL } = data;
13-
14-
const calculateRemaining = (data: string[]) => (data?.length && data.length > 3 ? data.length - 3 : 0);
11+
const TranscriptDetailsCard = ({ data }: { data: ContentTreeArray; slug: string[] }) => {
12+
const { speakers, tagsDetailed, summary, date, title, body, languageURL } = data;
13+
const calculateRemaining = (data: ContentData[] | string[]) => (data?.length && data.length > 3 ? data.length - 3 : 0);
1514

1615
return (
1716
<div className='border border-gray-custom-1200 rounded-lg p-4 md:p-5 2xl:p-6 flex flex-col gap-3 md:gap-4'>
@@ -57,20 +56,20 @@ const TranscriptDetailsCard = ({ data, slug }: { data: ContentTreeArray; slug: s
5756
) : null}
5857

5958
<section className='flex gap-2 items-center max-md:gap-1'>
60-
{tags?.length ? (
59+
{tagsDetailed?.length ? (
6160
<>
6261
<span>
6362
<Image src={TagsIcon} alt='date icon' className='w-5 md:w-6' />
6463
</span>
6564
<div className='flex gap-[9px] flex-wrap'>
6665
<div className='flex flex-wrap gap-[9px] max-md:gap-2'>
67-
{tags.slice(0, 3).map((tag, idx) => (
68-
<Pill key={idx} name={tag} slug={`/tags/${createSlug(tag)}`} />
66+
{tagsDetailed.slice(0, 3).map((tag, idx) => (
67+
<Pill key={idx} name={tag.name} slug={`/tags/${tag.slug}`} />
6968
))}
7069

71-
{calculateRemaining(tags) === 0 ? null : (
70+
{calculateRemaining(tagsDetailed) === 0 ? null : (
7271
<p className='py-[2px] px-5 rounded-[5px] bg-gray-custom-700 whitespace-nowrap text-nowrap max-md:px-3 lg:py-1 max-2xl:text-sm max-md:text-sm max-md:border max-md:border-gray-custom-300 max-md:leading-[100%]'>
73-
+ {calculateRemaining(tags)} more
72+
+ {calculateRemaining(tagsDetailed)} more
7473
</p>
7574
)}
7675
</div>

src/components/common/TranscriptMetadataCard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import {
88
MicIcon,
99
} from "@bitcoin-dev-project/bdp-ui/icons";
1010
import Link from "next/link";
11-
import { createSlug } from "@/utils";
11+
import { ContentData, createSlug } from "@/utils";
1212
import AiGeneratedIcon from "../svgs/AIGeneratedIcon";
1313
import { format, isDate } from "date-fns";
1414
import Pill from "./Pill";
1515

1616
interface ITranscriptMetadataComponent {
1717
title: string;
1818
date: string | Date;
19-
topics: string[];
19+
topics: ContentData[];
2020
speakers: string[] | null;
2121
transcriptBy: string | string[];
2222
}
@@ -38,6 +38,7 @@ const TranscriptMetadataComponent = ({
3838

3939
const formattedDate = isDate(convertedDate) ? format(convertedDate, "d MMMM, yyyy") : "";
4040

41+
4142
return (
4243
<div className="border flex text-black flex-col rounded-2xl p-4 md:p-5 2xl:p-6 gap-4 w-full border-gray-custom-1200">
4344
<div className="flex flex-col md:flex-row flex-wrap gap-4 justify-between ">
@@ -108,7 +109,7 @@ const TranscriptMetadataComponent = ({
108109
<div className="flex flex-wrap gap-2">
109110
{(topics && topics.length > 0) ?
110111
topics.map((topic) => (
111-
<Pill key={topic} name={topic} slug={`/tags/${createSlug(topic)}`} />
112+
<Pill key={topic.slug} name={topic.name} slug={`/tags/${topic.slug}`} />
112113
)):
113114
<p className="pl-2.5 pt-1.5 text-xs md:text-sm lg:text-sm 2xl:text-base md:font-medium">Not available</p>
114115
}

src/components/explore/TranscriptContentPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const TranscriptContentPage: FC<ITranscriptContentPage> = ({
9191
</div>
9292
</div>
9393

94-
<div className="flex-col flex gap-10 pb-[calc(90vh-var(--header-height))]">
94+
<div className="flex-col flex gap-10 pb-10">
9595
{groupedData &&
9696
type === "alphabet" &&
9797
Object.entries(groupedData).map((arg, i) => (

src/components/individual-transcript/IndividualTranscript.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ const IndividualTranscript = ({
4949
<TranscriptMetadataComponent
5050
title={transcript.title}
5151
date={transcript.date || ""}
52-
topics={transcript.tags || []}
52+
topics={transcript.tagsDetailed || []}
5353
speakers={transcript.speakers || []}
5454
transcriptBy={transcript.transcript_by || ""}
5555
/>
5656
</div>
5757

5858
<div>
59-
<div className="pt-4 md:pt-5 2xl:pt-6 pb-[var(--header-height)] xl:pb-[calc(60vh-var(--header-height))]">
59+
<div className="pt-4 md:pt-5 2xl:pt-6 pb-10">
6060
<Tabs
6161
markdown={transcript.body.raw}
6262
summary={transcript?.summary}

src/components/individual-transcript/markdown.css

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,34 @@ span.code-line {
3333
}
3434

3535
.wmde-markdown p {
36-
3736
margin-bottom: 8px;
3837
color: #000;
3938
font-size: 0.875rem;
4039
font-weight: 400;
4140
line-height: 2.1875rem;
4241
}
4342

43+
.wmde-markdown ul li {
44+
list-style-type: circle;
45+
color: #000;
46+
}
47+
48+
.wmde-markdown ul {
49+
padding-left: 1em;
50+
}
51+
52+
.wmde-markdown ol {
53+
margin: 0px !important;
54+
font-weight: 400;
55+
}
56+
4457
.wmde-markdown a.anchor {
4558
display: none !important;
4659
}
4760

4861
@media (min-width: 1024px) {
4962

5063
.wmde-markdown h1, .wmde-markdown h2 {
51-
/* margin: 0px !important; */
52-
scroll-margin-top: 100px;
53-
color: #000;
5464
padding-top: 10px;
5565
padding-bottom: 10px;
5666
margin: 12px 0px !important;
@@ -63,26 +73,16 @@ span.code-line {
6373
}
6474

6575
.wmde-markdown p {
66-
margin: 0px !important;
67-
color: #000;
6876
font-weight: 400;
6977
font-size: 1rem;
7078
line-height: 2.1875rem;
7179
}
7280
.wmde-markdown ul,.wmde-markdown ol {
7381
margin: 0px !important;
74-
color: #000;
7582
font-weight: 400;
7683
font-size: 1rem;
7784
line-height: 2.1875rem;
7885
}
79-
.wmde-markdown ul, .wmde-markdown li {
80-
list-style-type: circle;
81-
}
82-
83-
.wmde-markdown a.anchor {
84-
display: none !important;
85-
}
8686
}
8787

8888
@media (min-width: 1536px) {
@@ -93,17 +93,10 @@ span.code-line {
9393
}
9494

9595
.wmde-markdown h3,.wmde-markdown h4, .wmde-markdown h5, .wmde-markdown h6 {
96-
color: #000;
9796
font-size: 1rem;
9897
}
9998

10099
.wmde-markdown p {
101-
margin: 0px !important;
102-
color: #000;
103100
line-height: 2rem;
104101
}
105-
106-
.wmde-markdown a.anchor {
107-
display: none !important;
108-
}
109102
}

0 commit comments

Comments
 (0)