diff --git a/bun.lockb b/bun.lockb
index 3ae1c10..5142561 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/src/components/TableOfContents.astro b/src/components/TableOfContents.astro
new file mode 100644
index 0000000..05424b6
--- /dev/null
+++ b/src/components/TableOfContents.astro
@@ -0,0 +1,44 @@
+---
+import type { MarkdownHeading } from 'astro';
+
+interface Props {
+ headings: MarkdownHeading[];
+}
+
+const { headings } = Astro.props;
+
+const filteredHeadings = headings.filter((heading) => heading.depth <= 2);
+const toc = buildToc(headings);
+
+function buildToc(headings) {
+ // ...
+function buildToc(headings) {
+ const toc = [];
+ const parentHeadings = new Map();
+ headings.forEach((h) => {
+ const heading = { ...h, subheadings: [] };
+ parentHeadings.set(heading.depth, heading);
+ // Change 2 to 1 if your markdown includes your
+ if (heading.depth === 2) {
+ toc.push(heading);
+ } else {
+ parentHeadings.get(heading.depth - 1).subheadings.push(heading);
+ }
+ });
+ return toc;
+}
+}
+---
+
+
diff --git a/src/content/blog/hemoglobin.md b/src/content/blog/hemoglobin.md
new file mode 100644
index 0000000..1163762
--- /dev/null
+++ b/src/content/blog/hemoglobin.md
@@ -0,0 +1,53 @@
+---
+title: 'Bài 1.4: Hoá học Porphyrin & Hemoglobin'
+description: ''
+pubDate: 'Nov 11 2024'
+heroImage: '/blog-placeholder-3.jpg'
+tags: ['Hoá Sinh']
+---
+
+* Hb trong máu: ~ 15 g/dl (15g/100ml máu).
+
+* 1g Hb vận chuyển được 1,34ml oxy→ 100ml máu mang được max 20ml oxy (oxy hòa tan 0,39ml và oxy gắn Hb >19ml).
+
+## I/. ĐẠI CƯƠNG
+
+### 1). Cromoprotein
+
+* Protein tạp, nhóm ngoại là chất màu, chia làm 2 loại là có nhóm ngoại là/k là nhân porphyrin
+
+ #### a. Porphyrinoprotein: nhóm ngoại là nhân porphyrin
+
+ Thí dụ :
+ Hb (hemoglobin): sắc tố đỏ của hồng cầu.
+ Myoglobin: Sắc tố hô hấp trong tế bào cơ ở động vật có xương sống.
+ Một số oxydoreductase: các enzym xúc tác phản ứng oxy hóa khử như cytocrom
+
+ #### b. Cromoprotein có nhóm ngoại không phải là nhân porphyrin
+
+ Thí dụ:
+ Flavoprotein chứa riboflavin
+ Ferritin chứa sắt
+ Hemocyamin chứa đồng
+
+### 2). Porphyrin
+
+## II/. HEMOGLOBIN (Hb)
+
+### 1). HEM
+
+### 2). GLOBIN
+
+### 3). Sự kết hợp HEM và GLOBIN
+
+## III/. TÍNH CHẤT CỦA HEMOGLOBIN
+
+### 1). Kết hợp thuận nghịch với O2
+
+### 2). Kết hợp thuận nghịch với CO2
+
+### 3). Kết hợp với CO
+
+### 4). Oxy hóa Hb tạo methemoglobin (MetHb)
+
+### 5). Tính chất enzym của Hemoglobin
diff --git a/src/layouts/BlogPost.astro b/src/layouts/BlogPost.astro
index 4a494b6..ed1507f 100644
--- a/src/layouts/BlogPost.astro
+++ b/src/layouts/BlogPost.astro
@@ -1,13 +1,18 @@
---
import type { CollectionEntry } from 'astro:content';
+import type { MarkdownHeading } from 'astro';
import BaseHead from '../components/BaseHead.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import FormattedDate from '../components/FormattedDate.astro';
import Utterances from '../components/Utterances.astro';
-type Props = CollectionEntry<'blog'>['data'];
+import TableOfContents from '../components/TableOfContents.astro';
+// type Props = CollectionEntry<'blog'>['data'];
-const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
+type Props = CollectionEntry<'blog'>['data'] & { headings: MarkdownHeading[] };
+
+
+const { title, description, pubDate, updatedDate, heroImage, headings } = Astro.props;
---
@@ -42,6 +47,7 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
+
diff --git a/src/pages/notes/[...slug].astro b/src/pages/notes/[...slug].astro
index 07dbce2..619c26a 100644
--- a/src/pages/notes/[...slug].astro
+++ b/src/pages/notes/[...slug].astro
@@ -1,20 +1,33 @@
---
import { type CollectionEntry, getCollection } from 'astro:content';
import BlogPost from '../../layouts/BlogPost.astro';
+import type { MarkdownHeading } from 'astro';
export async function getStaticPaths() {
- const posts = await getCollection('blog');
- return posts.map((post) => ({
- params: { slug: post.slug },
- props: post,
- }));
+ const posts = await getCollection('blog');
+
+ const headings = await Promise.all(
+ posts.map(async (post) => {
+ const data = await post.render();
+ return data.headings;
+ })
+ );
+
+ return posts.map((post, index) => ({
+ params: { slug: post.slug },
+ props: { post, headings: headings[index] },
+ }));
}
-type Props = CollectionEntry<'blog'>;
-const post = Astro.props;
+type Props = {
+ post: CollectionEntry<'blog'>;
+ headings: MarkdownHeading[];
+};
+
+const { post, headings } = Astro.props;
const { Content } = await post.render();
---
-
+