Skip to content

Commit e40b085

Browse files
committed
Add blog with Astro content collections and first post
- Set up content collection for markdown blog posts (category: acquisition/product/insights) - Add blog listing page and individual post pages with styled typography - Add IconBuddy acquisition announcement as first post - Add Blog link to header and footer navigation
1 parent a9ab74b commit e40b085

6 files changed

Lines changed: 434 additions & 1 deletion

File tree

src/components/Footer.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<div class="footer-content">
66
<span>© 2025 <a href="https://simplebytes.com">Simple Bytes</a>, a <a href="https://meome.com/?ref=simplebytes" target="_blank" rel="noopener">Meome</a> company</span>
77
<nav class="footer-links">
8+
<a href="/blog">Blog</a>
89
<a href="/contact">Contact</a>
910
<a href="/privacy">Privacy</a>
1011
<a href="/terms">Terms</a>

src/components/Header.astro

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
<a href="/" class="logo-link" aria-label="Simple Bytes Home">
66
<img src="/svg/logo.svg" alt="Simple Bytes" class="logo">
77
</a>
8-
<button class="theme-toggle" role="switch" aria-checked="false" aria-label="Toggle dark mode"></button>
8+
<div class="header-right">
9+
<a href="/blog" class="header-link">Blog</a>
10+
<button class="theme-toggle" role="switch" aria-checked="false" aria-label="Toggle dark mode"></button>
11+
</div>
912
</header>
1013

1114
<style>
@@ -31,6 +34,23 @@
3134
filter: invert(1);
3235
}
3336

