Skip to content

Commit

Permalink
Merge pull request #1 from hamza-m-masood/table-of-contents
Browse files Browse the repository at this point in the history
feat: Adding table of contents to my blog
  • Loading branch information
hamza-m-masood authored Aug 15, 2024
2 parents e0b4a24 + bf06b02 commit b4318df
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 86 deletions.
6 changes: 3 additions & 3 deletions src/content/posts/file-io-in-go.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ tags: ["go"]
draft: false
---

# Printing in Golang
## Printing in Golang

Go has many ways to print. All printing functions stem from the `fmt` package.

Expand All @@ -31,14 +31,14 @@ Third family
- `fmt.Sprintf ` outputs to a string but also format the string.


# File I/O Packages
## File I/O Packages
1. Os package: has functions to open and create files, list directories etc... and has the `File` type
2. Io package: has utilities to read and write
3. Bufio pakcage: provides buffered i/o scanners etc...
4. Io/ioutil package: has extra utilities such as reading and an entire file to memory, or writing it all out at once
5. Strconv package: has utilities to convert to/from string representations

### Misc commands for files:
## Misc commands for files:
- Opening a file: `os.Open(fname)`
- Copying from a file to standard output: `io.Copy(os.Stdout, file)`
- Reading all the data from a file (without buffering): `ioutil.ReadAll(file)`
Expand Down
12 changes: 6 additions & 6 deletions src/content/posts/why-is-concurrency-hard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Concurrency can be extrememly difficult to get right. Bugs can occur even after

Running into concurrency issues is so common that we are now able to label common pitfalls. Below I have listed the most common issues of working with concurrency:

