├── src
├── components
│ ├── BlogPost.astro
│ ├── Menu.astro
│ ├── Navigation.astro
│ ├── Social.astro
│ ├── Footer.astro
│ ├── Header.astro
│ ├── Greeting.jsx
│ └── ThemeIcon.astro
├── scripts
│ └── menu.js
├── pages
│ ├── index.astro
│ ├── rss.xml.js
│ ├── blog.astro
│ ├── posts
│ │ ├── post-4.md
│ │ ├── post-2.md
│ │ ├── post-3.md
│ │ └── post-1.md
│ ├── tags
│ │ ├── index.astro
│ │ └── [tag].astro
│ └── about.astro
├── layouts
│ ├── BaseLayout.astro
│ └── MarkdownPostLayout.astro
└── styles
│ └── global.css
├── .vscode
├── extensions.json
└── launch.json
├── sandbox.config.json
├── astro.config.mjs
├── tsconfig.json
├── .gitignore
├── package.json
├── README.md
├── public
└── favicon.svg
└── LICENSE
/src/components/BlogPost.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title, url } = Astro.props
3 | ---
4 |
{title}
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/Menu.astro:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 |
7 |
--------------------------------------------------------------------------------
/src/components/Navigation.astro:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 |
Home
5 |
About
6 |
Blog
7 |
Tags
8 |
9 |
--------------------------------------------------------------------------------
/src/scripts/menu.js:
--------------------------------------------------------------------------------
1 | const menu = document.querySelector('.menu')
2 |
3 | menu?.addEventListener("click", () => {
4 | const isExpanded = menu.getAttribute("aria-expanded") === "true";
5 | menu.setAttribute("aria-expanded", `${!isExpanded}`);
6 | });
7 |
--------------------------------------------------------------------------------
/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": false,
4 | "view": "browser",
5 | "template": "node",
6 | "container": {
7 | "port": 3000,
8 | "startScript": "start",
9 | "node": "14"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/astro.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import { defineConfig } from "astro/config";
3 |
4 | import preact from "@astrojs/preact";
5 |
6 | // https://astro.build/config
7 | export default defineConfig({
8 | site: "https://example.com",
9 | integrations: [preact()],
10 | });
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict",
3 | "include": [
4 | ".astro/types.d.ts",
5 | "**/*"
6 | ],
7 | "exclude": [
8 | "dist"
9 | ],
10 | "compilerOptions": {
11 | "jsx": "react-jsx",
12 | "jsxImportSource": "preact"
13 | }
14 | }
--------------------------------------------------------------------------------
/src/components/Social.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { platform, username } = Astro.props;
3 | ---
4 | {platform}
5 |
6 |
14 |
--------------------------------------------------------------------------------
/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from '../layouts/BaseLayout.astro';
3 | import Greeting from '../components/Greeting';
4 | const pageTitle = "Home Page";
5 | ---
6 |
7 | My awesome blog subtitle
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
23 | # jetbrains setting folder
24 | .idea/
25 |
--------------------------------------------------------------------------------
/src/pages/rss.xml.js:
--------------------------------------------------------------------------------
1 | import rss, { pagesGlobToRssItems } from '@astrojs/rss';
2 |
3 | export async function GET(context) {
4 | return rss({
5 | title: 'Astro Learner | Blog',
6 | description: 'My journey learning Astro',
7 | site: context.site,
8 | items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),
9 | customData: `en-us `,
10 | });
11 | }
--------------------------------------------------------------------------------
/src/components/Footer.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Social from "./Social.astro";
3 | ---
4 |
5 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@example/minimal",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "private": true,
6 | "scripts": {
7 | "dev": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@astrojs/preact": "^4.1.1",
14 | "@astrojs/rss": "^4.0.12",
15 | "astro": "^5.14.4",
16 | "preact": "^10.27.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/Header.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Menu from "./Menu.astro";
3 | import Navigation from "./Navigation.astro";
4 | import ThemeIcon from "./ThemeIcon.astro";
5 | ---
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/components/Greeting.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'preact/hooks';
2 |
3 | export default function Greeting({ messages }) {
4 |
5 | const randomMessage = () => messages[(Math.floor(Math.random() * messages.length))];
6 |
7 | const [greeting, setGreeting] = useState(messages[0]);
8 |
9 | return (
10 |
11 |
{greeting}! Thank you for visiting!
12 | setGreeting(randomMessage())}>
13 | New Greeting
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/blog.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from "../layouts/BaseLayout.astro";
3 | import BlogPost from "../components/BlogPost.astro";
4 | const allPosts = Object.values(
5 | import.meta.glob("./posts/*.md", { eager: true })
6 | );
7 | const pageTitle = "My Astro Learning Blog";
8 | ---
9 |
10 |
11 | This is where I will post about my journey learning Astro.
12 |
13 | {allPosts.map((post:any) => )}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/pages/posts/post-4.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/MarkdownPostLayout.astro
3 | title: My Fourth Blog Post
4 | author: Astro Learner
5 | description: "This post will show up on its own!"
6 | image:
7 | url: "https://docs.astro.build/default-og-image.png"
8 | alt: "The word astro against an illustration of planets and stars."
9 | pubDate: 2022-08-08
10 | tags: ["astro", "successes"]
11 | ---
12 | This post should show up with my other blog posts, because `import.meta.glob()` is returning a list of all my posts in order to create my list.
13 |
--------------------------------------------------------------------------------
/src/pages/posts/post-2.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/MarkdownPostLayout.astro
3 | title: My Second Blog Post
4 | author: Astro Learner
5 | description: "After learning some Astro, I couldn't stop!"
6 | image:
7 | url: "https://docs.astro.build/assets/arc.webp"
8 | alt: "The Astro logo on a dark background with a purple gradient arc."
9 | pubDate: 2022-07-08
10 | tags: ["astro", "blogging", "learning in public", "successes"]
11 | ---
12 |
13 | After a successful first week learning Astro, I decided to try some more. I wrote and imported a small component from memory!
14 |
--------------------------------------------------------------------------------
/src/pages/posts/post-3.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/MarkdownPostLayout.astro
3 | title: My Third Blog Post
4 | author: Astro Learner
5 | description: "I had some challenges, but asking in the community really helped!"
6 | image:
7 | url: "https://docs.astro.build/assets/rays.webp"
8 | alt: "The Astro logo on a dark background with rainbow rays."
9 | pubDate: 2022-07-15
10 | tags: ["astro", "learning in public", "setbacks", "community"]
11 | ---
12 |
13 | It wasn't always smooth sailing, but I'm enjoying building with Astro. And, the [Discord community](https://astro.build/chat) is really friendly and helpful!
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Astro "Build a Blog" Project - Completed
2 |
3 | This is the project you'll build with the [Astro Tutorial](https://docs.astro.build/en/tutorial/0-introduction/). Use this code to compare to your own, or explore to see how the basics of a blog are built in Astro!
4 |
5 | This branch contains the state of the project after completing the basic tutorial, [Unit 6.3](https://docs.astro.build/en/tutorial/6-islands/3/).
6 |
7 | The [`content collections`](https://github.com/withastro/blog-tutorial-demo/tree/content-collections) branch is the completed project branch after the optional Content Collections extension in unit [6.4](https://docs.astro.build/en/tutorial/6-islands/4/).
8 |
--------------------------------------------------------------------------------
/src/layouts/BaseLayout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Header from "../components/Header.astro";
3 | import Footer from "../components/Footer.astro";
4 | import "../styles/global.css";
5 | const { pageTitle } = Astro.props;
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {pageTitle}
15 |
16 |
17 |
18 | {pageTitle}
19 |
20 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/src/pages/tags/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from "../../layouts/BaseLayout.astro";
3 | const allPosts = Object.values(
4 | import.meta.glob("../posts/*.md", { eager: true })
5 | );
6 | const tags = [
7 | ...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat()),
8 | ];
9 | const pageTitle = "Tag Index";
10 | ---
11 |
12 |
13 |
22 |
23 |
42 |
--------------------------------------------------------------------------------
/src/layouts/MarkdownPostLayout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from "./BaseLayout.astro";
3 | const { frontmatter } = Astro.props;
4 | ---
5 |
6 |
7 | {frontmatter.pubDate.toString().slice(0, 10)}
8 | {frontmatter.description}
9 | Written by: {frontmatter.author}
10 |
11 |
12 |
21 |
22 |
23 |
24 |
43 |
--------------------------------------------------------------------------------
/src/pages/tags/[tag].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from "../../layouts/BaseLayout.astro";
3 | import BlogPost from "../../components/BlogPost.astro";
4 |
5 | export async function getStaticPaths() {
6 | const allPosts = Object.values(
7 | import.meta.glob("../posts/*.md", { eager: true })
8 | );
9 |
10 | const uniqueTags = [
11 | ...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat()),
12 | ];
13 |
14 | return uniqueTags.map((tag) => {
15 | const filteredPosts = allPosts.filter((post: any) =>
16 | post.frontmatter.tags.includes(tag)
17 | );
18 | return {
19 | params: { tag },
20 | props: { posts: filteredPosts },
21 | };
22 | });
23 | }
24 |
25 | const { tag } = Astro.params;
26 | const { posts } = Astro.props;
27 | ---
28 |
29 |
30 | Posts tagged with {tag}
31 |
32 | {
33 | posts.map((post: any) => (
34 |
35 | ))
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/pages/posts/post-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/MarkdownPostLayout.astro
3 | title: 'My First Blog Post'
4 | pubDate: 2022-07-01
5 | description: "This is the first post of my new Astro blog."
6 | author: "Astro Learner"
7 | image:
8 | url: "https://docs.astro.build/assets/rose.webp"
9 | alt: "The Astro logo on a dark background with a pink glow."
10 | tags: ["astro", "blogging", "learning in public"]
11 | ---
12 |
13 | Welcome to my _new blog_ about learning Astro! Here, I will share my learning journey as I build a new website.
14 |
15 | ## What I've accomplished
16 |
17 | 1. **Installing Astro**: First, I created a new Astro project and set up my online accounts.
18 |
19 | 2. **Making Pages**: I then learned how to make pages by creating new `.astro` files and placing them in the `src/pages/` folder.
20 |
21 | 3. **Making Blog Posts**: This is my first blog post! I now have Astro pages and Markdown posts!
22 |
23 | ## What's next
24 |
25 | I will finish the Astro tutorial, and then keep adding more posts. Watch this space for more to come.
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 [Astro contributors](https://github.com/withastro/blog-tutorial-demo/graphs/contributors)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/styles/global.css:
--------------------------------------------------------------------------------
1 | html {
2 | background-color: #f1f5f9;
3 | font-family: sans-serif;
4 | }
5 |
6 | body {
7 | margin: 0 auto;
8 | width: 100%;
9 | max-width: 80ch;
10 | padding: 1rem;
11 | line-height: 1.5;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
18 | h1 {
19 | margin: 1rem 0;
20 | font-size: 2.5rem;
21 | }
22 |
23 | /* nav styles */
24 |
25 | .menu {
26 | background-color: #0d0950;
27 | border: none;
28 | color: #fff;
29 | font-size: 1.2rem;
30 | font-weight: bold;
31 | padding: 5px 10px;
32 | }
33 |
34 |
35 | .nav-links {
36 | width: 100%;
37 | display: none;
38 | margin: 0;
39 | }
40 |
41 | .nav-links a {
42 | display: block;
43 | text-align: center;
44 | padding: 10px 0;
45 | text-decoration: none;
46 | font-size: 1.2rem;
47 | font-weight: bold;
48 | text-transform: uppercase;
49 | color: #0d0950;
50 | }
51 |
52 | .nav-links a:hover,
53 | .nav-links a:focus {
54 | background-color: #ff9776;
55 | }
56 |
57 | :has(.menu[aria-expanded="true"]) .nav-links {
58 | display: unset;
59 | }
60 |
61 | @media screen and (min-width: 636px) {
62 | .nav-links {
63 | margin-left: 5em;
64 | display: block;
65 | position: static;
66 | width: auto;
67 | background: none;
68 | }
69 |
70 | .nav-links a {
71 | display: inline-block;
72 | padding: 15px 20px;
73 | }
74 |
75 | .menu {
76 | display: none;
77 | }
78 | }
79 |
80 | html.dark {
81 | background-color: #0d0950;
82 | color: #fff;
83 | }
84 |
85 | .dark .menu {
86 | background-color: #fff;
87 | color: #000;
88 | }
89 |
90 | .dark .nav-links a:hover,
91 | .dark .nav-links a:focus {
92 | color: #0d0950;
93 | }
94 |
95 | .dark .nav-links a {
96 | color: #fff;
97 | }
98 |
99 | .dark a {
100 | color: #ff9776;
101 | }
--------------------------------------------------------------------------------
/src/pages/about.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseLayout from "../layouts/BaseLayout.astro";
3 |
4 | const pageTitle = "About Me";
5 |
6 | const identity = {
7 | firstName: "Sarah",
8 | country: "Canada",
9 | occupation: "Technical Writer",
10 | hobbies: ["photography", "birdwatching", "baseball"],
11 | };
12 |
13 | const skills = ["HTML", "CSS", "JavaScript", "React", "Astro", "Writing Docs"];
14 |
15 | const happy = true;
16 | const finished = true;
17 | const goal = 3;
18 |
19 | const skillColor = "crimson";
20 | const fontWeight = "bold";
21 | const textCase = "uppercase";
22 | ---
23 |
24 |
35 |
36 |
37 | ... and my new Astro site!
38 |
39 |
40 | I am working through Astro's introductory tutorial. This is the second page
41 | on my website, and it's the first one I built myself!
42 |
43 |
44 |
45 | This site will update as I complete more of the tutorial, so keep checking
46 | back and see how my journey is going!
47 |
48 | Here are a few facts about me:
49 |
50 | My name is {identity.firstName}.
51 |
52 | I live in {identity.country} and I work as a {identity.occupation}.
53 |
54 | {
55 | identity.hobbies.length >= 2 && (
56 |
57 | Two of my hobbies are: {identity.hobbies[0]} and {identity.hobbies[1]}
58 |
59 | )
60 | }
61 |
62 | My skills are:
63 |
64 | {skills.map((skill) => {skill} )}
65 |
66 | {happy && I am happy to be learning Astro!
}
67 |
68 | {finished && I finished this tutorial!
}
69 |
70 | {
71 | goal === 3 ? (
72 | My goal is to finish in 3 days.
73 | ) : (
74 | My goal is not 3 days.
75 | )
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/src/components/ThemeIcon.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 |
6 |
7 |
12 |
17 |
18 |
19 |
20 |
40 |
41 |
73 |
--------------------------------------------------------------------------------