Skip to content

Commit 0561324

Browse files
committed
Add website to root folder
1 parent 5936bd8 commit 0561324

8 files changed

Lines changed: 117 additions & 29 deletions

File tree

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# ivikramsahu.github.io
2+
3+
Personal blog built with **Astro** + **Tailwind CSS**, deployed to **GitHub Pages** via **GitHub Actions**.
4+
5+
## Why this blog exists
6+
This site is designed to be fast, readable, and fun:
7+
8+
- **Writing-first**
9+
Posts are authored as content entries and rendered as static pages for great performance.
10+
- **A little delight**
11+
The sidebar includes a **Quotes** widget and a small **Snakes & Ladders** game to keep the experience light and interactive while still staying out of the way of reading.
12+
13+
## Features
14+
- **Astro static rendering** for speed and SEO.
15+
- **Tailwind CSS** for consistent styling.
16+
- **Sticky header** with a **theme toggle** (light/dark).
17+
- **Blog listing + pagination** (`/page/[page]/`).
18+
- **Post pages** (`/blog/[...slug]/`) with clean typography.
19+
- **Quotes widget**
20+
Rotates quotes and refreshes periodically.
21+
- **Snakes & Ladders**
22+
A small two-player (You vs Computer) mini-game with state persistence, move logs, and win/lose effects.
23+
24+
## Why the Quotes widget?
25+
The quotes panel is meant to add a small “focus boost” while browsing posts:
26+
27+
- A quick line of motivation or perspective
28+
- Refreshes automatically (and also changes on reload)
29+
- Lives in the sidebar so it doesn’t distract from reading
30+
31+
Implementation lives in `src/components/QuotesWidget.astro`.
32+
33+
## Why the Snakes & Ladders game?
34+
The game is intentionally simple and optional:
35+
36+
- Adds a playful element to the homepage/listing pages
37+
- Encourages exploration (without affecting core reading UX)
38+
- Runs fully client-side and doesn’t require any backend
39+
40+
Implementation lives in `src/components/SnakesAndLadders.astro`.
41+
42+
## Tech stack
43+
- **Astro** (site framework)
44+
- **Tailwind CSS** (styling)
45+
- **GitHub Pages** + **GitHub Actions** (deployment)
46+
47+
## Project structure (high level)
48+
- `src/layouts/BaseLayout.astro`
49+
Shared layout, header/nav, theme toggle.
50+
- `src/pages/index.astro`
51+
Homepage blog list + sidebar.
52+
- `src/pages/page/[page].astro`
53+
Paginated blog list pages.
54+
- `src/pages/blog/[...slug].astro`
55+
Individual blog post pages.
56+
- `src/pages/about.astro`
57+
About page.
58+
- `src/components/QuotesWidget.astro`
59+
Quotes sidebar widget.
60+
- `src/components/SnakesAndLadders.astro`
61+
Snakes & Ladders game.
62+
- `src/styles/global.css`
63+
Global styles + typography tweaks.
64+
- `.github/workflows/deploy.yml`
65+
GitHub Actions workflow that builds and deploys the static output.
66+
67+
## Running locally
68+
Prerequisites:
69+
- Node.js (LTS recommended)
70+
- npm
71+
72+
Commands:
73+
74+
```bash
75+
npm install
76+
npm run dev
77+
```
78+
79+
Astro will print the local dev URL (typically `http://localhost:4321`).
80+
81+
## Build
82+
```bash
83+
npm run build
84+
npm run preview
85+
```
86+
87+
## Deployment (GitHub Pages)
88+
This repo is intended to be deployed as a **user site**:
89+
90+
- Repo name: `ivikramsahu.github.io`
91+
- URL: `https://ivikramsahu.github.io/`
92+
93+
Notes:
94+
- Deployment is done via **GitHub Actions** (see `.github/workflows/deploy.yml`).
95+
- In GitHub settings, ensure:
96+
- **Settings → Pages → Source = GitHub Actions**
97+
- Not “Deploy from a branch” (that can trigger Jekyll on source files).
98+
99+
## Content notes
100+
If you imported content from another platform, helper scripts may live under `scripts/` (for example `scripts/import-hashnode.mjs`). These scripts are optional and not required to run the site.

