feat: themeing - Bug fixes

This commit is contained in:
minhtrannhat 2025-01-29 23:25:18 -05:00
parent f1ed47c164
commit 7781ac660b
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
21 changed files with 306 additions and 144 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="16" height="16"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 13.28L12.2 2H13.76L9.56 13.28H8Z" fill="black"></path>
<path d="M2 8.89995V7.95195C2 7.45595 2.16 7.05995 2.48 6.76395C2.8 6.46795 3.22 6.31995 3.74 6.31995C4.068 6.31995 4.34 6.37595 4.556 6.48795C4.772 6.59995 4.952 6.73595 5.096 6.89595C5.248 7.05595 5.38 7.21995 5.492 7.38795C5.612 7.54795 5.732 7.68395 5.852 7.79595C5.972 7.89995 6.112 7.95195 6.272 7.95195C6.424 7.95195 6.536 7.90795 6.608 7.81995C6.688 7.72395 6.728 7.59595 6.728 7.43595V6.55995H8V7.50795C8 7.99595 7.84 8.39195 7.52 8.69595C7.208 8.99195 6.788 9.13995 6.26 9.13995C5.932 9.13995 5.66 9.08395 5.444 8.97195C5.228 8.85995 5.044 8.72395 4.892 8.56395C4.748 8.40395 4.616 8.24395 4.496 8.08395C4.384 7.91595 4.268 7.77995 4.148 7.67595C4.028 7.56395 3.888 7.50795 3.728 7.50795C3.584 7.50795 3.472 7.55195 3.392 7.63995C3.312 7.72795 3.272 7.85595 3.272 8.02395V8.89995H2Z" fill="black"></path>
</svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
@media (prefers-color-scheme: dark) { :root { filter: invert(100%); } }
</style></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

BIN
public/og.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,6 +1,4 @@
@import url("https://fonts.cdnfonts.com/css/jetbrains-mono-2");
@import "tailwindcss";
@config "../tailwind.config.ts";
.tree,
@ -45,3 +43,5 @@
height: calc(var(--line-height) / 2);
border-left: var(--border-thickness) solid var(--text-color);
}
@import "tailwindcss";

View File