# Race Conditions
## Race Conditions
A race condition occurs when two or more processes must execute in a specific order, but the program allows for the operations to occur in any order, or an order that causes an error.
A classic example is one concurrent operation trying to read from a variable while (potentially) at the same time another concurrent operation is trying to write to it.
```go showLineNumbers
Expand Down Expand Up @@ -55,7 +55,7 @@ We have simply made it increasingly unlikely for our program to product the "inc

Another technique that might help in detecting race conditions is testing your program in different environments. Data races normally tend to occur when there is a change in an environment that was not thought of like a variation in memory or CPU.

# Atomicity
## Atomicity

If series of executions can in it's entirity without interruption in the defined context, then they are considered to be atomic.\
Atomic comes from the greek word Atom. Which means indivisible. Obviously, in modern physics we know this is not true. But it does bring the point across of a process or an execution being indivisible and uninterruptable.
Expand All @@ -77,7 +77,7 @@ Multiple steps are completed from a simple statement.Each step within the proces

Most statements are not atomic. Thus proving another reason why concurrency can be very challenging.

# Memory Access Synchronization
## Memory Access Synchronization

There is a difference between a **data race** and a **race condition**. A race condition occurs when the order of executions are nondeterministic. A data race occurs when many sections of the program are trying to access the same data. A need arises to synchroinze memory when there is a data race.

Expand Down Expand Up @@ -134,7 +134,7 @@ Knowing what data needs to be synchronized and how frequently you need to lock d

If all problems of the previous section are addressed then you will never get a wrong output. The following problems are for your program to always be doing work. In other words, the program has something useful to do at all times:

# Deadlock
## Deadlock

A deadlock happens when all goroutines are blocked. This can happen when all goroutines are waiting for eachother. In this case, your program will not work without manual intervention. Here is an example of a deadlock:

Expand Down Expand Up @@ -181,7 +181,7 @@ Deadlocks can be hard to spot. A technique that can help us identify them are th

The program above fulfills all of the conditions. Hence the reason for having a deadlock.

# Livelock
## Livelock

A very famous example of a livelock would be the following:
Imagine you were in a tight corridor. There is just enough space for two people to walk. You come face to face with another person. You move left, the other person moves left as well in an attempt to walk by. You move right, the other person moves right as well. Both people become stuck in this state of hallway shuffle moving left and right continuously!
Expand All @@ -190,7 +190,7 @@ This occurs when two goroutines or concurrent processes are trying to prevent de

Livelock is a subset of a larger problem called starvation.

# Starvation
## Starvation

A greedy goroutine means when one goroutine gets in the way of other goroutines. When you have a greedy goroutine, other concurrent processes can't find resources to perform their work. This is an example of starvation. A goroutine can also suffer finding resources from outside the Go program as well. Lack of CPU power, database connection, lack of memory etc.. can all lead to starvation. Starvation is relatively easy to spot when external factors are in play but can be quite difficult to spot when goroutines are competing against eachother.

Expand Down
2 changes: 1 addition & 1 deletion src/layouts/Base.astro
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface Props {
canonical?: string;
}
// distructure frontmatters
// destructure frontmatters
const { title, meta_title, description, image, noindex, canonical } =
Astro.props;
---
Expand Down
204 changes: 129 additions & 75 deletions src/layouts/PostSingle.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,31 @@ import dateFormat from "@/lib/utils/dateFormat";
import similerItems from "@/lib/utils/similarItems";
import { humanize, markdownify, slugify } from "@/lib/utils/textConverter";
import { BiCalendarEdit, BiCategoryAlt } from "react-icons/bi";
import TableOfContents from "./components/TableOfContents.astro";
const allAuthors = await getSinglePage("authors");
const posts = await getSinglePage("posts");
const { post } = Astro.props;
const { headings } = Astro.props;
const similarPosts = similerItems(post, posts, post.slug);
const { Content } = await post.render();
const { title, description, authors, categories, image, date, tags } =
post.data;
---

<section class="section">
<div class="container">
<article class="row justify-center">
<div class="md:col-10 text-center">
<h1 set:html={markdownify(title)} class="h2" />
<ul class="mt-4 flex flex-wrap items-center justify-center text-text">
<li class="mx-3">
{
allAuthors
.filter((author) =>
authors
.map((author: string) => slugify(author))
.includes(slugify(author.data.title)),
)
.map((author, i) => (
<a
href={`/authors/${slugify(author.slug)}`}
class="flex items-center hover:text-primary font-medium"
>
{author.data.image && (
<Image
src={author.data.image}
alt={author.data.title}
height={50}
width={50}
class="mr-2 h-6 w-6 rounded-full"
/>
)}
<span>{author.data.title}</span>
</a>
))
}
</li>
<section
class="px-5 sm:mx-auto sm:max-w-2xl sm:px-8 lg:px-0 antialiased md:max-w-6xl grid gap-12 mt-4 overflow-hidden md:overflow-visible"
>
<article class="min-w-full md:py-4 sm:max-w-none md:max-w-none">
<header class="mb-3 flex flex-col justify-center items-center gap-6">
<div class="flex flex-col gap-2">
<h1
set:html={markdownify(title)}
class="text-center text-4xl md:text-6xl md:pb-2.5 font-semibold"
/>
<ul
class="flex flex-wrap justify-center items-center gap-2 gap-y-4 md:gap-5"
>
<li class="mx-3 flex items-center flex-wrap font-medium">
<BiCalendarEdit className="mr-1 h-5 w-5 text-gray-600" />
<>{dateFormat(date)}</>
Expand All @@ -76,50 +58,66 @@ const { title, description, authors, categories, image, date, tags } =
</li>
</ul>
</div>

<div class="col-12 mt-8 mb-2">
{
image && (
<Image
src={image}
height={500}
width={1000}
alt={title}
class="rounded-lg"
/>
)
}
</div>

<div class="md:col-10">
<div class="content mb-16 text-left">
<Content />
</div>
<div class="flex flex-wrap items-center justify-between">
<ul class="mr-4 mb-4 space-x-3">
{
tags.map((tag: string) => (
<li class="inline-block">
<a
href={`/tags/${slugify(tag)}`}
class="block rounded-lg bg-theme-light px-4 py-2 font-semibold text-dark text-sm hover:text-primary transition duration-300"
>
#{humanize(tag)}
</a>
</li>
))
}
</ul>
<Share
className="social-share mb-4"
title={title}
description={description}
slug={post.slug}
</header>
<div class="col-12 mt-8 mb-2">
{
image && (
<Image
src={image}
alt={title}
width={1000}
height={500}
quality={100}
format="jpg"
loading="eager"
class="rounded-md w-full max-h-[300px] md:max-h-[500px] my-8 object-cover"
/>
</div>
)
}
</div>
<div>
<!-- <div class="content mb-16 text-left">
<Content />
</div> -->
<div class="grid grid-cols-1 md:grid-cols-[20%_auto] gap-10 mt-8">

<aside class="md:flex flex-col gap-8 hidden">
<div
class="sticky top-24 self-start hidden md:block transition-all duration-200"
>
{headings && headings.length > 0 && <TableOfContents {headings} />}
</div>
</aside>
<article class="max-w-full w-full">
<div class="prose prose-lg md:prose-xl mb-12 min-w-full">
<Content />
</div>
</article>
</div>
</article>
</div>
</div>
<div class="flex flex-wrap items-center justify-between">
<ul class="mr-4 mb-4 space-x-3">
{
tags.map((tag: string) => (
<li class="inline-block">
<a
href={`/tags/${slugify(tag)}`}
class="block rounded-lg bg-theme-light px-4 py-2 font-semibold text-dark text-sm hover:text-primary transition duration-300"
>
#{humanize(tag)}
</a>
</li>
))
}
</ul>
<Share
className="social-share mb-4"
title={title}
description={description}
slug={post.slug}
/>
</div>
</article>
</section>

<!-- similar posts -->
Expand All @@ -133,3 +131,59 @@ const { title, description, authors, categories, image, date, tags } =
</section>
)
}
<script>
const fnObserver = () => {
function handleIntersection(
entries: IntersectionObserverEntry[],
observer: IntersectionObserver,
) {
entries.forEach((entry) => {
const index = document.querySelector(
`aside a[href="#${entry.target.id}"]`,
);

if (entry.isIntersecting) {
index?.classList.add(
"bg-blue-100",
"bg-blue-100",
"font-bold",
"transition-colors",
"duration-100",
);
} else {
index?.classList.remove(
"bg-blue-100",
"bg-blue-100",
"font-bold",
"transition-colors",
"duration-100",
);
}
});
}

const headings = document.querySelectorAll(
"div.prose h1, div.prose h2, div.prose h3, div.prose h4, div.prose h5, div.prose h6",
);

const options = {
root: null,
rootMargin: " 15% 0px 0% 0px ",
threshold: 1,
};

const observer = new IntersectionObserver(handleIntersection, options);

headings.forEach((heading) => {
observer.observe(heading);
});
};

fnObserver();
document.addEventListener("astro:after-swap", fnObserver);
</script>
<style>
body {
margin-left: calc(100vw - 100%); /* prevent layout shift */
}
</style>
42 changes: 42 additions & 0 deletions src/layouts/components/TableOfContents.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
// TableOfContents.astro
const { headings } = Astro.props;
const toc = buildToc(headings);
import TableOfContentsHeading from "./TableOfContentsHeading.astro";
interface Heading {
depth: number;
title: string;
subheadings: Heading[];
}
function buildToc(headings: Array<{ depth: number; title: string }>): Heading[] {
const toc: Heading[] = [];
const parentHeadings = new Map<number, Heading>();
headings.forEach((h) => {
const heading: Heading = { ...h, subheadings: [] };
parentHeadings.set(heading.depth, heading);
// Change 2 to 1 if your markdown includes your <h1>
if (heading.depth === 2) {
toc.push(heading);
} else {
const parentHeading = parentHeadings.get(heading.depth - 1);
if (parentHeading) {
parentHeading.subheadings.push(heading);
} else {
console.warn(`No parent found for heading at depth ${heading.depth}`);
}
}
});
return toc;
}
---

<nav class="toc">
<ul>
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
</ul>
</nav>
19 changes: 19 additions & 0 deletions src/layouts/components/TableOfContentsHeading.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
// TableOfContentsHeading.astro
const { heading } = Astro.props;
---

<li>
<a href={'#' + heading.slug}>
{heading.text}
</a>
{
heading.subheadings.length > 0 && (
<ul>
{heading.subheadings.map((subheading) => (
<Astro.self heading={subheading} />
))}
</ul>
)
}
</li>
Loading

0 comments on commit b4318df

Please sign in to comment.