astro.config.mjs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { defineConfig } from 'astro/config';
22
import tailwind from '@astrojs/tailwind';
33

44
export default defineConfig({
5-
site: 'https://ivikramsahu.github.io/vikramsahu-blog',
6-
base: '/vikramsahu-blog',
5+
site: 'https://ivikramsahu.github.io',
76
trailingSlash: 'always',
87
integrations: [
98
tailwind({

src/layouts/BaseLayout.astro

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ type Props = {
88
};
99
1010
const { title, description, containerClass = 'max-w-6xl' } = Astro.props;
11-
const base = import.meta.env.BASE_URL;
1211
const siteName = "Vikram's Focushours";
1312
const metaTitle = title ? `${title} | ${siteName}` : siteName;
1413
const metaDescription = description ?? 'Writing and notes.';
@@ -110,9 +109,9 @@ const metaDescription = description ?? 'Writing and notes.';
110109
})();
111110
</script>
112111

113-
<link rel="icon" href={`${base}favicon.svg`} type="image/svg+xml" sizes="any" />
114-
<link rel="shortcut icon" href={`${base}favicon.svg`} />
115-
<link rel="apple-touch-icon" href={`${base}favicon.svg`} />
112+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" sizes="any" />
113+
<link rel="shortcut icon" href="/favicon.svg" />
114+
<link rel="apple-touch-icon" href="/favicon.svg" />
116115

117116
<link rel="preconnect" href="https://fonts.googleapis.com" />
118117
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -122,29 +121,28 @@ const metaDescription = description ?? 'Writing and notes.';
122121
/>
123122

124123
<title>{metaTitle}</title>
125-
<style is:inline>{`:root{--base-url:${base};}`}</style>
126124
</head>
127125
<body class="min-h-screen font-sans flex flex-col bg-zinc-50 text-zinc-900 transition-colors duration-300 dark:bg-zinc-950 dark:text-zinc-50">
128126
<header class="sticky top-0 z-50 border-b border-zinc-200 bg-white/70 backdrop-blur transition-colors duration-300 dark:border-zinc-800 dark:bg-zinc-950/70">
129127
<div class={`mx-auto flex ${containerClass} flex-wrap items-center justify-between gap-4 px-4 py-4`}>
130-
<a href={base} class="flex min-w-0 items-center gap-3 no-underline">
128+
<a href="/" class="flex min-w-0 items-center gap-3 no-underline">
131129
<picture>
132-
<source srcset={`${base}mascot.png`} type="image/png" />
133-
<img src={`${base}mascot.svg`} alt="Vikram mascot" class="h-[75px] w-[75px]" />
130+
<source srcset="/mascot.png" type="image/png" />
131+
<img src="/mascot.svg" alt="Vikram mascot" class="h-[75px] w-[75px]" />
134132
</picture>
135133
<span class="truncate text-[32px] leading-none font-semibold tracking-tight text-black dark:text-zinc-50">
136134
{siteName}
137135
</span>
138136
</a>
139137
<nav class="flex shrink-0 items-center gap-4 text-sm">
140138
<a
141-
href={base}
139+
href="/"
142140
class="no-underline text-zinc-700 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-white"
143141
>
144142
Blog
145143
</a>
146144
<a
147-
href={`${base}about/`}
145+
href="/about/"
148146
class="no-underline text-zinc-700 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-white"
149147
>
150148
About

src/pages/about.astro

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
import BaseLayout from '../layouts/BaseLayout.astro';
3-
const base = import.meta.env.BASE_URL;
43
---
54

65
<BaseLayout title="About" description="About this site." containerClass="max-w-6xl">
@@ -9,7 +8,7 @@ const base = import.meta.env.BASE_URL;
98

109
<div class="not-prose my-6">
1110
<img
12-
src={`${base}about.png`}
11+
src="/about.png"
1312
alt="Vikram Sahu"
1413
class="w-full rounded-2xl border border-zinc-200 shadow-sm dark:border-zinc-800"
1514
loading="lazy"

src/pages/blog/[...slug].astro

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
import BaseLayout from '../../layouts/BaseLayout.astro';
33
import { getCollection } from 'astro:content';
4-
const base = import.meta.env.BASE_URL;
54
65
export async function getStaticPaths() {
76
const posts = (await getCollection('blog')).filter((p) => !p.data.draft);
@@ -80,7 +79,7 @@ function renderInlineCode(input: string) {
8079
<article class="prose prose-zinc prose-lg dark:prose-invert max-w-none">
8180
<div class="not-prose mb-8 space-y-3">
8281
<a
83-
href={base}
82+
href="/"
8483
class="text-sm text-zinc-600 no-underline hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
8584
>
8685
← Back

src/pages/index.astro

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import BaseLayout from '../layouts/BaseLayout.astro';
33
import { getCollection } from 'astro:content';
44
import SnakesAndLadders from '../components/SnakesAndLadders.astro';
55
import QuotesWidget from '../components/QuotesWidget.astro';
6-
const base = import.meta.env.BASE_URL;
76
87
const posts = (await getCollection('blog'))
98
.filter((p) => !p.data.draft)
@@ -80,7 +79,7 @@ function renderInlineCode(input: string) {
8079

8180
return (
8281
<a
83-
href={`${base}blog/${post.slug}/`}
82+
href={`/blog/${post.slug}/`}
8483
class="block p-[30px] no-underline hover:bg-zinc-50 dark:hover:bg-zinc-800"
8584
>
8685
<div class="space-y-4">
@@ -162,7 +161,7 @@ function renderInlineCode(input: string) {
162161
Prev
163162
</span>
164163
<a
165-
href={`${base}page/2/`}
164+
href="/page/2/"
166165
class="rounded-lg border border-zinc-200 px-3 py-2 text-sm text-zinc-700 no-underline hover:bg-zinc-50 dark:border-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-900"
167166
>
168167
Next

src/pages/page/[page].astro

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { getCollection } from 'astro:content';
44
import SnakesAndLadders from '../../components/SnakesAndLadders.astro';
55
import QuotesWidget from '../../components/QuotesWidget.astro';
66
7-
const base = import.meta.env.BASE_URL;
8-
97
const pageSize = 10;
108
119
export async function getStaticPaths() {
@@ -37,12 +35,8 @@ const start = (currentPage - 1) * pageSize;
3735
const pagePosts = posts.slice(start, start + pageSize);
3836
3937
const prevHref =
40-
currentPage <= 1
41-
? null
42-
: currentPage === 2
43-
? base
44-
: `${base}page/${currentPage - 1}/`;
45-
const nextHref = currentPage >= totalPages ? null : `${base}page/${currentPage + 1}/`;
38+
currentPage <= 1 ? null : currentPage === 2 ? '/' : `/page/${currentPage - 1}/`;
39+
const nextHref = currentPage >= totalPages ? null : `/page/${currentPage + 1}/`;
4640
4741
function estimateReadTimeMinutes(text: string) {
4842
const words = text.split(/\s+/).filter(Boolean).length;
@@ -110,7 +104,7 @@ function renderInlineCode(input: string) {
110104

111105
return (
112106
<a
113-
href={`${base}blog/${post.slug}/`}
107+
href={`/blog/${post.slug}/`}
114108
class="block p-[30px] no-underline hover:bg-zinc-50 dark:hover:bg-zinc-800"
115109
>
116110
<div class="space-y-4">

src/styles/global.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
@font-face {
66
font-family: 'Agave';
7-
src: url('/vikramsahu-blog/font/Agave-Regular.ttf') format('truetype');
7+
src: url('/font/Agave-Regular.ttf') format('truetype');
88
font-weight: 400;
99
font-style: normal;
1010
font-display: swap;

0 commit comments

Comments
 (0)