summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2025-05-23 15:07:50 +0200
committerYuval Adam <_@yuv.al>2025-05-23 15:07:50 +0200
commitf32aa30f2f0722fb659a22ddc57cdf3bd79a4ab5 (patch)
treeaf0031bb0ac0ab7a6c2c4b9d70303b45283ca7c0 /src
parent85bde2d3d69a9f976d3e8ecc9343d1b52a0ec29f (diff)
Add blog pages, content and standardlayout
Diffstat (limited to 'src')
-rw-r--r--src/content/blog/getting-started-with-astro.md48
-rw-r--r--src/content/blog/integrating-react-with-astro.md81
-rw-r--r--src/content/blog/tailwind-css-in-astro.md122
-rw-r--r--src/content/config.ts19
-rw-r--r--src/layouts/StandardLayout.astro51
-rw-r--r--src/pages/blog/[slug].astro67
-rw-r--r--src/pages/blog/index.astro48
-rw-r--r--src/pages/index.astro83
8 files changed, 511 insertions, 8 deletions
diff --git a/src/content/blog/getting-started-with-astro.md b/src/content/blog/getting-started-with-astro.md
new file mode 100644
index 0000000..dadcdcd
--- /dev/null
+++ b/src/content/blog/getting-started-with-astro.md
@@ -0,0 +1,48 @@
+---
+title: "Getting Started with Astro"
+description: "Learn how to build fast websites with Astro's innovative multi-page approach."
+pubDate: 2025-05-20
+image: "https://images.unsplash.com/photo-1614728263952-84ea256f9679?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1200&q=80"
+author: "Astro Developer"
+tags: ["astro", "web development", "javascript"]
+---
+
+# Getting Started with Astro
+
+Astro is a modern web framework that allows you to build faster websites with less client-side JavaScript. It's perfect for content-focused websites like blogs, marketing sites, and portfolios.
+
+## Why Astro?
+
+Astro offers several advantages over traditional frameworks:
+
+- **Performance First**: Astro websites are designed to be lightning-fast by default.
+- **Content-Focused**: Built with content-heavy websites in mind.
+- **Server-First**: Generates HTML on the server, not in the browser.
+- **Easy to Use**: Familiar syntax that combines the best parts of HTML, JSX, and markdown.
+- **Fully Featured**: Includes everything you need for production.
+
+## Basic Example
+
+Here's a simple Astro component:
+
+```astro
+---
+// Your component script goes here
+const greeting = "Hello, Astro!";
+---
+
+<div>
+ <h1>{greeting}</h1>
+ <p>This is my first Astro site.</p>
+</div>
+```
+
+## Next Steps
+
+Ready to dive deeper? Here are some resources to help you on your Astro journey:
+
+1. [Astro Documentation](https://docs.astro.build)
+2. [Astro Discord Community](https://astro.build/chat)
+3. [Astro GitHub Repository](https://github.com/withastro/astro)
+
+Happy coding with Astro!
diff --git a/src/content/blog/integrating-react-with-astro.md b/src/content/blog/integrating-react-with-astro.md
new file mode 100644
index 0000000..b3dee5a
--- /dev/null
+++ b/src/content/blog/integrating-react-with-astro.md
@@ -0,0 +1,81 @@
+---
+title: "Integrating React with Astro"
+description: "Learn how to use React components within your Astro website for interactive UI elements."
+pubDate: 2025-05-21
+image: "https://images.unsplash.com/photo-1633356122102-3fe601e05bd2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1200&q=80"
+author: "React Expert"
+tags: ["astro", "react", "integration", "web development"]
+---
+
+# Integrating React with Astro
+
+Astro allows you to use React components alongside static content, giving you the best of both worlds: the performance of static HTML with the interactivity of React when needed.
+
+## Setting Up React in Astro
+
+First, you'll need to install the React integration:
+
+```bash
+npm install @astrojs/react react react-dom
+```
+
+Then, update your `astro.config.mjs` file:
+
+```javascript
+import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
+
+export default defineConfig({
+ integrations: [react()]
+});
+```
+
+## Creating React Components
+
+Create your React components as you normally would:
+
+```jsx
+// src/components/Counter.jsx
+import { useState } from 'react';
+
+export default function Counter() {
+ const [count, setCount] = useState(0);
+
+ return (
+ <button onClick={() => setCount(count + 1)}>
+ Clicked {count} times
+ </button>
+ );
+}
+```
+
+## Using React Components in Astro
+
+Import and use your React components in Astro files:
+
+```astro
+---
+import Counter from '../components/Counter';
+---
+
+<div>
+ <h1>My Astro Site</h1>
+ <Counter client:load />
+</div>
+```
+
+The `client:load` directive tells Astro to hydrate this component on page load, making it interactive.
+
+## Client Directives
+
+Astro provides several client directives to control when React components are hydrated:
+
+- `client:load`: Hydrate the component on page load
+- `client:idle`: Hydrate when the browser is idle
+- `client:visible`: Hydrate when the component is visible in the viewport
+- `client:media`: Hydrate when a media query is matched
+- `client:only`: Skip server-rendering and only render on the client
+
+## Conclusion
+
+By combining Astro's static-first approach with React's interactivity, you can build fast, responsive websites that provide excellent user experiences without sacrificing developer experience.
diff --git a/src/content/blog/tailwind-css-in-astro.md b/src/content/blog/tailwind-css-in-astro.md
new file mode 100644
index 0000000..ff7bac3
--- /dev/null
+++ b/src/content/blog/tailwind-css-in-astro.md
@@ -0,0 +1,122 @@
+---
+title: "Using Tailwind CSS in Astro"
+description: "Learn how to integrate and use Tailwind CSS to style your Astro website efficiently."
+pubDate: 2025-05-22
+image: "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1200&q=80"
+author: "CSS Enthusiast"
+tags: ["astro", "tailwind", "css", "styling"]
+---
+
+# Using Tailwind CSS in Astro
+
+Tailwind CSS is a utility-first CSS framework that can be seamlessly integrated with Astro to create beautiful, responsive websites without writing custom CSS.
+
+## Setting Up Tailwind in Astro
+
+To get started with Tailwind CSS in your Astro project, you'll need to install the necessary dependencies:
+
+```bash
+npm install -D @tailwindcss/vite tailwindcss
+```
+
+Next, create a configuration file for Tailwind:
+
+```bash
+npx tailwindcss init
+```
+
+Update your `tailwind.config.js` file:
+
+```javascript
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
+```
+
+## Integrating with Astro
+
+Update your `astro.config.mjs` file to use the Tailwind plugin:
+
+```javascript
+import { defineConfig } from 'astro/config';
+import tailwindcss from '@tailwindcss/vite';
+
+export default defineConfig({
+ vite: {
+ plugins: [tailwindcss()]
+ }
+});
+```
+
+Create or update your global CSS file to include Tailwind's directives:
+
+```css
+/* src/styles/global.css */
+@import "tailwindcss";
+```
+
+Import this CSS file in your layout or components:
+
+```astro
+---
+import '../styles/global.css';
+---
+```
+
+## Using Tailwind Classes
+
+Now you can use Tailwind's utility classes directly in your HTML:
+
+```astro
+<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
+ <div class="md:flex">
+ <div class="md:shrink-0">
+ <img class="h-48 w-full object-cover md:h-full md:w-48" src="/img/example.jpg" alt="Example">
+ </div>
+ <div class="p-8">
+ <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Case study</div>
+ <a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">Finding customers for your new business</a>
+ <p class="mt-2 text-slate-500">Getting a new business off the ground is a lot of hard work. Here are five ideas you can use to find your first customers.</p>
+ </div>
+ </div>
+</div>
+```
+
+## Tailwind Typography Plugin
+
+For styling markdown content, the Typography plugin is extremely useful:
+
+```bash
+npm install -D @tailwindcss/typography
+```
+
+Add it to your Tailwind config:
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ // ...
+ plugins: [
+ require('@tailwindcss/typography'),
+ // ...
+ ],
+}
+```
+
+Then use the `prose` class on your markdown content:
+
+```astro
+<article class="prose lg:prose-xl">
+ <!-- Your markdown content will be styled nicely -->
+ <slot />
+</article>
+```
+
+## Conclusion
+
+Tailwind CSS provides a powerful and efficient way to style your Astro website. With its utility-first approach, you can rapidly build custom designs without leaving your HTML or writing custom CSS.
diff --git a/src/content/config.ts b/src/content/config.ts
new file mode 100644
index 0000000..43a44ad
--- /dev/null
+++ b/src/content/config.ts
@@ -0,0 +1,19 @@
+import { defineCollection, z } from 'astro:content';
+
+// Define the blog collection schema
+const blogCollection = defineCollection({
+ type: 'content',
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ pubDate: z.date(),
+ image: z.string().optional(),
+ author: z.string().default('Anonymous'),
+ tags: z.array(z.string()).default([]),
+ }),
+});
+
+// Export the collections
+export const collections = {
+ 'blog': blogCollection,
+};
diff --git a/src/layouts/StandardLayout.astro b/src/layouts/StandardLayout.astro
new file mode 100644
index 0000000..a6c9151
--- /dev/null
+++ b/src/layouts/StandardLayout.astro
@@ -0,0 +1,51 @@
+---
+import '../styles/global.css';
+
+interface Props {
+ title?: string;
+ description?: string;
+}
+
+const {
+ title = "Astro Site",
+ description = "A simple Astro site with blog functionality"
+} = Astro.props;
+---
+
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+ <meta name="viewport" content="width=device-width" />
+ <meta name="generator" content={Astro.generator} />
+ <meta name="description" content={description} />
+ <title>{title}</title>
+ </head>
+ <body class="min-h-screen bg-gray-50 flex flex-col">
+ <header class="bg-white shadow-sm">
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
+ <nav class="flex justify-between items-center">
+ <a href="/" class="text-xl font-bold text-gray-900">Astro Blog</a>
+ <div class="flex space-x-6">
+ <a href="/" class="text-gray-700 hover:text-blue-600">Home</a>
+ <a href="/blog" class="text-gray-700 hover:text-blue-600">Blog</a>
+ </div>
+ </nav>
+ </div>
+ </header>
+
+ <main class="flex-grow">
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
+ <slot />
+ </div>
+ </main>
+
+ <footer class="bg-white border-t border-gray-200">
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
+ <p class="text-center text-gray-500 text-sm">
+ &copy; {new Date().getFullYear()} Astro Blog. All rights reserved.
+ </p>
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro
new file mode 100644
index 0000000..f42f5c9
--- /dev/null
+++ b/src/pages/blog/[slug].astro
@@ -0,0 +1,67 @@
+---
+import { getCollection, getEntry } from 'astro:content';
+import StandardLayout from '../../layouts/StandardLayout.astro';
+
+// Define the props type
+export async function getStaticPaths() {
+ const blogEntries = await getCollection('blog');
+ return blogEntries.map(entry => ({
+ params: { slug: entry.slug },
+ props: { entry },
+ }));
+}
+
+// Get the blog post data
+const { entry } = Astro.props;
+const { Content } = await entry.render();
+
+// Format the publication date
+const formattedDate = new Date(entry.data.pubDate).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+});
+---
+
+<StandardLayout title={entry.data.title} description={entry.data.description}>
+ <article class="max-w-3xl mx-auto">
+ <div class="mb-8">
+ <a href="/blog" class="text-blue-600 hover:text-blue-800 flex items-center">
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
+ <path fill-rule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clip-rule="evenodd" />
+ </svg>
+ Back to Blog
+ </a>
+ </div>
+
+ {entry.data.image && (
+ <img
+ src={entry.data.image}
+ alt={entry.data.title}
+ class="w-full h-64 md:h-96 object-cover rounded-lg shadow-md mb-8"
+ />
+ )}
+
+ <h1 class="text-4xl font-bold text-gray-900 mb-4">{entry.data.title}</h1>
+
+ <div class="flex items-center text-gray-600 mb-8">
+ <span>By {entry.data.author}</span>
+ <span class="mx-2">•</span>
+ <time datetime={entry.data.pubDate.toISOString()}>{formattedDate}</time>
+ </div>
+
+ {entry.data.tags && entry.data.tags.length > 0 && (
+ <div class="flex flex-wrap gap-2 mb-8">
+ {entry.data.tags.map(tag => (
+ <span class="bg-gray-100 text-gray-800 text-sm font-medium px-3 py-1 rounded-full">
+ {tag}
+ </span>
+ ))}
+ </div>
+ )}
+
+ <div class="prose prose-lg max-w-none">
+ <Content />
+ </div>
+ </article>
+</StandardLayout>
diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro
new file mode 100644
index 0000000..76b9f57
--- /dev/null
+++ b/src/pages/blog/index.astro
@@ -0,0 +1,48 @@
+---
+import StandardLayout from '../../layouts/StandardLayout.astro';
+import { getCollection } from 'astro:content';
+
+// Get all blog posts sorted by publication date
+const posts = await getCollection('blog');
+posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
+---
+
+<StandardLayout title="Blog | Astro Site" description="Read our latest blog posts">
+ <div class="space-y-8">
+ <h1 class="text-3xl font-bold text-gray-900">Blog</h1>
+
+ <div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
+ {posts.map((post) => (
+ <article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
+ <a href={`/blog/${post.slug}`} class="block">
+ {post.data.image && (
+ <img
+ src={post.data.image}
+ alt={post.data.title}
+ class="w-full h-48 object-cover"
+ />
+ )}
+ <div class="p-6">
+ <h2 class="text-xl font-semibold text-gray-900 mb-2">{post.data.title}</h2>
+ <p class="text-sm text-gray-500 mb-3">
+ {new Date(post.data.pubDate).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ })}
+ </p>
+ <p class="text-gray-700">{post.data.description}</p>
+ <p class="mt-4 text-blue-600 font-medium">Read more →</p>
+ </div>
+ </a>
+ </article>
+ ))}
+ </div>
+
+ {posts.length === 0 && (
+ <div class="bg-white rounded-lg shadow p-6 text-center">
+ <p class="text-gray-700">No blog posts found. Check back soon!</p>
+ </div>
+ )}
+ </div>
+</StandardLayout>
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 22adfcf..a88712c 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,11 +1,78 @@
---
-import Counter from '../components/Counter';
-import CenteredLayout from '../layouts/CenteredLayout.astro';
+import Counter from "../components/Counter";
+import StandardLayout from "../layouts/StandardLayout.astro";
+import { getCollection } from "astro:content";
+
+// Get the latest 3 blog posts
+const latestPosts = await getCollection("blog");
+latestPosts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
+const featuredPosts = latestPosts.slice(0, 3);
---
-<CenteredLayout title="Astro">
- <div class="text-center">
- <h1 class="text-4xl font-bold mb-6">Astro</h1>
- <Counter client:load />
- </div>
-</CenteredLayout>
+<StandardLayout title="Astro - Home">
+ <section class="py-12">
+ <div class="text-center mb-12">
+ <h1 class="text-5xl font-bold text-gray-900 mb-4">
+ Welcome to Astro
+ </h1>
+ <p class="text-xl text-gray-600 max-w-3xl mx-auto">
+ A modern framework for building fast, content-focused websites.
+ </p>
+ <div class="mt-8">
+ <Counter client:load />
+ </div>
+ </div>
+ </section>
+
+ <section
+ class="py-12 bg-gray-50 -mx-4 sm:-mx-6 lg:-mx-8 px-4 sm:px-6 lg:px-8"
+ >
+ <div class="max-w-7xl mx-auto">
+ <div class="flex justify-between items-center mb-8">
+ <h2 class="text-3xl font-bold text-gray-900">
+ Latest Blog Posts
+ </h2>
+ <a
+ href="/blog"
+ class="text-blue-600 hover:text-blue-800 font-medium"
+ >View all posts →</a
+ >
+ </div>
+
+ <div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
+ {
+ featuredPosts.map((post) => (
+ <article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
+ <a href={`/blog/${post.slug}`} class="block">
+ {post.data.image && (
+ <img
+ src={post.data.image}
+ alt={post.data.title}
+ class="w-full h-48 object-cover"
+ />
+ )}
+ <div class="p-6">
+ <h3 class="text-xl font-semibold text-gray-900 mb-2">
+ {post.data.title}
+ </h3>
+ <p class="text-sm text-gray-500 mb-3">
+ {new Date(
+ post.data.pubDate,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })}
+ </p>
+ <p class="text-gray-700">
+ {post.data.description}
+ </p>
+ </div>
+ </a>
+ </article>
+ ))
+ }
+ </div>
+ </div>
+ </section>
+</StandardLayout>