Skip to content

Commit d0d5c5d

Browse files
committed
Add styling and theming.
1 parent 935f869 commit d0d5c5d

File tree

14 files changed

+439
-145
lines changed

14 files changed

+439
-145
lines changed

astro.config.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
import { defineConfig } from 'astro/config';
33
import solidJs from '@astrojs/solid-js';
44
import markdoc from '@astrojs/markdoc';
5+
import tailwind from '@tailwindcss/vite'
56

67
export default defineConfig({
78
output: "static",
89
site: 'https://rubinius.com',
910
base: '/',
1011

12+
vite: { plugins: [tailwind()] },
1113
integrations: [solidJs(), markdoc()],
1214
});

package-lock.json

Lines changed: 28 additions & 111 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"devDependencies": {
2020
"@astrojs/markdoc": "^0.15.8",
2121
"@mermaid-js/mermaid-cli": "^11.4.0",
22+
"@tailwindcss/typography": "^0.5.19",
2223
"@tailwindcss/vite": "^4.1.16",
2324
"mermaid": "^11.12.1",
2425
"tailwindcss": "^4.1.16"

src/components/Analytics.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
const gaId = "G-5SDC7TZYDR";
2+
const gaId = "G-KLQJHB8G93";
33
---
44

55
<script async src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}></script>

src/components/BlogList.astro

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
import { getBlogList, isActivePath } from "@/lib/blog";
3+
const blogLinks = await getBlogList();
4+
5+
const { activeId } = Astro.props;
6+
---
7+
8+
<nav aria-label="All blog posts" class="text-sm">
9+
<h2 class="mb-2 px-2 text-xs font-semibold uppercase tracking-wide opacity-70">
10+
Blog posts
11+
</h2>
12+
<ul class="space-y-1">
13+
{blogLinks.map((it) => {
14+
const isActive = isActivePath(it.path, activeId);
15+
return (
16+
<li>
17+
<a
18+
href={it.path}
19+
aria-current={isActive ? "page" : undefined}
20+
class={
21+
"block rounded-md px-2 py-1.5 outline-none ring-0 transition " +
22+
(isActive
23+
? "bg-fg/10 font-medium"
24+
: "hover:bg-fg/5 focus:bg-fg/5")
25+
}
26+
>
27+
{it.title}
28+
</a>
29+
</li>
30+
);
31+
})}
32+
</ul>
33+
</nav>

src/components/DocToc.astro

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
import { buildToc, type RawHeading, type TocItem } from "@/lib/docs";
3+
4+
interface Props {
5+
headings: RawHeading[]; // pass through from entry.render()
6+
}
7+
const { headings } = Astro.props;
8+
const toc: TocItem[] = buildToc(headings, [2, 3]);
9+
---
10+
11+
<nav aria-label="In this document" class="text-sm">
12+
<h2 class="mb-2 px-2 text-xs font-semibold uppercase tracking-wide opacity-70">
13+
In this document
14+
</h2>
15+
16+
{toc.length === 0 ? (
17+
<p class="px-2 opacity-70">No sections</p>
18+
) : (
19+
<ul class="space-y-1">
20+
{toc.map((h2) => (
21+
<li>
22+
<a href={h2.slug} class="block rounded-md px-2 py-1.5 hover:bg-fg/5">{h2.text}</a>
23+
{h2.children?.length ? (
24+
<ul class="mt-1 ms-2 border-s ps-3 space-y-1">
25+
{h2.children.map((h3) => (
26+
<li>
27+
<a href={h3.slug} class="block rounded-md px-2 py-1 hover:bg-fg/5">
28+
{h3.text}
29+
</a>
30+
</li>
31+
))}
32+
</ul>
33+
) : null}
34+
</li>
35+
))}
36+
</ul>
37+
)}
38+
</nav>

src/components/SiteHeader.astro

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
---
2+
import ThemeSwitch from "@/components/ThemeSwitch.astro";
23
---
4+
35
<header class="flex items-center justify-between h-14">
46
<div class="text-sm font-semibold tracking-tight">
57
Rubinius
68
</div>
7-
<nav class="flex items-center gap-4 text-sm font-medium text-slate-700">
8-
<a href="/blog/" class="hover:text-slate-900">Blog</a>
9-
<a href="/newsletters/" class="hover:text-slate-900">Newsletters</a>
10-
<a href="/docs/" class="hover:text-slate-900">Docs</a>
11-
<a href="/reference/" class="hover:text-slate-900">Reference</a>
9+
<nav class="hidden md:flex gap-4 text-sm text-slate-200/80 items-end">
10+
<a href="/" class="text-black dark:text-white">Home</a>
11+
<a href="/blog" class="text-black dark:text-white">Blog</a>
12+
<a href="/docs" class="text-black dark:text-white">Docs</a>
13+
<ThemeSwitch />
1214
</nav>
1315
</header>

src/components/ThemeBoot.astro

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script is:inline>
2+
// 0. Get system theme
3+
function systemTheme() {
4+
return window.matchMedia("(prefers-color-scheme: dark)")
5+
}
6+
7+
// 1. Change html to the correct theme (light/dark)
8+
function setTheme(isDark) {
9+
console.log("setTheme: isDark: " + isDark);
10+
document.documentElement.classList.toggle("dark", isDark);
11+
}
12+
13+
// 2. Possibly update theme when system setting is changed
14+
function systemUpdateTheme(e) {
15+
console.log("systemUpdateTheme " + e.matches)
16+
initTheme();
17+
}
18+
19+
systemTheme().addEventListener("change", systemUpdateTheme);
20+
21+
// 3. Set initial theme from settings
22+
function initTheme() {
23+
let savedTheme = localStorage.getItem("theme");
24+
if (!savedTheme) {
25+
selectTheme("system");
26+
} else {
27+
if (savedTheme === "system") {
28+
setTheme(systemTheme().matches);
29+
} else {
30+
setTheme(savedTheme === "dark");
31+
}
32+
}
33+
}
34+
35+
// 4. Change theme on button press
36+
function selectTheme(theme) {
37+
localStorage.setItem("theme", theme);
38+
initTheme();
39+
}
40+
41+
initTheme();
42+
</script>

src/components/ThemeSwitch.astro

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
const buttons = [
3+
{ id: "theme-light", value: "light", pressed: false },
4+
{ id: "theme-system", value: "system", pressed: false },
5+
{ id: "theme-dark", value: "dark", pressed: false },
6+
];
7+
---
8+
9+
<div class="flex gap-2" role="radiogroup">
10+
{buttons.map(({ id, value, pressed }) => (
11+
<button
12+
id={id}
13+
type="button"
14+
class="text-black border-black dark:text-white dark:border-white px-3 py-1.5 rounded-xl text-sm font-medium border"
15+
aria-pressed={pressed}
16+
>
17+
{value}
18+
</button>
19+
))}
20+
</div>
21+
22+
<script is:inline>
23+
function attachThemeHandler(id, value) {
24+
const el = document.getElementById(id);
25+
if (el) el.addEventListener("click", () => selectTheme(value));
26+
}
27+
28+
attachThemeHandler("theme-light", "light");
29+
attachThemeHandler("theme-system", "system");
30+
attachThemeHandler("theme-dark", "dark");
31+
</script>

0 commit comments

Comments
 (0)