Improve blog template (#217)
1
examples/blog/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
dist
|
|
@ -1,15 +1,22 @@
|
|||
# Astro Blog Example
|
||||
|
||||
Features:
|
||||
|
||||
- ✅ SEO-friendly setup with canonical URLs and OpenGraph data
|
||||
- ✅ Full Markdown support
|
||||
- ✅ RSS 2.0 generation
|
||||
- ✅ Sitemap.xml generation
|
||||
|
||||
## Setup
|
||||
|
||||
```
|
||||
npm install
|
||||
yarn
|
||||
```
|
||||
|
||||
## Dev
|
||||
|
||||
```
|
||||
npm start
|
||||
yarn start
|
||||
```
|
||||
|
||||
Preview at `http://localhost:3000`
|
||||
|
@ -17,7 +24,7 @@ Preview at `http://localhost:3000`
|
|||
## Build
|
||||
|
||||
```
|
||||
npm build
|
||||
yarn build
|
||||
```
|
||||
|
||||
Will output static site at `./dist`
|
||||
|
|
|
@ -2,9 +2,9 @@ export default {
|
|||
projectRoot: '.',
|
||||
public: './public',
|
||||
dist: './dist',
|
||||
buildOptions:{
|
||||
buildOptions: {
|
||||
sitemap: true,
|
||||
site: 'https://muppet-blog.github.io/',
|
||||
site: 'https://mysite.dev/', // change
|
||||
},
|
||||
astroRoot: './src',
|
||||
};
|
||||
|
|
BIN
examples/blog/public/authors/don.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
examples/blog/public/authors/sancho.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
|
@ -1,9 +1,23 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
font-family: 'Spectral', serif;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: crimson;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
max-width: 1400px;
|
||||
max-width: 60rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 2rem;
|
||||
|
|
Before Width: | Height: | Size: 40 KiB |
BIN
examples/blog/public/images/chapter-01.jpg
Normal file
After Width: | Height: | Size: 150 KiB |
BIN
examples/blog/public/images/chapter-02.jpg
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
examples/blog/public/images/chapter-03.jpg
Normal file
After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 228 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 31 KiB |
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
export let author;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin-right: 0.5rem;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="card">
|
||||
<div class="avatar">
|
||||
<img class="avatar" src={author.img} alt={author.name} />
|
||||
</div>
|
||||
{author.name}
|
||||
</div>
|
|
@ -7,33 +7,33 @@ export let type: string | undefined;
|
|||
export let next: string | undefined;
|
||||
export let prev: string | undefined;
|
||||
export let canonicalURL: string | undefined;
|
||||
|
||||
// internal data
|
||||
const OG_TYPES = {
|
||||
'movie': 'video.movie',
|
||||
'television': 'video.tv_show'
|
||||
}
|
||||
---
|
||||
|
||||
<!-- Common -->
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="UTF-8">
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="stylesheet" href="/global.css" />
|
||||
<link rel="sitemap" href="/sitemap.xml" />
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
{next && <link rel="next" href={next} />}
|
||||
{prev && <link rel="prev" href={prev} />}
|
||||
<meta name="description" content={description}>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/global.css">
|
||||
<!-- Sitemap -->
|
||||
<link rel="sitemap" href="/sitemap.xml">
|
||||
<!-- RSS -->
|
||||
<link rel="alternate" type="application/rss+xml" href="/feed/posts.xml">
|
||||
|
||||
<!-- SEO -->
|
||||
<link rel="canonical" href={canonicalURL}>
|
||||
{next && <link rel="next" href={new URL(next, canonicalURL).href}>}
|
||||
{prev && <link rel="prev" href={new URL(prev, canonicalURL).href}>}
|
||||
|
||||
<!-- OpenGraph -->
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
{image && (<meta property="og:image" content={image} />)}
|
||||
{OG_TYPES[type] && (<meta property="og:type" content={OG_TYPES[type]} />)}
|
||||
<meta property="og:title" content={title}>
|
||||
<meta property="og:description" content={description}>
|
||||
{image && (<meta property="og:image" content={new URL(image, canonicalURL)}>)}
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} />
|
||||
<meta name="twitter:site" content="@astro" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
{image && (<meta name="twitter:image" content={image} />)}
|
||||
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'}>
|
||||
<meta name="twitter:site" content="@astro">
|
||||
<meta name="twitter:title" content={title}>
|
||||
<meta name="twitter:description" content={description}>
|
||||
{image && (<meta name="twitter:image" content={image}>)}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
---
|
||||
export let title;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
.header {
|
||||
display: flex;
|
||||
|
@ -7,8 +11,10 @@
|
|||
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
margin-right: 2rem;
|
||||
font-size: 1.2em;
|
||||
letter-spacing: -0.03em;
|
||||
font-weight: 400;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.nav {
|
||||
|
@ -28,17 +34,19 @@ li {
|
|||
|
||||
a {
|
||||
display: block;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.2em;
|
||||
letter-spacing: -0.02em;
|
||||
margin-left: 0.75em;
|
||||
margin-right: 0.75em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<nav class="header">
|
||||
<h1 class="title">Muppet Blog</h1>
|
||||
<h1 class="title">Don’s Blog</h1>
|
||||
<ul class="nav">
|
||||
<li><a href="/">All Posts</a></li>
|
||||
<li><a href="/tag/movie/1">Movies</a></li>
|
||||
<li><a href="/tag/television/1">Television</a></li>
|
||||
<li><a href="/author/don">Author: Don</a></li>
|
||||
<li><a href="/author/sancho">Author: Sancho</a></li>
|
||||
<li><a href="/about">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
@ -6,17 +6,21 @@ export let nextUrl: string;
|
|||
<style lang="scss">
|
||||
.nav {
|
||||
display: flex;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
margin-left: auto;
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
.prev,
|
||||
.next {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
|
||||
&[href="#"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.prev {
|
||||
|
@ -28,7 +32,9 @@ export let nextUrl: string;
|
|||
}
|
||||
</style>
|
||||
|
||||
<nav class="nav">
|
||||
<a class="prev" href={prevUrl || '#'}>Prev</a>
|
||||
<a class="next" href={nextUrl || '#'}>Next</a>
|
||||
</nav>
|
||||
<div class="wrapper">
|
||||
<nav class="nav">
|
||||
<a class="prev" href={prevUrl || '#'}>Prev</a>
|
||||
<a class="next" href={nextUrl || '#'}>Next</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -2,57 +2,62 @@
|
|||
export let post;
|
||||
export let author;
|
||||
|
||||
import AuthorCard from './AuthorCard.astro';
|
||||
|
||||
function formatDate(date) {
|
||||
return new Date(date).toUTCString();
|
||||
return new Date(date).toUTCString().replace(/(\d\d\d\d) .*/, '$1'); // remove everything after YYYY
|
||||
}
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
.post {
|
||||
display: grid;
|
||||
grid-template-columns: 8rem auto;
|
||||
grid-gap: 1.5rem;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
border-bottom: 1px solid rgba(black, 0.25);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
width: 8rem;
|
||||
height: 8rem;
|
||||
object-fit: cover;
|
||||
border-radius: 0.25rem;
|
||||
overflow: hidden;
|
||||
.author {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.date {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.link {
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 700;
|
||||
font-size: 1em;
|
||||
font-size: 2.75em;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
display: block;
|
||||
margin-top: 0.5em;
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<article class="post">
|
||||
<div class="thumb">
|
||||
<img src={post.image} alt={post.title} />
|
||||
</div>
|
||||
|
||||
<div class="data">
|
||||
<h1>{post.title}</h1>
|
||||
<AuthorCard author={author} />
|
||||
<time>{formatDate(post.date)}</time>
|
||||
<p>{post.description}</p>
|
||||
<a href={post.url}>Read</a>
|
||||
<a class="author" href={`/author/${post.author}`}>{author.name}</a>
|
||||
<time class="date" datetime={post.date}>{formatDate(post.date)}</time>
|
||||
<p class="description">
|
||||
{post.description}
|
||||
<a class="link" href={post.url}>Read</a>
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
|
|
@ -1,27 +1,10 @@
|
|||
{
|
||||
"animal": {
|
||||
"name": "Animal",
|
||||
"email": "animal@muppets.co",
|
||||
"img": "/images/animal.jpg"
|
||||
"don": {
|
||||
"name": "Don Quixote",
|
||||
"image": "/authors/don.jpg"
|
||||
},
|
||||
"kermit": {
|
||||
"name": "Kermit the Frog",
|
||||
"email": "kermit@muppets.co",
|
||||
"img": "/images/kermit.jpg"
|
||||
},
|
||||
"ms-piggy": {
|
||||
"name": "Animal",
|
||||
"email": "mspiggy@muppets.co",
|
||||
"img": "/images/ms-piggy.jpg"
|
||||
},
|
||||
"gonzo": {
|
||||
"name": "Gonzo",
|
||||
"email": "thegonz@muppets.co",
|
||||
"img": "/images/gonzo.jpg"
|
||||
},
|
||||
"rizzo": {
|
||||
"name": "Rizzo the Rat",
|
||||
"email": "rizzo@muppets.co",
|
||||
"img": "/images/rizzo.jpg"
|
||||
"sancho": {
|
||||
"name": "Sancho Panza",
|
||||
"image": "/authors/sancho.jpg"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
---
|
||||
import AuthorCard from '../components/AuthorCard.astro';
|
||||
import MainHead from '../components/MainHead.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
|
||||
|
@ -11,18 +10,67 @@ import authorData from '../data/authors.json';
|
|||
<html>
|
||||
<head>
|
||||
<title>{content.title}</title>
|
||||
<MainHead title={content.title} description={content.description} image={content.image} />
|
||||
<MainHead title={content.title} description={content.description} image={content.image} canonicalURL={Astro.request.canonicalURL} />
|
||||
<style lang="scss">
|
||||
.title {
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 4rem;
|
||||
font-size: 3em;
|
||||
letter-spacing: -0.04em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 4rem;
|
||||
font-size: 1.4em;
|
||||
font-weight: 400;
|
||||
text-align: justify;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.article {
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 6rem;
|
||||
|
||||
:global(p) {
|
||||
font-size: 1.3em;
|
||||
line-height: 2;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.posts {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Nav />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1>{content.title}</h1>
|
||||
<AuthorCard author={authorData[content.author]} />
|
||||
<article>
|
||||
<h1 class="title">{content.title}</h1>
|
||||
<h3 class="description">{content.description}</h3>
|
||||
<img class="img" src={content.image} alt={content.title}>
|
||||
<article class="article">
|
||||
<slot />
|
||||
</article>
|
||||
<footer class="footer">
|
||||
<a class="posts" href="/posts">All Posts</a>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
|
|
108
examples/blog/src/pages/$author.astro
Normal file
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
import MainHead from '../components/MainHead.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import PostPreview from '../components/PostPreview.astro';
|
||||
import Pagination from '../components/Pagination.astro';
|
||||
|
||||
// page
|
||||
let title = 'Don’s Blog';
|
||||
let description = 'An example blog on Astro';
|
||||
let canonicalURL = Astro.request.canonicalURL;
|
||||
const author = authorData[collection.params.author];
|
||||
|
||||
// collection
|
||||
import authorData from '../data/authors.json';
|
||||
export let collection: any;
|
||||
export async function createCollection() {
|
||||
/** Load posts */
|
||||
let allPosts = Astro.fetchContent('./post/*.md');
|
||||
let allAuthors = new Set();
|
||||
|
||||
/** Loop through all posts, gather all authors */
|
||||
let routes = [];
|
||||
for (const post of allPosts) {
|
||||
if (!allAuthors.has(post.author)) {
|
||||
allAuthors.add(post.author);
|
||||
routes.push({ author: post.author });
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
/** Sort posts newest -> oldest, filter by params.author */
|
||||
async data({ params }) {
|
||||
allPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
return allPosts.filter((post) => post.author === params.author);
|
||||
},
|
||||
/** Set page size */
|
||||
pageSize: 3,
|
||||
/** Set permalink URL */
|
||||
permalink: ({ params }) => `/author/${params.author}`,
|
||||
/** Pass back all routes so Astro can generate the static build */
|
||||
routes,
|
||||
};
|
||||
}
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<MainHead
|
||||
title={title}
|
||||
description={description}
|
||||
image={collection.data[0].image}
|
||||
canonicalURL={canonicalURL}
|
||||
prev={collection.url.prev}
|
||||
next={collection.url.next}
|
||||
/>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 3em;
|
||||
letter-spacing: -0.04em;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-right: 0.5em;
|
||||
border-radius: 50%;
|
||||
overflow:hidden;
|
||||
|
||||
&-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 1em;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Nav title={title} />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1 class="title">
|
||||
<div class="avatar"><img class="avatar-img" src={author.image} alt={author.name}></div>
|
||||
{author.name}
|
||||
</h1>
|
||||
<small class="count">{collection.start + 1}–{collection.end + 1} of {collection.total}</small>
|
||||
{collection.data.map((post) => <PostPreview post={post} author={author} />)}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<Pagination prevUrl={collection.url.prev} nextUrl={collection.url.next} />
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -5,22 +5,26 @@ import PostPreview from '../components/PostPreview.astro';
|
|||
import Pagination from '../components/Pagination.astro';
|
||||
|
||||
// page
|
||||
let title = 'Muppet Blog: Home';
|
||||
let title = 'Don’s Blog';
|
||||
let description = 'An example blog on Astro';
|
||||
let canonicalURL = Astro.request.canonicalURL;
|
||||
|
||||
// collection
|
||||
import authorData from '../data/authors.json';
|
||||
export let collection: any;
|
||||
export async function createCollection() {
|
||||
return {
|
||||
/** Load posts, sort newest -> oldest */
|
||||
async data() {
|
||||
let allPosts = Astro.fetchContent('./post/*.md');
|
||||
allPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
return allPosts;
|
||||
},
|
||||
pageSize: 3,
|
||||
/** Set page size */
|
||||
pageSize: 2,
|
||||
/** Generate RSS feed (only for main /posts/ feed) */
|
||||
rss: {
|
||||
title: 'Muppet Blog',
|
||||
title: 'Don’s Blog',
|
||||
description: 'An example blog on Astro',
|
||||
customData: `<language>en-us</language>`,
|
||||
item: (item) => ({
|
||||
|
@ -37,18 +41,38 @@ export async function createCollection() {
|
|||
<html>
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<MainHead title={title} description={description} />
|
||||
<link rel="canonical" href={'https://mysite.dev' + collection.url.current} />
|
||||
{collection.url.next && <link rel="next" href={'https://mysite.dev' + collection.url.next} />}
|
||||
{collection.url.prev && <link rel="prev" href={'https://mysite.dev' + collection.url.prev} />}
|
||||
<MainHead
|
||||
title={title}
|
||||
description={description}
|
||||
image={collection.data[0].image}
|
||||
canonicalURL={canonicalURL}
|
||||
prev={collection.url.prev}
|
||||
next={collection.url.next}
|
||||
/>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
font-size: 3em;
|
||||
letter-spacing: -0.04em;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 1em;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Nav />
|
||||
<Nav title={title} />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1>All Posts</h1>
|
||||
<small>{collection.start + 1}–{collection.end + 1} of {collection.total}</small><br />
|
||||
<h1 class="title">All Posts</h1>
|
||||
<small class="count">{collection.start + 1}–{collection.end + 1} of {collection.total}</small>
|
||||
{collection.data.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
|
||||
</main>
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
---
|
||||
import MainHead from '../components/MainHead.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import PostPreview from '../components/PostPreview.astro';
|
||||
import Pagination from '../components/Pagination.astro';
|
||||
|
||||
// page
|
||||
let title = 'Muppet Blog: Home';
|
||||
let description = 'An example blog on Astro';
|
||||
|
||||
// collection
|
||||
import authorData from '../data/authors.json';
|
||||
export let collection: any;
|
||||
export async function createCollection() {
|
||||
let allPosts = Astro.fetchContent('./post/*.md');
|
||||
let allTags = new Set();
|
||||
let routes = [];
|
||||
for (const post of allPosts) {
|
||||
if (!allTags.has(post.tag)) {
|
||||
allTags.add(post.tag);
|
||||
routes.push({ tag: post.tag });
|
||||
}
|
||||
}
|
||||
return {
|
||||
async data({ params }) {
|
||||
allPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
return allPosts.filter((post) => post.tag === params.tag);
|
||||
},
|
||||
routes,
|
||||
permalink: ({ params }) => `/tag/${params.tag}`,
|
||||
pageSize: 3
|
||||
};
|
||||
}
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<MainHead title={title} description={description} />
|
||||
<link rel="canonical" href={'https://mysite.dev' + collection.url.current} />
|
||||
{collection.url.next && <link rel="next" href={'https://mysite.dev' + collection.url.next} />}
|
||||
{collection.url.prev && <link rel="prev" href={'https://mysite.dev' + collection.url.prev} />}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Nav />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1>Tagged: {collection.params.tag}</h1>
|
||||
<small>{collection.start + 1}–{collection.end + 1} of {collection.total}</small><br />
|
||||
{collection.data.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<Pagination prevUrl={collection.url.prev} nextUrl={collection.url.next} />
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
61
examples/blog/src/pages/about.astro
Normal file
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import MainHead from '../components/MainHead.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
|
||||
let title = "About";
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
<MainHead
|
||||
title={title}
|
||||
canonicalURL={Astro.request.canonicalURL}
|
||||
/>
|
||||
<style lang="scss">
|
||||
|
||||
.text {
|
||||
padding-bottom: 6rem;
|
||||
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
line-height: 2;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.hero {
|
||||
display: block;
|
||||
height: 16rem;
|
||||
overflow: hidden;
|
||||
margin: 4rem 0;
|
||||
|
||||
&-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3em;
|
||||
letter-spacing: -0.04em;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<Nav title={title} />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1 class="title">{title}</h1>
|
||||
<figure class="hero"><img class="hero-img" src="/images/chapter-01.jpg"></figure>
|
||||
<div class="text">
|
||||
<p>The book cover and spine above and the images which follow were not part of the original Ormsby translation—they are taken from the 1880 edition of J. W. Clark, illustrated by Gustave Doré. Clark in his edition states that, “The English text of ‘Don Quixote’ adopted in this edition is that of Jarvis, with occasional corrections from Motteaux.”</p>
|
||||
<p>See in the introduction below John Ormsby’s critique of both the Jarvis and Motteaux translations. It has been elected in the present Project Gutenberg edition to attach the famous engravings of Gustave Doré to the Ormsby translation instead of the Jarvis/Motteaux. The detail of many of the Doré engravings can be fully appreciated only by utilizing the “Full Size” button to expand them to their original dimensions. Ormsby in his Preface has criticized the fanciful nature of Doré’s illustrations; others feel these woodcuts and steel engravings well match Quixote’s dreams.</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -5,7 +5,7 @@ import PostPreview from '../components/PostPreview.astro';
|
|||
import Pagination from '../components/Pagination.astro';
|
||||
|
||||
// page
|
||||
let title = 'Muppet Blog: Home';
|
||||
let title = 'Don’s Blog';
|
||||
let description = 'An example blog on Astro';
|
||||
|
||||
// collection
|
||||
|
@ -15,7 +15,7 @@ import authorData from '../data/authors.json';
|
|||
|
||||
let allPosts = Astro.fetchContent('./post/*.md');
|
||||
allPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
let firstThree = allPosts.slice(0, 3);
|
||||
let firstPage = allPosts.slice(0, 2);
|
||||
---
|
||||
|
||||
<html>
|
||||
|
@ -24,6 +24,7 @@ let firstThree = allPosts.slice(0, 3);
|
|||
<MainHead
|
||||
title={title}
|
||||
description={description}
|
||||
image={firstPage[0].image}
|
||||
canonicalURL={Astro.request.canonicalURL.href}
|
||||
/>
|
||||
</head>
|
||||
|
@ -32,8 +33,7 @@ let firstThree = allPosts.slice(0, 3);
|
|||
<Nav />
|
||||
|
||||
<main class="wrapper">
|
||||
<h1>Recent posts</h1>
|
||||
{firstThree.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
|
||||
{firstPage.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
|
|
13
examples/blog/src/pages/post/chapter-i.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Chapter I
|
||||
tag: movie
|
||||
date: 2021-05-17
|
||||
image: /images/chapter-01.jpg
|
||||
author: don
|
||||
description: Which Treats of the Character and Pursuits of the Famous Gentleman Don Quixote of La Mancha
|
||||
---
|
||||
|
||||
In a village of La Mancha, the name of which I have no desire to call to mind, there lived not long since one of those gentlemen that keep a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing. An olla of rather more beef than mutton, a salad on most nights, scraps on Saturdays, lentils on Fridays, and a pigeon or so extra on Sundays, made away with three-quarters of his income. The rest of it went in a doublet of fine cloth and velvet breeches and shoes to match for holidays, while on week-days he made a brave figure in his best homespun. He had in his house a housekeeper past forty, a niece under twenty, and a lad for the field and market-place, who used to saddle the hack as well as handle the bill-hook. The age of this gentleman of ours was bordering on fifty; he was of a hardy habit, spare, gaunt-featured, a very early riser and a great sportsman. They will have it his surname was Quixada or Quesada (for here there is some difference of opinion among the authors who write on the subject), although from reasonable conjectures it seems plain that he was called Quexana. This, however, is of but little importance to our tale; it will be enough not to stray a hair’s breadth from the truth in the telling of it.
|
||||
|
||||
You must know, then, that the above-named gentleman whenever he was at leisure (which was mostly all the year round) gave himself up to reading books of chivalry with such ardour and avidity that he almost entirely neglected the pursuit of his field-sports, and even the management of his property; and to such a pitch did his eagerness and infatuation go that he sold many an acre of tillageland to buy books of chivalry to read, and brought home as many of them as he could get. But of all there were none he liked so well as those of the famous Feliciano de Silva’s composition, for their lucidity of style and complicated conceits were as pearls in his sight, particularly when in his reading he came upon courtships and cartels, where he often found passages like “the reason of the unreason with which my reason is afflicted so weakens my reason that with reason I murmur at your beauty;” or again, “the high heavens, that of your divinity divinely fortify you with the stars, render you deserving of the desert your greatness deserves.” Over conceits of this sort the poor gentleman lost his wits, and used to lie awake striving to understand them and worm the meaning out of them; what Aristotle himself could not have made out or extracted had he come to life again for that special purpose. He was not at all easy about the wounds which Don Belianis gave and took, because it seemed to him that, great as were the surgeons who had cured him, he must have had his face and body covered all over with seams and scars. He commended, however, the author’s way of ending his book with the promise of that interminable adventure, and many a time was he tempted to take up his pen and finish it properly as is there proposed, which no doubt he would have done, and made a successful piece of work of it too, had not greater and more absorbing thoughts prevented him.
|
15
examples/blog/src/pages/post/chapter-ii.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Chapter II
|
||||
tag: movie
|
||||
date: 2021-05-18
|
||||
image: /images/chapter-02.jpg
|
||||
author: sancho
|
||||
description: Which Treats of the First Sally the Ingenious Don Quixote Made From Home
|
||||
---
|
||||
|
||||
These preliminaries settled, he did not care to put off any longer the execution of his design, urged on to it by the thought of all the world was losing by his delay, seeing what wrongs he intended to right, grievances to redress, injustices to repair, abuses to remove, and duties to discharge. So, without giving notice of his intention to anyone, and without anybody seeing him, one morning before the dawning of the day (which was one of the hottest of the month of July) he donned his suit of armour, mounted Rocinante with his patched-up helmet on, braced his buckler, took his lance, and by the back door of the yard sallied forth upon the plain in the highest contentment and satisfaction at seeing with what ease he had made a beginning with his grand purpose. But scarcely did he find himself upon the open plain, when a terrible thought struck him, one all but enough to make him abandon the enterprise at the very outset. It occurred to him that he had not been dubbed a knight, and that according to the law of chivalry he neither could nor ought to bear arms against any knight; and that even if he had been, still he ought, as a novice knight, to wear white armour, without a device upon the shield until by his prowess he had earned one. These reflections made him waver in his purpose, but his craze being stronger than any reasoning, he made up his mind to have himself dubbed a knight by the first one he came across, following the example of others in the same case, as he had read in the books that brought him to this pass. As for white armour, he resolved, on the first opportunity, to scour his until it was whiter than an ermine; and so comforting himself he pursued his way, taking that which his horse chose, for in this he believed lay the essence of adventures.
|
||||
|
||||
Thus setting out, our new-fledged adventurer paced along, talking to himself and saying, “Who knows but that in time to come, when the veracious history of my famous deeds is made known, the sage who writes it, when he has to set forth my first sally in the early morning, will do it after this fashion? ‘Scarce had the rubicund Apollo spread o’er the face of the broad spacious earth the golden threads of his bright hair, scarce had the little birds of painted plumage attuned their notes to hail with dulcet and mellifluous harmony the coming of the rosy Dawn, that, deserting the soft couch of her jealous spouse, was appearing to mortals at the gates and balconies of the Manchegan horizon, when the renowned knight Don Quixote of La Mancha, quitting the lazy down, mounted his celebrated steed Rocinante and began to traverse the ancient and famous Campo de Montiel;’” which in fact he was actually traversing. “Happy the age, happy the time,” he continued, “in which shall be made known my deeds of fame, worthy to be moulded in brass, carved in marble, limned in pictures, for a memorial for ever. And thou, O sage magician, whoever thou art, to whom it shall fall to be the chronicler of this wondrous history, forget not, I entreat thee, my good Rocinante, the constant companion of my ways and wanderings.” Presently he broke out again, as if he were love-stricken in earnest, “O Princess Dulcinea, lady of this captive heart, a grievous wrong hast thou done me to drive me forth with scorn, and with inexorable obduracy banish me from the presence of thy beauty. O lady, deign to hold in remembrance this heart, thy vassal, that thus in anguish pines for love of thee.”
|
||||
|
||||
So he went on stringing together these and other absurdities, all in the style of those his books had taught him, imitating their language as well as he could; and all the while he rode so slowly and the sun mounted so rapidly and with such fervour that it was enough to melt his brains if he had any. Nearly all day he travelled without anything remarkable happening to him, at which he was in despair, for he was anxious to encounter someone at once upon whom to try the might of his strong arm.
|
13
examples/blog/src/pages/post/chapter-iii.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Chapter III
|
||||
tag: movie
|
||||
date: 2021-05-19
|
||||
image: /images/chapter-03.jpg
|
||||
author: don
|
||||
description: Wheren is Related the Droll Way in which Don Quixote Had Himself Dubbed a Knight
|
||||
---
|
||||
|
||||
Harassed by this reflection, he made haste with his scanty pothouse supper, and having finished it called the landlord, and shutting himself into the stable with him, fell on his knees before him, saying, “From this spot I rise not, valiant knight, until your courtesy grants me the boon I seek, one that will redound to your praise and the benefit of the human race.” The landlord, seeing his guest at his feet and hearing a speech of this kind, stood staring at him in bewilderment, not knowing what to do or say, and entreating him to rise, but all to no purpose until he had agreed to grant the boon demanded of him. “I looked for no less, my lord, from your High Magnificence,” replied Don Quixote, “and I have to tell you that the boon I have asked and your liberality has granted is that you shall dub me knight to-morrow morning, and that to-night I shall watch my arms in the chapel of this your castle; thus to-morrow, as I have said, will be accomplished what I so much desire, enabling me lawfully to roam through all the four quarters of the world seeking adventures on behalf of those in distress, as is the duty of chivalry and of knights-errant like myself, whose ambition is directed to such deeds.”
|
||||
|
||||
The landlord, who, as has been mentioned, was something of a wag, and had already some suspicion of his guest’s want of wits, was quite convinced of it on hearing talk of this kind from him, and to make sport for the night he determined to fall in with his humour. So he told him he was quite right in pursuing the object he had in view, and that such a motive was natural and becoming in cavaliers as distinguished as he seemed and his gallant bearing showed him to be; and that he himself in his younger days had followed the same honourable calling, roaming in quest of adventures in various parts of the world, among others the Curing-grounds of Malaga, the Isles of Riaran, the Precinct of Seville, the Little Market of Segovia, the Olivera of Valencia, the Rondilla of Granada, the Strand of San Lucar, the Colt of Cordova, the Taverns of Toledo, and divers other quarters, where he had proved the nimbleness of his feet and the lightness of his fingers, doing many wrongs, cheating many widows, ruining maids and swindling minors, and, in short, bringing himself under the notice of almost every tribunal and court of justice in Spain; until at last he had retired to this castle of his, where he was living upon his property and upon that of others; and where he received all knights-errant of whatever rank or condition they might be, all for the great love he bore them and that they might share their substance with him in return for his benevolence. He told him, moreover, that in this castle of his there was no chapel in which he could watch his armour, as it had been pulled down in order to be rebuilt, but that in a case of necessity it might, he knew, be watched anywhere, and he might watch it that night in a courtyard of the castle, and in the morning, God willing, the requisite ceremonies might be performed so as to have him dubbed a knight, and so thoroughly dubbed that nobody could be more so. He asked if he had any money with him, to which Don Quixote replied that he had not a farthing, as in the histories of knights-errant he had never read of any of them carrying any. On this point the landlord told him he was mistaken; for, though not recorded in the histories, because in the author’s opinion there was no need to mention anything so obvious and necessary as money and clean shirts, it was not to be supposed therefore that they did not carry them, and he might regard it as certain and established that all knights-errant (about whom there were so many full and unimpeachable books) carried well-furnished purses in case of emergency, and likewise carried shirts and a little box of ointment to cure the wounds they received. For in those plains and deserts where they engaged in combat and came out wounded, it was not always that there was someone to cure them, unless indeed they had for a friend some sage magician to succour them at once by fetching through the air upon a cloud some damsel or dwarf with a vial of water of such virtue that by tasting one drop of it they were cured of their hurts and wounds in an instant and left as sound as if they had not received any damage whatever. But in case this should not occur, the knights of old took care to see that their squires were provided with money and other requisites, such as lint and ointments for healing purposes; and when it happened that knights had no squires (which was rarely and seldom the case) they themselves carried everything in cunning saddle-bags that were hardly seen on the horse’s croup, as if it were something else of more importance, because, unless for some such reason, carrying saddle-bags was not very favourably regarded among knights-errant. He therefore advised him (and, as his godson so soon to be, he might even command him) never from that time forth to travel without money and the usual requirements, and he would find the advantage of them when he least expected it.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Muppet Babies
|
||||
tag: television
|
||||
date: 1984-09-15
|
||||
image: /images/muppet-babies.jpg
|
||||
author: ms-piggy
|
||||
description: Muppet Babies,is an American animated television series that aired from September 15, 1984, to November 2, 1991, on CBS.
|
||||
---
|
||||
|
||||
Jim Henson's Muppet Babies, commonly known by the shortened title Muppet Babies, is an American animated television series that aired from September 15, 1984, to November 2, 1991, on CBS. The show portrays childhood versions of the Muppets living together in a nursery under the care of a human woman identified only as Nanny (the whereabouts of their parents are never addressed), who appears in almost every episode, but her face is never visible; only the babies' view of her pink skirt, purple sweater, and distinctive green and white striped socks is shown. The idea of presenting the Muppets as children first appeared in a dream sequence in The Muppets Take Manhattan (1984), released two months before Muppet Babies debuted, in which Miss Piggy imagined what it would be like if she and Kermit the Frog had grown up together.
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Muppet Treasure Island
|
||||
tag: movie
|
||||
date: 1996-02-16
|
||||
image: /images/muppet-treasure-island.png
|
||||
author: ms-piggy
|
||||
description: Muppet Treasure Island is a 1996 American musical adventure comedy film directed by Brian Henson.
|
||||
---
|
||||
|
||||
Muppet Treasure Island is a 1996 American musical adventure comedy film directed by Brian Henson. It is the fifth theatrical film in The Muppets franchise.
|
||||
|
||||
Adapted from the 1883 novel Treasure Island by Robert Louis Stevenson, similarly to its predecessor The Muppet Christmas Carol (1992), the key roles were played by live-action actors, with the Muppets in supporting roles. It stars Tim Curry as Long John Silver, and Kevin Bishop as Jim Hawkins alongside Muppet performers Dave Goelz, Steve Whitmire, Jerry Nelson, Kevin Clash, and Frank Oz portraying various roles.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Muppets from Space
|
||||
tag: movie
|
||||
date: 1999-07-14
|
||||
image: /images/muppets-from-space.jpg
|
||||
author: rizzo
|
||||
description: Muppets from Space is a 1999 American science fiction comedy film directed by Tim Hill (in his feature directorial debut) and written by Jerry Juhl, Joseph Mazzarino, and Ken Kaufman.
|
||||
---
|
||||
|
||||
Muppets from Space is a 1999 American science fiction comedy film directed by Tim Hill (in his feature directorial debut) and written by Jerry Juhl, Joseph Mazzarino, and Ken Kaufman. The sixth theatrical film in The Muppets franchise, it is the first Muppets film to not be a musical and the first film since the death of Muppets creator Jim Henson to have an original Muppets-focused plot. It stars Jeffrey Tambor, F. Murray Abraham, David Arquette, Pat Hingle, Rob Schneider, Andie MacDowell, Josh Charles, Hulk Hogan, and Ray Liotta, alongside Muppet performers Dave Goelz, Steve Whitmire, Bill Barretta, and Frank Oz. In the film, Gonzo attempts to discover his origins after having nightmares. After he and Rizzo the Rat are captured by government officials during his search, Kermit the Frog and the rest of the Muppet gang must save them.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: Muppets Most Wanted
|
||||
tag: movie
|
||||
date: 2014-03-11
|
||||
image: /images/muppets-most-wanted.jpg
|
||||
author: animal
|
||||
description: Muppets Most Wanted is a 2014 American musical crime comedy film and the eighth theatrical film featuring the Muppets.
|
||||
---
|
||||
|
||||
Muppets Most Wanted is a 2014 American musical crime comedy film and the eighth theatrical film featuring the Muppets.[4] Directed by James Bobin and written by Bobin and Nicholas Stoller, the film is a direct sequel to The Muppets (2011) and stars Ricky Gervais, Ty Burrell and Tina Fey, as well as Muppets performers Steve Whitmire, Eric Jacobson, Dave Goelz, Bill Barretta, David Rudman, Matt Vogel and Peter Linz.[5] In the film, the Muppets become involved in an international crime caper perpetrated by Constantine, a criminal with a strong resemblance to Kermit, while on a world tour in Europe.[6] As of 2021, it is the most recent theatrical Muppets film.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: The Muppet Christmas Carol
|
||||
tag: movie
|
||||
date: 1992-12-11
|
||||
image: /images/the-muppet-christmas-carol.jpg
|
||||
author: kermit
|
||||
description: The Muppet Christmas Carol is a 1992 American Christmas musical fantasy comedy drama film directed by Brian Henson (in his feature directorial debut) from a screenplay by Jerry Juhl.
|
||||
---
|
||||
|
||||
The Muppet Christmas Carol is a 1992 American Christmas musical fantasy comedy drama film directed by Brian Henson (in his feature directorial debut) from a screenplay by Jerry Juhl. The fourth theatrical film in The Muppets franchise, it was the first film to be produced following the deaths of Muppets creator Jim Henson and performer Richard Hunt, with the film being dedicated to both of them. Adapted from the 1843 novella A Christmas Carol by Charles Dickens, it stars Michael Caine as Ebenezer Scrooge, alongside Muppet performers Dave Goelz, Steve Whitmire, Jerry Nelson, and Frank Oz portraying various roles. Although artistic license is taken to suit the aesthetic of the Muppets, The Muppet Christmas Carol otherwise follows Dickens's original story closely.[4]
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: The Muppet Show
|
||||
tag: television
|
||||
date: 1976-09-13
|
||||
image: /images/the-muppet-show.jpg
|
||||
author: kermit
|
||||
description: The Muppet Show is a comedy television series created by Jim Henson and featuring the Muppets.
|
||||
---
|
||||
|
||||
The Muppet Show is a comedy television series created by Jim Henson and featuring the Muppets. The series originated as two pilot episodes produced by Henson for ABC in 1974 and 1975, respectively. While neither episode was moved forward as a series and other networks in the United States rejected Henson's proposals, British producer Lew Grade expressed interest in the project and agreed to co-produce The Muppet Show for ATV. Five seasons, totalling 120 episodes, were broadcast on ATV and other ITV franchises in the United Kingdom and in first-run syndication through CBS in the US from 1976 to 1981. The programme was taped at Elstree Studios, England.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: ../../layouts/post.astro
|
||||
title: The Muppets
|
||||
tag: movie
|
||||
date: 2011-11-04
|
||||
image: /images/the-muppets.jpg
|
||||
author: gonzo
|
||||
description: The Muppets is a 2011 American musical comedy film directed by James Bobin, written by Jason Segel and Nicholas Stoller, and the seventh theatrical film featuring the Muppets.
|
||||
---
|
||||
|
||||
The Muppets is a 2011 American musical comedy film directed by James Bobin, written by Jason Segel and Nicholas Stoller, and the seventh theatrical film featuring the Muppets.[6] The film stars Segel, Amy Adams, Chris Cooper, and Rashida Jones, as well as Muppets performers Steve Whitmire, Eric Jacobson, Dave Goelz, Bill Barretta, David Rudman, Matt Vogel, and Peter Linz. Bret McKenzie served as music supervisor, writing four of the film's five original songs, while Christophe Beck composed the film's score.[7] In the film, devoted Muppet fan Walter, his human brother Gary and Gary's girlfriend Mary help Kermit the Frog reunite the disbanded Muppets, as they must raise $10 million to save the Muppet Theater from Tex Richman, a businessman who plans to demolish the studio to drill for oil.
|