diff options
| -rw-r--r-- | src/content/blog/getting-started-with-astro.md | 48 | ||||
| -rw-r--r-- | src/content/blog/integrating-react-with-astro.md | 81 | ||||
| -rw-r--r-- | src/content/blog/tailwind-css-in-astro.md | 122 | ||||
| -rw-r--r-- | src/content/config.ts | 19 | ||||
| -rw-r--r-- | src/layouts/StandardLayout.astro | 51 | ||||
| -rw-r--r-- | src/pages/blog/[slug].astro | 67 | ||||
| -rw-r--r-- | src/pages/blog/index.astro | 48 | ||||
| -rw-r--r-- | src/pages/index.astro | 83 |
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"> + © {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> |
