- ✔
pnpm create astro@latest - ✔ Answer: recommended+Typescript/strict+Git
- ✔ VsCode : extension Astro
- pages : Astro components or React, Vue, ...
- Layout: common parts nav menu, Header
- Components
- Public: static assets
Clean all files or empty project
pages/index.astro
---
// Front matter
// Add JS
const name = "Astro";
const colorPurple = "purple";
const users = [ 'Astro', "Brad", "John", "Clint" ]
const visible = true; // false
// Fetch
const response = await fetch('https://jsonplaceholder.typicode.com/users?_limit=10');
const users2 = await response.json()
---
<!-- JS expression in {} -->
<h1 class={colorPurple}>Hello {name}: { 1 + 2 }</h1>
<!-- Array map -->
<ul>
{ users.map( user => <li>{user}</li>) }
</ul>
<!-- Array fetched map -->
<ul>
{ users2.map( user => <li>{user.name}</li>) }
</ul>
<!-- Condition -->
{ visible && <p>I'm visible!</p>}
<!-- Scoped styling -->
<style>
h1 { color:red }
.purple { color:blueviolet }
</style>layouts/Layout.astro
---
import '../styles/global.css' // CSS
export interface Props {
title ?: string; // optional
}
const { title = "Astro test"} = Astro.props as Props
---
<!DOCTYPE html>
<html lang="en">
<head><title>{title}</title></head>
<body></body>
<html>pages/index.astro
---
import Layout from '../layouts/Layout.astro'
---
<Layout title="Home Page">
<h1>Hello</h1>
<Layout>---
import logo from '../img/logo.svg'
---
<header class="header">
<div class="container">
<div class="logo">
<a href="index.html">
<img src={logo} alt="" />
</a>
</div>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</div>
</header>
<style>
.header {
height: 70px;
background: var(--color-primary);
}
.header .container {
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
}
.header img {
height: 35px;
vertical-align: middle;
}
.header nav ul {
display: flex;
}
</style>pnpm astro add reactCreate a component, import it with .jsx or .tsx
components/Features.astro
---
import Card from "./Card.astro";
const data = [
{ title: 'Astro', body: 'Lorem ipsum ...'},
{ title: 'Hugo', body: 'Nulla lacus ...'},
{ title: 'React', body: 'Morbi commodo ...'},
]
---
<section class="features">
<div class="container">
{ data.map( feature => (
<Card dark={true} title={feature.title} body={feature.body} />
))}
</div>
</section>
<style>
.features .container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px;
}
@media (max-width: 500px) {
.features .container {
grid-template-columns: 1fr;
}
}
</style>components/Card.astro
---
export interface Props {
title: string,
body: string,
dark ?: boolean
}
const { title, body, dark = false } = Astro.props as Props
---
<div class={`card ${dark && 'dark'}`}>
<h3>{title}</h3>
<p>{body}</p>
</div>
<style>
.card { }
.dark { }
</style>use data in Props
<Tabs headings={['NPM', 'PNPM', 'YARN']} contents={['$ npm create astro@latest', '$ pnpm create astro@latest', '$ yarn create astro']} />Downside: the JS script acts on all the page, not the component
---
const activeColor = "red"
---
<p>Hello</p>
<script define:vars={{activeColor}}>
document.querySelector('p').style.color=activeColor;
</script>Content : posts/test1.md
---
title: Test 1.0
slug: test1
excerpt: Lorem ipsum dolor sit amet ...
date: 2022-05-13
author: John Doe
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur quis porttitor mauris. Sed quis nulla malesuada, imperdiet ipsum eleifend, pharetra lacus. Maecenas vehicula tincidunt lorem sed elementum. Vestibulum luctus ...List of posts : pages/blog.astro glob + frontmatter object + slug
---
import Layout from '../layouts/Layout.astro';
const posts = await Astro.glob('../posts/*.md');
---
<Layout title="Astro Blog">
<div class="container">
{posts.map(post => (
<article>
<h3>{post.frontmatter.title}</h3>
<p>{post.frontmatter.excerpt}</p>
<a class="btn" href={`/${post.frontmatter.slug}`}>Read More</a>
</article>
))}
</div>
</Layout>Slug: pages/[slug].astro
---
import Layout from '../layouts/Layout.astro';
export async function getStaticPaths() {
const posts = await Astro.glob('../posts/*.md');
return posts.map(post => ({
params: {
slug: post.frontmatter.slug
},
props: {
post
}
}));
}
const { Content, frontmatter } = Astro.props.post;
---
<Layout title={frontmatter.title}>
<section class="page-content">
<div class="container">
<article>
<a class="btn" href="/blog">Go Back</a>
<h2>{frontmatter.title}</h2>
<div>
Written by <strong>{frontmatter.author} </strong> on {new Date(frontmatter.date).toLocaleDateString()}
</div>
<Content />
</article>
</div>
</section>
</Layout>