@ -1,27 +1,20 @@
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { createSignal, onCleanup, onMount, Suspense } from "solid-js";
import { Suspense } from "solid-js";
import "./app.css";
import { Layout } from "./components/Layout";
import { MetaProvider, Title } from "@solidjs/meta";
import { MetaProvider, Title, Meta } from "@solidjs/meta";
export default function App() {
onMount(() => {
const listener = (e: KeyboardEvent) => {
if (e.metaKey && e.key.toLowerCase() === "k") {
e.preventDefault(); // Prevent the default action (optional)
document.body.classList.toggle("debug");
}
};
window.addEventListener("keydown", listener);
onCleanup(() => {
window.removeEventListener("keydown", listener);
});
});
return (
<MetaProvider>
<Title>minhtrannhat.com</Title>
<Title>minhtran_dev</Title>
<Meta property="og:title" content="minhtran_dev" />
<Meta property="og:description" content="just trying my best :)" />
<Meta property="og:image" content="/og.png" />
<Meta property="og:image:alt" content="minhtran_dev site" />
<Meta property="og:image:width" content="1200" />
<Meta property="og:image:height" content="630" />
<Router
root={(props) => {
return (

View File

@ -3,13 +3,13 @@ import JobCard from "./JobCard";
import { createSignal } from "solid-js";
const Experience = () => {
const [jobs, setJobs] = createSignal([
const [jobs, _] = createSignal([
{
title: "Software Developer Engineer Intern",
company: "Amazon (Delivery Extensions Team)",
location: "Toronto, Ontario, Canada",
range: "May 2025 - July 2025",
url: "",
url: "https://amazon.jobs/content/en/teams/ftr",
},
{
title: "Software Engineer Intern",
@ -21,9 +21,10 @@ const Experience = () => {
]);
return (
<section class="mt-6 mx-auto px-4">
<h2 class="mt-6 text-xl font-bold mb-8">Experience</h2>
<div>
<section class="mt-16 px-4">
<h2 class="text-xl text-nord-1 font-bold mb-6">Experience</h2>
<div class="!flex !flex-col !gap-0.5v ml-2h">
<For each={jobs()}>{(job) => <JobCard job={job} />}</For>
</div>
</section>

View File

@ -1,13 +1,13 @@
const JobCard = (props) => {
return (
<div class="mb-8">
<div class="p-4">
<h3 class="font-bold text-xl">
{props.job.title} @
<a href={props.job.url} class="text-blue-500 hover:text-blue-600">
{props.job.company}
</a>
</h3>
<p class="text-gray-600 mb-4">
<p class="text-nord-1 mb-4">
{props.job.range} | {props.job.location}
</p>
</div>

View File

@ -22,17 +22,22 @@ export const Layout: ParentComponent = (props) => {
<div class="bg-nord-6 flex flex-col min-h-screen pt-2v py-1v px-2h max-w-full mx-auto relative overflow-x-hidden leading-1 box-border decoration-2 underline-offset-2">
<header class="flex flex-col items-center justify-center gap-2v px-4h py-2v">
<a href="/" class="text-nord-3 text-2v leading-2 font-bold">
~/minhtrannhat
~/minh
</a>
<nav class="container mx-auto px-4 py-4">
<ul class="flex flex-wrap justify-center items-center gap-6">
<A end class="hover:underline" activeClass="font-bold" href={"/"}>
<A
end
class="hover:underline hover:text-nord10"
activeClass="font-bold"
href={"/"}
>
Home
</A>
<A
end
class="hover:underline"
class="hover:underline hover:text-nord10"
activeClass="font-bold"
href={"/articles"}
>
@ -40,20 +45,21 @@ export const Layout: ParentComponent = (props) => {
</A>
<A
end
class="hover:underline"
class="hover:underline hover:text-nord10"
activeClass="font-bold"
href={"/tags"}
>
Tags
</A>
<a
<A
class="hover:text-nord10"
href="/resume.pdf"
target="_blank"
rel="noreferrer"
onClick={() => changeFavicon("./favicon.ico")}
>
Resume
</a>
</A>
</ul>
</nav>
</header>

View File

@ -42,7 +42,7 @@ const Pre: ParentComponent<{ lang: string; lines?: string; file?: string }> = (
return (
<div class="my-1v">
<div class="bg-black text-white dark:bg-white dark:text-black flex justify-between px-1h text-sm leading-1">
<div class="bg-nord2 text-nord12 flex justify-between px-1h text-sm leading-1">
<Show when={props.file} fallback={<span aria-hidden />}>
<span>{props.file}</span>
</Show>
@ -186,9 +186,9 @@ export const PostImage: Component<{
);
};
export const Aside: ParentComponent = (props) => (
export const Notes: ParentComponent = (props) => (
<aside class="border-l-2 border-black dark:border-white pl-1h mt-1v">
<div class="uppercase text-sm leading-1 font-medium select-none">Aside</div>
<div class="uppercase text-sm leading-1 font-medium select-none">Notes</div>
<div class="[&_*:first-child]:mt-0">{props.children}</div>
</aside>
);

136
src/css/prism-nord.css Normal file
View File

@ -0,0 +1,136 @@
/* Generated with http://k88hudson.github.io/syntax-highlighting-theme-generator/www */
/*********************************************************
* General
*/
pre[class*="language-"],
code[class*="language-"] {
color: #d8dee9;
font-size: 1em;
text-shadow: none;
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::selection,
code[class*="language-"]::selection,
pre[class*="language-"]::mozselection,
code[class*="language-"]::mozselection {
text-shadow: none;
background: none;
}
@media print {
pre[class*="language-"],
code[class*="language-"] {
text-shadow: none;
}
}
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
background: #2e3440;
}
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
color: #d8dee9;
background: #2e3440;
}
/*********************************************************
* Tokens
*/
.namespace {
opacity: 0.7;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #606e87;
}
.token.punctuation {
color: #81a1c1;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #b48ead;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a2bf8c;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #80a2c1;
background: none;
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #81a1c1;
}
.token.function {
color: #8fbcbc;
}
.token.regex,
.token.important,
.token.variable {
color: #ee9900;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/*********************************************************
* Line highlighting
*/
pre[data-line] {
position: relative;
}
pre[class*="language-"] > code[class*="language-"] {
position: relative;
z-index: 1;
}
.line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em;
background: #3b4251;
box-shadow: inset 5px 0 0 #d8dee9;
z-index: 0;
pointer-events: none;
line-height: inherit;
white-space: pre;
}

View File

@ -1 +1,11 @@
[]
[
{
"title": "Testing Test Test Test",
"description": "Woah this is so cool",
"date": "2025-1-29",
"featuredImage": null,
"featuredImageDesc": null,
"tags": ["rust", "python", "mdx", "markdown"],
"slug": "test"
}
]

View File

@ -1,48 +0,0 @@
---
date: 20204-05-11
tags:
- solidjs
- webdev
title: How to enumerate routes in solid-start
---
This website is built with [solid-start](https://start.solidjs.com/getting-started/what-is-solidstart).
I needed a way to enumerate all of the posts under `/blog` so that I could dynamically generate lists, both for the [home page](/), and for the tags pages: [/tags/solidjs](/tags/solidjs).
However, the solid-start `<FileRouter>` doesn't expose any of that information, either at build-time or run-time. We have to figure it out ourselves.
My first thought was to have a script that watches the directory and writes to a file.
That would've worked. But while browsing through the docs trying to figure out how to get a file watcher to be part of the vite dev server, I found out about [virtual modules](https://vitejs.dev/guide/api-plugin#virtual-modules-convention).
Essentially, you can define a `js` module that has dynamic content by exporting a `js` string.
```js lang="js" lines="2,14"
export default function myPlugin() {
const virtualModuleId = 'virtual:my-module'
const resolvedVirtualModuleId = '\0' + virtualModuleId
return {
name: 'my-plugin', // required, will show up in warnings and errors
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const msg = "from virtual module"`
}
},
}
}
```
After adding `myPlugin` to your vite plugins list, you can import the virtual module anywhere in the code and use it as if it were a real file.
```js lang="js"
import {msg} from "virtual:my-module"
```
This seemed more "elegant" than a file watcher.

View File

@ -1,34 +0,0 @@
---
date: 20204-05-11
tags:
- solidjs
- webdev
title: This blog uses solid-start.
description: How to set up a blog using solid-start and mdx.
---
This website uses [solid-start](https://start.solidjs.com/getting-started/what-is-solidstart).
solid-start is a Next.js-like framework for creating SSR / SSG websites. But instead of react, it builds on top of solid-js.
I've been using solid and solid-start professionally for almost 2 years. And while solid-js feels rock-solid, solid-start still feels rough around the edges.
For each of the features I wanted to implement, I ran into issues that delayed this from being a weekend project into taking about 4 weekends instead.
Here's what I wanted to accomplish:
1. Use [mdx](https://mdxjs.com/) for writing the posts
2. Define metadata for each post in the same mdx file
3. Full SSG
4. Code highlighting at compile time
5. Tags
And here's how I did it:
## Using mdx
MDX is markdown that you can intersprinkle with jsx.
The initial scaffolding is easy, follow [these steps](https://docs.solidjs.com/solid-start/getting-started), and choose the `with-mdx` option.
I opted to have my posts live under the `/blog` path.

1
src/global.d.ts vendored
View File

@ -1 +0,0 @@
/// <reference types="@solidjs/start/env" />

View File

@ -1,14 +0,0 @@
---
date: 2022-12-27
title: Software Engineer Intern
company: Cisco Systems
location: Remote
range: January - May 2023
url: https://www.cisco.com/c/en/us/products/cloud-systems-management/modeling-labs/index.html
---
- Developed a **multi-threaded Python microservice** for a Cisco internal SaaS ingesting usage telemetry data of Cisco Cat9kv switches from thousands of GNS3 networking projects to be stored in **Elastic Search**.
- Containerized and integrated **Elastic Search** and **Kibana** into existing microservices system.
- Created insightful **Kibana** charts highlighting Cat9kv switch flavors daily usage and number of daily users to present to Cisco Enterprise Networking Group executives.
- Wrote custom **Ansible** modules to synchronize folders across Cisco managed servers while ensuring 100% folder structure and files integrity with hashing algorithm utilizing Python SHA1 crytographic library.
- Automated custom **Ansible** modules testing with **Bash** scripts. Testing environment made with **Vagrant** and **Docker** to simulate production servers

View File

@ -19,8 +19,8 @@ const Homepage = () => {
Montreal, Canada.
<br />
<br />
I'm most passionate about designing distributed systems that scales
but I'm also interested in compilers and systems programming.
Things that I'm most passionate about: distributed systems, backend
development, compilers and systems programming.
<br />
<br />
When I'm not coding, I read books, listen to podcasts or study music
@ -29,7 +29,7 @@ const Homepage = () => {
<p>
Say hi:{" "}
<a
class="underline"
class="underline hover:text-nord-11"
target="_blank"
rel="noreferrer"
href="mailto:minh@minhtrannhat.com"
@ -41,7 +41,7 @@ const Homepage = () => {
<ul class="mx-4 sm:mx-6 sm:mt-3v text-slate-600 text-base sm:text-sm leading-1">
<For each={links}>
{(link) => (
<li class="list-square hover:text-black ml-2h leading-1">
<li class="list-square hover:text-nord-11 ml-2h leading-1">
<a
target="_blank"
rel="noreferrer"

View File

@ -5,6 +5,7 @@ import { posts } from "~/data/posts";
import { MDXProvider } from "solid-mdx";
import { markdownComponents, PostImage } from "~/components/Markdown";
import dayjs from "dayjs";
import "../css/prism-nord.css";
import type { Post } from "~/types";
const Blog = (props: RouteSectionProps<unknown>) => {
@ -18,7 +19,7 @@ const Blog = (props: RouteSectionProps<unknown>) => {
return (
<article class="pb-5v">
<Title>minhtrannhat.com - {meta()?.title}</Title>
<Title>minhtran_dev - {meta()?.title}</Title>
<Meta name="og:title" content={meta().title} />
<Meta name="description" content={meta().description} />
<Meta name="og:description" content={meta().description} />

118
src/routes/blog/test.mdx Normal file
View File

@ -0,0 +1,118 @@
---
title: Testing Test Test Test
description: Woah this is so cool
date: 2025-1-29
featuredImage:
featuredImageDesc:
tags:
- rust
- python
- mdx
- markdown
---
import { Notes, PostImage } from "~/components/Markdown"
import { Tree } from "~/components/Tree"
Woah this blog is sooo cool, look at all these beautifully rendered markdown stuffs :OOOO
<Notes>
Notty Notes
</Notes>
## Contents
<hr />
## Python
### longestCommonSubsequence
```python lang="python" file="leetcode1143.py"
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
# edge cases
# both texts are just length of 1:
if len(text1) == 1 and len(text2) == 1:
return int(text1 == text2)
# only one row:
if len(text2) == 1 and len(text1) > 1:
return int(text2 in text1)
# only one col:
if len(text1) == 1 and len(text2) > 1:
return int(text1 in text2)
rows = len(text2)
cols = len(text1)
# we use bottom up 2D DP
# reaching here means it is at least 2x2
dp = [
[0 for _ in range(cols)] for _ in range(rows)
]
# seed the top left tile
dp[0][0] = 1 if text1[0] == text2[0] else 0
# we seed the first row and first col
for col in range(1, cols):
dp[0][col] = dp[0][col - 1] if text1[col] != text2[0] else 1
for row in range(1, rows):
dp[row][0] = dp[row - 1][0] if text1[0] != text2[row] else 1
# for the inner triangle, we use the following
# dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) if text1[i] != text2[j]
# else max(dp[i - 1][j], dp[i][j - 1]) + 1
for row in range(1, rows):
for col in range(1, cols):
dp[row][col] = dp[row - 1][col - 1] + 1 if text1[col] == text2[row] else max(dp[row - 1][col], dp[row][col - 1])
# return the bottom right tile
return dp[rows - 1][cols - 1]
# space and time complexity: both O(N * M)
# CAN OPTIMIZE TO GET SPACE COMPLEXITY OF O(MIN(N, M))
```
## Rust
### Async Programming stuffs
```rust lang="rust" file="ffi.rs"
// Here we have the syscalls
// Unsafe !!!
#[link(name = "c")]
extern "C" {
pub fn epoll_create(size: i32) -> i32;
pub fn close(fd: i32) -> i32;
pub fn epoll_ctl(epfd: i32, op: i32, fd: i32, event: *mut Event) -> i32;
pub fn epoll_wait(epfd: i32, events: *mut Event, maxevents: i32, timeout: i32) -> i32;
}
// Avoid padding by using repr(packed)
// Data struct is different in Rust compared to C
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
pub struct Event {
pub(crate) events: u32,
// Using `Token` a.k.a `epoll_data` to track which socket generated the event
pub(crate) epoll_data: usize,
}
impl Event {
pub fn token(&self) -> usize {
self.epoll_data
}
}
```

View File

@ -4,7 +4,7 @@ import { tags } from "~/data/tags";
const Tags = () => {
return (
<div>
<h1 class="text-xl font-bold mt-2v mb-1v">All tags:</h1>
<h1 class="text-xl text-nord-1 font-bold mt-1v mb-1v">All tags:</h1>
<ol class="flex flex-col gap-1v list-square ml-2h">
<For each={Object.values(tags)}>
{(tag) => (