37+
.header-right {
38+
display: flex;
39+
align-items: center;
40+
gap: 1rem;
41+
}
42+
43+
.header-link {
44+
font-size: 0.875rem;
45+
color: var(--text-secondary);
46+
text-decoration: none;
47+
transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
48+
}
49+
50+
.header-link:hover {
51+
color: var(--text-primary);
52+
}
53+
3454
.theme-toggle {
3555
appearance: none;
3656
position: relative;

src/content.config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { defineCollection, z } from 'astro:content';
2+
import { glob } from 'astro/loaders';
3+
4+
const blog = defineCollection({
5+
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
6+
schema: z.object({
7+
title: z.string(),
8+
description: z.string(),
9+
date: z.string(),
10+
category: z.enum(['acquisition', 'product', 'insights']),
11+
}),
12+
});
13+
14+
export const collections = { blog };
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: "Simple Bytes Acquires IconBuddy"
3+
description: "We've acquired IconBuddy.com — the search engine for 500K+ open-source icons — as a strategic addition to our portfolio."
4+
date: "2026-03-15"
5+
category: "acquisition"
6+
---
7+
8+
We're excited to announce that Simple Bytes has acquired [IconBuddy.com](https://www.iconbuddy.com), the popular open-source icon search engine used by over 500,000 professionals worldwide.
9+
10+
## What is IconBuddy?
11+
12+
IconBuddy is a unified search engine and management platform for open-source icons. It provides access to over 500,000 icons across 300+ icon sets — including Material Symbols, Fluent UI, Phosphor, Solar, and many more — all searchable from a single interface.
13+
14+
The platform also offers editing tools, multiple export formats (SVG, PNG, JSX, Vue), and integrations for Figma, VS Code, Framer, WordPress, and Chrome.
15+
16+
## Why IconBuddy?
17+
18+
IconBuddy fits perfectly into our mission of building tiny, easy-to-use tools for better productivity. Designers and developers spend too much time hunting for the right icon across dozens of different libraries. IconBuddy solves that with fast, unified search powered by Algolia.
19+
20+
It's the kind of tool we love at Simple Bytes: focused, useful, and respectful of your time.
21+
22+
## What's Next
23+
24+
IconBuddy will continue to operate independently at [iconbuddy.com](https://www.iconbuddy.com). We're planning to invest in performance improvements, expanded icon set coverage, and new integrations over the coming months.
25+
26+
We're thrilled to welcome IconBuddy to the Simple Bytes family.

src/pages/blog/[slug].astro

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
import BaseLayout from '../../layouts/BaseLayout.astro';
3+
import { getCollection, render } from 'astro:content';
4+
5+
export async function getStaticPaths() {
6+
const posts = await getCollection('blog');
7+
return posts.map((post) => ({
8+
params: { slug: post.id },
9+
props: { post },
10+
}));
11+
}
12+
13+
const { post } = Astro.props;
14+
const { Content } = await render(post);
15+
16+
const categoryLabels: Record<string, string> = {
17+
acquisition: 'Acquisition',
18+
product: 'Product',
19+
insights: 'Insights',
20+
};
21+
22+
function formatDate(dateStr: string) {
23+
return new Date(dateStr).toLocaleDateString('en-US', {
24+
year: 'numeric',
25+
month: 'long',
26+
day: 'numeric',
27+
});
28+
}
29+
---
30+
31+
<BaseLayout
32+
title={`${post.data.title} - Simple Bytes`}
33+
description={post.data.description}
34+
>
35+
<a href="/blog" class="back-link">← Back to blog</a>
36+
37+
<article class="post">
38+
<header class="post-header">
39+
<div class="post-meta">
40+
<span class="post-category">{categoryLabels[post.data.category] || post.data.category}</span>
41+
<span class="post-date">{formatDate(post.data.date)}</span>
42+
</div>
43+
<h1>{post.data.title}</h1>
44+
<p class="post-description">{post.data.description}</p>
45+
</header>
46+
47+
<div class="post-content">
48+
<Content />
49+
</div>
50+
</article>
51+
</BaseLayout>
52+
53+
<style>
54+
.back-link {
55+
display: inline-flex;
56+
align-items: center;
57+
gap: 0.5rem;
58+
font-size: 0.875rem;
59+
color: var(--text-secondary);
60+
text-decoration: none;
61+
margin-bottom: 2rem;
62+
transition: color 0.2s;
63+
}
64+
65+
.back-link:hover {
66+
color: var(--text-primary);
67+
}
68+
69+
.post {
70+
max-width: 680px;
71+
}
72+
73+
.post-header {
74+
margin-bottom: 3rem;
75+
}
76+
77+
.post-meta {
78+
display: flex;
79+
align-items: center;
80+
gap: 0.75rem;
81+
margin-bottom: 1rem;
82+
}
83+
84+
.post-category {
85+
font-size: 0.75rem;
86+
font-weight: 500;
87+
text-transform: uppercase;
88+
letter-spacing: 0.05em;
89+
color: var(--accent);
90+
background: var(--accent-subtle);
91+
padding: 0.2rem 0.5rem;
92+
border-radius: var(--radius-sm);
93+
}
94+
95+
.post-date {
96+
font-size: 0.8125rem;
97+
color: var(--text-tertiary);
98+
}
99+
100+
h1 {
101+
font-size: clamp(2rem, 5vw, 2.75rem);
102+
font-weight: 600;
103+
letter-spacing: -0.03em;
104+
line-height: 1.2;
105+
margin-bottom: 1rem;
106+
}
107+
108+
.post-description {
109+
font-size: 1.125rem;
110+
color: var(--text-secondary);
111+
line-height: 1.6;
112+
}
113+
114+
.post-content {
115+
font-size: 1.0625rem;
116+
line-height: 1.8;
117+
color: var(--text-primary);
118+
}
119+
120+
.post-content :global(h2) {
121+
font-size: 1.375rem;
122+
font-weight: 600;
123+
margin-top: 2.5rem;
124+
margin-bottom: 1rem;
125+
letter-spacing: -0.02em;
126+
}
127+
128+
.post-content :global(h3) {
129+
font-size: 1.125rem;
130+
font-weight: 600;
131+
margin-top: 2rem;
132+
margin-bottom: 0.75rem;
133+
}
134+
135+
.post-content :global(p) {
136+
margin-bottom: 1.25rem;
137+
}
138+
139+
.post-content :global(a) {
140+
color: var(--accent);
141+
text-decoration: underline;
142+
text-underline-offset: 2px;
143+
transition: opacity 0.2s;
144+
}
145+
146+
.post-content :global(a:hover) {
147+
opacity: 0.7;
148+
}
149+
150+
.post-content :global(ul),
151+
.post-content :global(ol) {
152+
margin-bottom: 1.25rem;
153+
padding-left: 1.5rem;
154+
}
155+
156+
.post-content :global(li) {
157+
margin-bottom: 0.5rem;
158+
}
159+
160+
.post-content :global(blockquote) {
161+
border-left: 3px solid var(--border-color);
162+
padding-left: 1.25rem;
163+
margin: 1.5rem 0;
164+
color: var(--text-secondary);
165+
font-style: italic;
166+
}
167+
168+
.post-content :global(code) {
169+
font-family: var(--font-mono);
170+
font-size: 0.9em;
171+
background: var(--accent-subtle);
172+
padding: 0.15rem 0.35rem;
173+
border-radius: var(--radius-sm);
174+
}
175+
176+
.post-content :global(pre) {
177+
background: var(--bg-secondary);
178+
border: 1px solid var(--border-color);
179+
border-radius: var(--radius-md);
180+
padding: 1.25rem;
181+
overflow-x: auto;
182+
margin-bottom: 1.25rem;
183+
}
184+
185+
.post-content :global(pre code) {
186+
background: none;
187+
padding: 0;
188+
}
189+
190+
.post-content :global(img) {
191+
max-width: 100%;
192+
border-radius: var(--radius-md);
193+
margin: 1.5rem 0;
194+
}
195+
196+
.post-content :global(hr) {
197+
border: none;
198+
border-top: 1px solid var(--border-color);
199+
margin: 2rem 0;
200+
}
201+
202+
@media (max-width: 768px) {
203+
h1 {
204+
font-size: 1.75rem;
205+
}
206+
207+
.post-description {
208+
font-size: 1rem;
209+
}
210+
211+
.post-content {
212+
font-size: 1rem;
213+
}
214+
}
215+
</style>

0 commit comments

Comments
 (0)