paperastro 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/extensions.json +4 -0
- package/.vscode/launch.json +11 -0
- package/README.md +125 -0
- package/astro.config.mjs +11 -0
- package/package.json +41 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +9 -0
- package/public/fonts/atkinson-bold.woff +0 -0
- package/public/fonts/atkinson-regular.woff +0 -0
- package/public/screenshot.png +0 -0
- package/src/assets/scrap-placeholder.png +0 -0
- package/src/components/BaseHead.astro +63 -0
- package/src/components/Footer.astro +34 -0
- package/src/components/FormattedDate.astro +17 -0
- package/src/components/Header.astro +21 -0
- package/src/components/HeaderLink.astro +45 -0
- package/src/consts.ts +6 -0
- package/src/content/blog/first-post.md +39 -0
- package/src/content/blog/second-post.md +72 -0
- package/src/content.config.ts +19 -0
- package/src/layouts/BlogPost.astro +73 -0
- package/src/pages/about.astro +47 -0
- package/src/pages/blog/[...slug].astro +20 -0
- package/src/pages/blog/index.astro +87 -0
- package/src/pages/contact.astro +114 -0
- package/src/pages/index.astro +75 -0
- package/src/pages/rss.xml.js +16 -0
- package/src/styles/.global.css.swo +0 -0
- package/src/styles/global.css +0 -0
- package/tsconfig.json +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
|
|
2
|
+
# PaperAstro
|
|
3
|
+
|
|
4
|
+
PaperAstro is a lightweight, professional Astro starter template styled with PaperCSS.
|
|
5
|
+
It provides a clean, sketch‑inspired aesthetic while maintaining strong performance, clarity, and simplicity.
|
|
6
|
+
|
|
7
|
+
This template includes built‑in support for form handling through the Fabform backend.
|
|
8
|
+
Learn more at: [https://fabform.io](https://fabform.io)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
### Install with npm (recommended)
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm create astro@latest -- --template @fabform/paperastro
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This scaffolds a fresh project using the latest version of the PaperAstro starter.
|
|
21
|
+
You can explore npm installation.
|
|
22
|
+
|
|
23
|
+
### Install with Git
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
git clone https://github.com/fabformhub/paperastro
|
|
27
|
+
cd paperastro
|
|
28
|
+
npm install
|
|
29
|
+
npm run dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You can explore Git installation.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Screenshot
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Demo
|
|
44
|
+
|
|
45
|
+
Live Demo: [https://paperastro.vercel.app/](https://paperastro.vercel.app/)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- Built with Astro 5
|
|
52
|
+
- Styled entirely with PaperCSS
|
|
53
|
+
- MDX support included
|
|
54
|
+
- RSS and Sitemap integrations
|
|
55
|
+
- Sharp for image optimization
|
|
56
|
+
- Native form handling powered by Fabform
|
|
57
|
+
- Minimal, well‑structured project layout
|
|
58
|
+
- Suitable for blogs, documentation, and lightweight content sites
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Project Structure
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
/
|
|
66
|
+
├── public/
|
|
67
|
+
├── src/
|
|
68
|
+
│ ├── components/
|
|
69
|
+
│ ├── layouts/
|
|
70
|
+
│ ├── pages/
|
|
71
|
+
│ ├── consts.ts
|
|
72
|
+
│ └── styles/
|
|
73
|
+
└── package.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
You can explore project structure.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npm run dev # Start the development server
|
|
84
|
+
npm run build # Build the site for production
|
|
85
|
+
npm run preview # Preview the production build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can explore Astro commands.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Form Handling with Fabform
|
|
93
|
+
|
|
94
|
+
PaperAstro includes ready‑to‑use form integration powered by the Fabform backend.
|
|
95
|
+
You can connect any form by adding your Fabform endpoint URL.
|
|
96
|
+
|
|
97
|
+
Learn more at: [https://fabform.io](https://fabform.io)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Deploy with Vercel
|
|
102
|
+
|
|
103
|
+
Deploy PaperAstro to Vercel with one click:
|
|
104
|
+
|
|
105
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/fabformhub/paperastro)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT License
|
|
112
|
+
© 2026 Geoffrey Callaghan
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Repository
|
|
117
|
+
|
|
118
|
+
GitHub: [https://github.com/fabformhub/paperastro](https://github.com/fabformhub/paperastro)
|
|
119
|
+
|
|
120
|
+
## npm Package
|
|
121
|
+
|
|
122
|
+
[https://www.npmjs.com/package/@fabform/paperastro](https://www.npmjs.com/package/@fabform/paperastro)
|
|
123
|
+
You can explore the npm package.
|
|
124
|
+
|
|
125
|
+
---
|
package/astro.config.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import mdx from '@astrojs/mdx';
|
|
4
|
+
import sitemap from '@astrojs/sitemap';
|
|
5
|
+
import { defineConfig } from 'astro/config';
|
|
6
|
+
|
|
7
|
+
// https://astro.build/config
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
site: 'https://example.com',
|
|
10
|
+
integrations: [mdx(), sitemap()],
|
|
11
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "paperastro",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A lightweight, professional Astro starter template styled with PaperCSS and powered by Fabform.",
|
|
6
|
+
"author": "Geoffrey Callaghan",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/fabformhub/paperastro#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/fabformhub/paperastro.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/fabformhub/paperastro/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"astro",
|
|
18
|
+
"starter",
|
|
19
|
+
"template",
|
|
20
|
+
"papercss",
|
|
21
|
+
"blog",
|
|
22
|
+
"documentation",
|
|
23
|
+
"fabform",
|
|
24
|
+
"static-site",
|
|
25
|
+
"astro-theme"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "astro dev",
|
|
29
|
+
"build": "astro build",
|
|
30
|
+
"preview": "astro preview",
|
|
31
|
+
"astro": "astro"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@astrojs/mdx": "^4.3.13",
|
|
35
|
+
"@astrojs/rss": "^4.0.15",
|
|
36
|
+
"@astrojs/sitemap": "^3.7.0",
|
|
37
|
+
"astro": "^5.17.1",
|
|
38
|
+
"sharp": "^0.34.3"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
|
2
|
+
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
|
3
|
+
<style>
|
|
4
|
+
path { fill: #000; }
|
|
5
|
+
@media (prefers-color-scheme: dark) {
|
|
6
|
+
path { fill: #FFF; }
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
9
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Import the global.css file here so that it is included on
|
|
3
|
+
// all pages through the use of the <BaseHead /> component.
|
|
4
|
+
import '../styles/global.css';
|
|
5
|
+
import type { ImageMetadata } from 'astro';
|
|
6
|
+
import FallbackImage from '../assets/scrap-placeholder.png';
|
|
7
|
+
import { SITE_TITLE } from '../consts';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
image?: ImageMetadata;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
|
16
|
+
|
|
17
|
+
const { title, description, image = FallbackImage } = Astro.props;
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<!-- Global Metadata -->
|
|
21
|
+
<meta charset="utf-8" />
|
|
22
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
23
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
24
|
+
<link rel="icon" href="/favicon.ico" />
|
|
25
|
+
<link rel="sitemap" href="/sitemap-index.xml" />
|
|
26
|
+
|
|
27
|
+
<!-- Global CSS -->
|
|
28
|
+
<link rel="stylesheet" href="https://unpkg.com/papercss@1.9.2/dist/paper.min.css" />
|
|
29
|
+
|
|
30
|
+
<link
|
|
31
|
+
rel="alternate"
|
|
32
|
+
type="application/rss+xml"
|
|
33
|
+
title={SITE_TITLE}
|
|
34
|
+
href={new URL('rss.xml', Astro.site)}
|
|
35
|
+
/>
|
|
36
|
+
<meta name="generator" content={Astro.generator} />
|
|
37
|
+
|
|
38
|
+
<!-- Font preloads -->
|
|
39
|
+
<link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin />
|
|
40
|
+
<link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin />
|
|
41
|
+
|
|
42
|
+
<!-- Canonical URL -->
|
|
43
|
+
<link rel="canonical" href={canonicalURL} />
|
|
44
|
+
|
|
45
|
+
<!-- Primary Meta Tags -->
|
|
46
|
+
<title>{title}</title>
|
|
47
|
+
<meta name="title" content={title} />
|
|
48
|
+
<meta name="description" content={description} />
|
|
49
|
+
|
|
50
|
+
<!-- Open Graph / Facebook -->
|
|
51
|
+
<meta property="og:type" content="website" />
|
|
52
|
+
<meta property="og:url" content={Astro.url} />
|
|
53
|
+
<meta property="og:title" content={title} />
|
|
54
|
+
<meta property="og:description" content={description} />
|
|
55
|
+
<meta property="og:image" content={new URL(image.src, Astro.url)} />
|
|
56
|
+
|
|
57
|
+
<!-- Twitter -->
|
|
58
|
+
<meta property="twitter:card" content="summary_large_image" />
|
|
59
|
+
<meta property="twitter:url" content={Astro.url} />
|
|
60
|
+
<meta property="twitter:title" content={title} />
|
|
61
|
+
<meta property="twitter:description" content={description} />
|
|
62
|
+
<meta property="twitter:image" content={new URL(image.src, Astro.url)} />
|
|
63
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
const year = new Date().getFullYear();
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<footer class="paper padding-large text-center margin-top-large">
|
|
6
|
+
|
|
7
|
+
<p class="paper">
|
|
8
|
+
© {year} PaperAstro. Built with Astro and styled using PaperCSS. Forms powered by the
|
|
9
|
+
<a href="https://fabform.io" target="_blank">form backend service</a> fabform.io.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<div class="social-links flex justify-center gap-small margin-top-large">
|
|
13
|
+
|
|
14
|
+
<!-- GitHub -->
|
|
15
|
+
<a href="https://github.com/fabformhub/paperastro" target="_blank" class="paper-btn btn-small flex align-center gap-small">
|
|
16
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
17
|
+
<path d="M12 2a10 10 0 0 0-3 19.5c.5.1.7-.2.7-.5v-2c-3 .7-3.6-1.5-3.6-1.5-.5-1.2-1.2-1.5-1.2-1.5-1-.7.1-.7.1-.7 1 .1 1.6 1 1.6 1 .9 1.6 2.4 1.1 3 .8.1-.7.4-1.1.7-1.4-2.4-.3-5-1.2-5-5.4 0-1.1.4-2 1-2.7-.1-.3-.4-1.3.1-2.6 0 0 .8-.3 2.7 1a9.3 9.3 0 0 1 5 0c1.9-1.3 2.7-1 2.7-1 .5 1.3.2 2.3.1 2.6.6.7 1 1.6 1 2.7 0 4.2-2.6 5.1-5 5.4.4.3.8 1 .8 2v3c0 .3.2.6.7.5A10 10 0 0 0 12 2z"/>
|
|
18
|
+
</svg>
|
|
19
|
+
GitHub
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
</footer>
|
|
25
|
+
|
|
26
|
+
<style>
|
|
27
|
+
.gap-small {
|
|
28
|
+
gap: 0.5rem;
|
|
29
|
+
}
|
|
30
|
+
svg {
|
|
31
|
+
display: inline-block;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE_TITLE } from '../consts';
|
|
3
|
+
import HeaderLink from './HeaderLink.astro';
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<header class="paper">
|
|
7
|
+
<div class="container">
|
|
8
|
+
<nav class="padding-small flex align-center space-between">
|
|
9
|
+
|
|
10
|
+
<!-- Navigation Links -->
|
|
11
|
+
<div class="flex gap-small">
|
|
12
|
+
<HeaderLink href="/" class="paper-btn btn-small">{SITE_TITLE}</HeaderLink>
|
|
13
|
+
<HeaderLink href="/blog" class="paper-btn btn-small">Blog</HeaderLink>
|
|
14
|
+
<HeaderLink href="/about" class="paper-btn btn-small">About</HeaderLink>
|
|
15
|
+
<HeaderLink href="/contact" class="paper-btn btn-small">Contact</HeaderLink>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
</nav>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
+
|
|
4
|
+
type Props = HTMLAttributes<'a'>;
|
|
5
|
+
|
|
6
|
+
const { href, class: className, ...props } = Astro.props;
|
|
7
|
+
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
|
|
8
|
+
const subpath = pathname.match(/[^\/]+/g);
|
|
9
|
+
const isActive = href === pathname || href === '/' + (subpath?.[0] || '');
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<a
|
|
13
|
+
href={href}
|
|
14
|
+
class:list={[
|
|
15
|
+
"paper-btn btn-small no-decoration",
|
|
16
|
+
className,
|
|
17
|
+
{ active: isActive }
|
|
18
|
+
]}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</a>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
a {
|
|
26
|
+
display: inline-block;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.no-decoration {
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Active state */
|
|
34
|
+
a.active {
|
|
35
|
+
font-weight: bold;
|
|
36
|
+
box-shadow: 2px 2px 0 #000;
|
|
37
|
+
transform: translate(-1px, -1px);
|
|
38
|
+
transition: transform 0.05s ease;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
a.active:hover {
|
|
42
|
+
transform: translate(-2px, -2px);
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
|
package/src/consts.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Place any global data in this file.
|
|
2
|
+
// You can import this data from anywhere in your site by using the `import` keyword.
|
|
3
|
+
|
|
4
|
+
export const SITE_TITLE = 'PaperAstro';
|
|
5
|
+
export const SITE_DESCRIPTION = 'A hand‑drawn, lightweight Astro starter built with PaperCSS.';
|
|
6
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Getting Started with PaperAstro"
|
|
3
|
+
description: "An introduction to the PaperAstro starter template and how to begin using it."
|
|
4
|
+
pubDate: "Jan 1 2026"
|
|
5
|
+
heroImage: "../../assets/scrap-placeholder.png"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
PaperAstro is a lightweight starter template designed to help developers build clean, content‑focused websites using Astro and PaperCSS. This example post demonstrates how a typical article is structured within the template.
|
|
9
|
+
|
|
10
|
+
## Why PaperAstro exists
|
|
11
|
+
|
|
12
|
+
Many developers want a simple, minimal foundation for blogs or documentation sites without the overhead of a full design system. PaperAstro provides:
|
|
13
|
+
|
|
14
|
+
- A sketch‑inspired aesthetic powered by PaperCSS
|
|
15
|
+
- A clear and minimal project structure
|
|
16
|
+
- Built‑in support for MDX, RSS, and sitemaps
|
|
17
|
+
- Form handling through Fabform.io
|
|
18
|
+
- Fast performance enabled by Astro’s modern architecture
|
|
19
|
+
|
|
20
|
+
## Writing content
|
|
21
|
+
|
|
22
|
+
Blog posts are stored in the `src/content/blog/` directory and use frontmatter to define metadata such as:
|
|
23
|
+
|
|
24
|
+
- `title`
|
|
25
|
+
- `description`
|
|
26
|
+
- `pubDate`
|
|
27
|
+
- `heroImage`
|
|
28
|
+
|
|
29
|
+
Content can be written in Markdown or MDX, depending on your needs.
|
|
30
|
+
|
|
31
|
+
## Adding images
|
|
32
|
+
|
|
33
|
+
Hero images can be added by referencing files inside the `src/assets/` directory. PaperAstro uses Astro’s built‑in image optimization to ensure images are responsive and efficient.
|
|
34
|
+
|
|
35
|
+
## Customizing the layout
|
|
36
|
+
|
|
37
|
+
You can modify the blog layout by editing:
|
|
38
|
+
|
|
39
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Understanding the PaperAstro Project Structure"
|
|
3
|
+
description: "A walkthrough of the core folders and files that make up the PaperAstro starter template."
|
|
4
|
+
pubDate: "Jan 11 2026"
|
|
5
|
+
heroImage: "../../assets/scrap-placeholder.png"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
PaperAstro is designed to be minimal, clear, and easy to extend. This post provides an overview of the project structure so you can quickly understand how the template is organized and where to make changes.
|
|
9
|
+
|
|
10
|
+
## Key directories
|
|
11
|
+
|
|
12
|
+
The main folders you will work with include:
|
|
13
|
+
|
|
14
|
+
### `src/pages/`
|
|
15
|
+
This directory contains your site’s routes. Each `.astro` or `.md` file becomes a page on your website.
|
|
16
|
+
Examples include:
|
|
17
|
+
|
|
18
|
+
- `index.astro` for the homepage
|
|
19
|
+
- `about.astro` for the About page
|
|
20
|
+
- `contact.astro` for the contact form
|
|
21
|
+
|
|
22
|
+
### `src/components/`
|
|
23
|
+
Reusable UI components such as the header, footer, and utility components live here.
|
|
24
|
+
You can add your own components to keep your layout clean and modular.
|
|
25
|
+
|
|
26
|
+
### `src/layouts/`
|
|
27
|
+
Layouts define the structure shared across multiple pages.
|
|
28
|
+
For example, `BlogPost.astro` controls how individual blog posts are displayed.
|
|
29
|
+
|
|
30
|
+
### `src/content/blog/`
|
|
31
|
+
This folder contains your Markdown or MDX blog posts.
|
|
32
|
+
Each post includes frontmatter metadata such as:
|
|
33
|
+
|
|
34
|
+
- `title`
|
|
35
|
+
- `description`
|
|
36
|
+
- `pubDate`
|
|
37
|
+
- `heroImage`
|
|
38
|
+
|
|
39
|
+
## Assets and styling
|
|
40
|
+
|
|
41
|
+
### `src/assets/`
|
|
42
|
+
Images, hero graphics, and other static assets are stored here.
|
|
43
|
+
Astro’s image optimization pipeline ensures they are responsive and efficient.
|
|
44
|
+
|
|
45
|
+
### PaperCSS styling
|
|
46
|
+
PaperAstro uses PaperCSS for all styling. No custom CSS is required, but you can extend the design by adding your own styles if needed.
|
|
47
|
+
|
|
48
|
+
## Configuration files
|
|
49
|
+
|
|
50
|
+
### `astro.config.mjs`
|
|
51
|
+
Controls Astro integrations, build settings, and site configuration.
|
|
52
|
+
|
|
53
|
+
### `src/consts.ts`
|
|
54
|
+
Stores global constants such as the site title and description.
|
|
55
|
+
|
|
56
|
+
## Extending the template
|
|
57
|
+
|
|
58
|
+
PaperAstro is intentionally minimal, giving you the freedom to:
|
|
59
|
+
|
|
60
|
+
- Add new pages
|
|
61
|
+
- Create custom layouts
|
|
62
|
+
- Integrate additional Astro features
|
|
63
|
+
- Expand the blog section
|
|
64
|
+
- Introduce new components
|
|
65
|
+
|
|
66
|
+
The structure is designed to stay out of your way while providing a solid foundation for content‑driven websites.
|
|
67
|
+
|
|
68
|
+
## Summary
|
|
69
|
+
|
|
70
|
+
Understanding the project structure is the first step toward customizing PaperAstro for your needs.
|
|
71
|
+
With a clear layout and minimal overhead, you can quickly build a site that is both functional and visually distinctive.
|
|
72
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
|
2
|
+
import { glob } from 'astro/loaders';
|
|
3
|
+
|
|
4
|
+
const blog = defineCollection({
|
|
5
|
+
// Load Markdown and MDX files in the `src/content/blog/` directory.
|
|
6
|
+
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
|
|
7
|
+
// Type-check frontmatter using a schema
|
|
8
|
+
schema: ({ image }) =>
|
|
9
|
+
z.object({
|
|
10
|
+
title: z.string(),
|
|
11
|
+
description: z.string(),
|
|
12
|
+
// Transform string to Date object
|
|
13
|
+
pubDate: z.coerce.date(),
|
|
14
|
+
updatedDate: z.coerce.date().optional(),
|
|
15
|
+
heroImage: image().optional(),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const collections = { blog };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Image } from 'astro:assets';
|
|
3
|
+
import type { CollectionEntry } from 'astro:content';
|
|
4
|
+
import BaseHead from '../components/BaseHead.astro';
|
|
5
|
+
import Footer from '../components/Footer.astro';
|
|
6
|
+
import FormattedDate from '../components/FormattedDate.astro';
|
|
7
|
+
import Header from '../components/Header.astro';
|
|
8
|
+
|
|
9
|
+
type Props = CollectionEntry<'blog'>['data'];
|
|
10
|
+
|
|
11
|
+
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<html lang="en">
|
|
15
|
+
<head>
|
|
16
|
+
<BaseHead title={title} description={description} />
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
<Header />
|
|
21
|
+
|
|
22
|
+
<main class="container padding-large">
|
|
23
|
+
<article class="paper">
|
|
24
|
+
|
|
25
|
+
<!-- Hero Image -->
|
|
26
|
+
<div class="hero-image margin-bottom-large">
|
|
27
|
+
{heroImage && (
|
|
28
|
+
<Image
|
|
29
|
+
width={1020}
|
|
30
|
+
height={510}
|
|
31
|
+
src={heroImage}
|
|
32
|
+
alt={title}
|
|
33
|
+
class="img-responsive paper"
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- Title + Dates -->
|
|
39
|
+
<div class="text-center margin-bottom-large">
|
|
40
|
+
<h1 class="paper">{title}</h1>
|
|
41
|
+
|
|
42
|
+
<p class="paper">
|
|
43
|
+
Published on <FormattedDate date={pubDate} />
|
|
44
|
+
{updatedDate && (
|
|
45
|
+
<>
|
|
46
|
+
<br />
|
|
47
|
+
<span class="italic">
|
|
48
|
+
Last updated on <FormattedDate date={updatedDate} />
|
|
49
|
+
</span>
|
|
50
|
+
</>
|
|
51
|
+
)}
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
<hr />
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Blog Content -->
|
|
58
|
+
<div class="paper padding-large">
|
|
59
|
+
<slot />
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!-- Footer Note -->
|
|
63
|
+
<p class="text-center margin-top-large paper">
|
|
64
|
+
Thank you for reading. This article is part of the PaperAstro starter template.
|
|
65
|
+
</p>
|
|
66
|
+
|
|
67
|
+
</article>
|
|
68
|
+
</main>
|
|
69
|
+
|
|
70
|
+
<Footer />
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
|
73
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
import AboutHeroImage from '../assets/scrap-placeholder.png';
|
|
3
|
+
import Layout from '../layouts/BlogPost.astro';
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<Layout
|
|
7
|
+
title="About PaperAstro"
|
|
8
|
+
description="Learn more about the purpose and philosophy behind the PaperAstro starter template."
|
|
9
|
+
pubDate={new Date('August 08 2021')}
|
|
10
|
+
heroImage={AboutHeroImage}
|
|
11
|
+
>
|
|
12
|
+
<p class="paper">
|
|
13
|
+
PaperAstro is a lightweight Astro starter template designed for developers who want a clean,
|
|
14
|
+
sketch‑inspired aesthetic without sacrificing performance or simplicity. It combines the speed
|
|
15
|
+
and flexibility of Astro with the hand‑drawn visual style of PaperCSS, resulting in a unique
|
|
16
|
+
foundation for blogs, documentation sites, and small web projects.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p class="paper">
|
|
20
|
+
This project was created to offer a minimal, approachable starting point for developers who
|
|
21
|
+
appreciate clarity and structure. PaperAstro avoids unnecessary complexity and focuses on
|
|
22
|
+
providing a solid, well‑organized base that can be extended in any direction.
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p class="paper">
|
|
26
|
+
Key principles behind PaperAstro include:
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<ul class="paper">
|
|
30
|
+
<li>Clean, readable code that is easy to understand and modify</li>
|
|
31
|
+
<li>A minimal design system powered entirely by PaperCSS</li>
|
|
32
|
+
<li>Fast performance enabled by Astro’s modern architecture</li>
|
|
33
|
+
<li>Practical defaults for content‑driven websites</li>
|
|
34
|
+
</ul>
|
|
35
|
+
|
|
36
|
+
<p class="paper">
|
|
37
|
+
PaperAstro also includes built‑in support for form handling through Fabform, making it simple
|
|
38
|
+
to add contact forms or other user input without managing backend infrastructure.
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<p class="paper">
|
|
42
|
+
Whether you're building a personal site, a small publication, or a documentation hub,
|
|
43
|
+
PaperAstro provides a reliable foundation that stays out of your way while giving your project
|
|
44
|
+
a distinctive visual character.
|
|
45
|
+
</p>
|
|
46
|
+
</Layout>
|
|
47
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { type CollectionEntry, getCollection, render } from 'astro:content';
|
|
3
|
+
import BlogPost from '../../layouts/BlogPost.astro';
|
|
4
|
+
|
|
5
|
+
export async function getStaticPaths() {
|
|
6
|
+
const posts = await getCollection('blog');
|
|
7
|
+
return posts.map((post) => ({
|
|
8
|
+
params: { slug: post.id },
|
|
9
|
+
props: post,
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
type Props = CollectionEntry<'blog'>;
|
|
13
|
+
|
|
14
|
+
const post = Astro.props;
|
|
15
|
+
const { Content } = await render(post);
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<BlogPost {...post.data}>
|
|
19
|
+
<Content />
|
|
20
|
+
</BlogPost>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Image } from 'astro:assets';
|
|
3
|
+
import { getCollection } from 'astro:content';
|
|
4
|
+
import BaseHead from '../../components/BaseHead.astro';
|
|
5
|
+
import Footer from '../../components/Footer.astro';
|
|
6
|
+
import FormattedDate from '../../components/FormattedDate.astro';
|
|
7
|
+
import Header from '../../components/Header.astro';
|
|
8
|
+
import { SITE_DESCRIPTION, SITE_TITLE } from '../../consts';
|
|
9
|
+
|
|
10
|
+
const posts = (await getCollection('blog')).sort(
|
|
11
|
+
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
|
12
|
+
);
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<!doctype html>
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<head>
|
|
18
|
+
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
|
19
|
+
</head>
|
|
20
|
+
|
|
21
|
+
<body>
|
|
22
|
+
<Header />
|
|
23
|
+
|
|
24
|
+
<main class="container padding-large">
|
|
25
|
+
|
|
26
|
+
<h1 class="paper text-center">
|
|
27
|
+
<span class="inline-icon">
|
|
28
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
29
|
+
<rect x="3" y="4" width="18" height="16" rx="2" ry="2" />
|
|
30
|
+
<line x1="7" y1="8" x2="17" y2="8" />
|
|
31
|
+
<line x1="7" y1="12" x2="17" y2="12" />
|
|
32
|
+
<line x1="7" y1="16" x2="13" y2="16" />
|
|
33
|
+
</svg>
|
|
34
|
+
</span>
|
|
35
|
+
The Papery Blog Roll
|
|
36
|
+
</h1>
|
|
37
|
+
|
|
38
|
+
<p class="paper text-center">
|
|
39
|
+
Welcome to the official archive of all things scribbled, doodled, typed,
|
|
40
|
+
or accidentally published. Each post below has been lovingly handcrafted
|
|
41
|
+
using Astro and PaperCSS, then pinned to this digital bulletin board for
|
|
42
|
+
your reading pleasure.
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<section class="margin-top-large">
|
|
46
|
+
<ul class="flex flex-wrap gap-large no-bullet justify-center">
|
|
47
|
+
{
|
|
48
|
+
posts.map((post) => (
|
|
49
|
+
<li class="paper padding-small" style="width: 100%; max-width: 420px;">
|
|
50
|
+
<a href={`/blog/${post.id}/`} class="no-decoration">
|
|
51
|
+
{post.data.heroImage && (
|
|
52
|
+
<Image
|
|
53
|
+
width={720}
|
|
54
|
+
height={360}
|
|
55
|
+
src={post.data.heroImage}
|
|
56
|
+
alt=""
|
|
57
|
+
class="img-responsive paper margin-bottom-small"
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
|
|
61
|
+
<h4 class="margin-none">{post.data.title}</h4>
|
|
62
|
+
|
|
63
|
+
<p class="italic margin-none">
|
|
64
|
+
<FormattedDate date={post.data.pubDate} />
|
|
65
|
+
</p>
|
|
66
|
+
</a>
|
|
67
|
+
</li>
|
|
68
|
+
))
|
|
69
|
+
}
|
|
70
|
+
</ul>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<p class="paper text-center margin-top-large">
|
|
74
|
+
<span class="inline-icon">
|
|
75
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
76
|
+
<path d="M5 19h14M5 5h14M5 12h8" />
|
|
77
|
+
</svg>
|
|
78
|
+
</span>
|
|
79
|
+
That’s all for now. More papery posts are already scribbled in the margins.
|
|
80
|
+
</p>
|
|
81
|
+
|
|
82
|
+
</main>
|
|
83
|
+
|
|
84
|
+
<Footer />
|
|
85
|
+
</body>
|
|
86
|
+
</html>
|
|
87
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
import BaseHead from '../components/BaseHead.astro';
|
|
3
|
+
import Header from '../components/Header.astro';
|
|
4
|
+
import Footer from '../components/Footer.astro';
|
|
5
|
+
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!doctype html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<BaseHead title={`${SITE_TITLE} – Contact`} description={SITE_DESCRIPTION} />
|
|
12
|
+
</head>
|
|
13
|
+
|
|
14
|
+
<body>
|
|
15
|
+
<Header />
|
|
16
|
+
|
|
17
|
+
<!--
|
|
18
|
+
============================
|
|
19
|
+
FABFORM.IO INTEGRATION NOTES
|
|
20
|
+
============================
|
|
21
|
+
|
|
22
|
+
Replace YOUR-ENDPOINT-ID-HERE with your Fabform endpoint.
|
|
23
|
+
Example: https://fabform.io/f/abc123
|
|
24
|
+
|
|
25
|
+
Do NOT remove name="" attributes — Fabform needs them.
|
|
26
|
+
Do NOT expose API keys — Fabform does not require any.
|
|
27
|
+
-->
|
|
28
|
+
|
|
29
|
+
<main class="container padding-large">
|
|
30
|
+
|
|
31
|
+
<div class="paper padding-large">
|
|
32
|
+
|
|
33
|
+
<h1 class="text-center">
|
|
34
|
+
<span class="inline-icon">
|
|
35
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
36
|
+
<rect x="3" y="4" width="18" height="16" rx="2" ry="2" />
|
|
37
|
+
<line x1="7" y1="8" x2="17" y2="8" />
|
|
38
|
+
</svg>
|
|
39
|
+
</span>
|
|
40
|
+
Contact
|
|
41
|
+
</h1>
|
|
42
|
+
|
|
43
|
+
<p class="text-center">
|
|
44
|
+
Use the form below to send a message.
|
|
45
|
+
This form is styled with PaperCSS and securely processed by Fabform.io.
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<form
|
|
49
|
+
action="https://fabform.io/f/YOUR-ENDPOINT-ID-HERE"
|
|
50
|
+
method="POST"
|
|
51
|
+
class="margin-top-large"
|
|
52
|
+
>
|
|
53
|
+
|
|
54
|
+
<div class="form-group">
|
|
55
|
+
<label for="name">Your Name</label>
|
|
56
|
+
<input class="input-block" type="text" id="name" name="name" required>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="form-group">
|
|
60
|
+
<label for="email">Your Email</label>
|
|
61
|
+
<input class="input-block" type="email" id="email" name="email" required>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="form-group">
|
|
65
|
+
<label for="subject">Subject</label>
|
|
66
|
+
<select id="subject" name="subject" class="input-block">
|
|
67
|
+
<option value="general">General Message</option>
|
|
68
|
+
<option value="feedback">Feedback</option>
|
|
69
|
+
<option value="support">Support Request</option>
|
|
70
|
+
</select>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="form-group">
|
|
74
|
+
<label for="message">Your Message</label>
|
|
75
|
+
<textarea class="input-block no-resize" id="message" name="message" rows="6" required></textarea>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<fieldset class="form-group">
|
|
79
|
+
<legend>Stay Updated</legend>
|
|
80
|
+
|
|
81
|
+
<label class="paper-check" for="newsletter">
|
|
82
|
+
<input type="checkbox" id="newsletter" name="newsletter" value="yes">
|
|
83
|
+
<span>Subscribe to updates</span>
|
|
84
|
+
</label>
|
|
85
|
+
</fieldset>
|
|
86
|
+
|
|
87
|
+
<button type="submit" class="paper-btn btn-primary btn-block margin-top">
|
|
88
|
+
Send Message
|
|
89
|
+
</button>
|
|
90
|
+
|
|
91
|
+
</form>
|
|
92
|
+
|
|
93
|
+
<div class="text-center margin-top-large">
|
|
94
|
+
<a href="https://fabform.io" target="_blank" class="badge secondary">
|
|
95
|
+
Powered by Fabform.io
|
|
96
|
+
</a>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
</main>
|
|
102
|
+
|
|
103
|
+
<Footer />
|
|
104
|
+
|
|
105
|
+
<style>
|
|
106
|
+
.inline-icon {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
vertical-align: middle;
|
|
109
|
+
margin-right: 0.35rem;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
114
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
import BaseHead from '../components/BaseHead.astro';
|
|
3
|
+
import Footer from '../components/Footer.astro';
|
|
4
|
+
import Header from '../components/Header.astro';
|
|
5
|
+
import { SITE_DESCRIPTION, SITE_TITLE } from '../consts';
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!doctype html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<Header />
|
|
15
|
+
|
|
16
|
+
<main class="container padding-large">
|
|
17
|
+
|
|
18
|
+
<h1 class="text-center paper">Welcome to PaperAstro</h1>
|
|
19
|
+
|
|
20
|
+
<p class="paper">
|
|
21
|
+
PaperAstro is a lightweight, professional starter template built with Astro and styled
|
|
22
|
+
entirely using PaperCSS. It provides a clean, sketch‑inspired aesthetic while maintaining
|
|
23
|
+
strong performance, clarity, and simplicity.
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p class="paper">
|
|
27
|
+
This template is designed for developers who want a minimal, well‑structured foundation
|
|
28
|
+
for blogs, documentation sites, or small content‑driven projects. PaperAstro keeps the
|
|
29
|
+
design approachable and distinctive without adding unnecessary complexity.
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
<h2 class="paper">Features</h2>
|
|
33
|
+
|
|
34
|
+
<ul class="paper">
|
|
35
|
+
<li>Clean, minimal layout powered by Astro</li>
|
|
36
|
+
<li>Sketch‑style UI using PaperCSS</li>
|
|
37
|
+
<li>MDX support for rich content</li>
|
|
38
|
+
<li>RSS and Sitemap integrations included</li>
|
|
39
|
+
<li>Image optimization via Sharp</li>
|
|
40
|
+
<li>Built‑in form handling through Fabform.io</li>
|
|
41
|
+
</ul>
|
|
42
|
+
|
|
43
|
+
<h2 class="paper">Getting Started</h2>
|
|
44
|
+
|
|
45
|
+
<p class="paper">
|
|
46
|
+
To begin customizing this template, edit the files inside the <code>src</code> directory.
|
|
47
|
+
The structure is intentionally simple, making it easy to adapt the layout, add pages,
|
|
48
|
+
or integrate additional Astro features.
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<ul class="paper">
|
|
52
|
+
<li>Modify this page at <code>src/pages/index.astro</code></li>
|
|
53
|
+
<li>Add new routes inside <code>src/pages/</code></li>
|
|
54
|
+
<li>Update global settings in <code>src/consts.ts</code></li>
|
|
55
|
+
<li>Extend layouts or components as needed</li>
|
|
56
|
+
</ul>
|
|
57
|
+
|
|
58
|
+
<h2 class="paper">Resources</h2>
|
|
59
|
+
|
|
60
|
+
<ul class="paper">
|
|
61
|
+
<li><a href="https://docs.astro.build/">Astro Documentation</a></li>
|
|
62
|
+
<li><a href="https://www.getpapercss.com/">PaperCSS Documentation</a></li>
|
|
63
|
+
<li><a href="https://fabform.io">Fabform.io</a> for form handling</li>
|
|
64
|
+
</ul>
|
|
65
|
+
|
|
66
|
+
<p class="paper text-center">
|
|
67
|
+
PaperAstro provides a focused, reliable starting point for your next project.
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
</main>
|
|
71
|
+
|
|
72
|
+
<Footer />
|
|
73
|
+
</body>
|
|
74
|
+
</html>
|
|
75
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
import rss from '@astrojs/rss';
|
|
3
|
+
import { SITE_DESCRIPTION, SITE_TITLE } from '../consts';
|
|
4
|
+
|
|
5
|
+
export async function GET(context) {
|
|
6
|
+
const posts = await getCollection('blog');
|
|
7
|
+
return rss({
|
|
8
|
+
title: SITE_TITLE,
|
|
9
|
+
description: SITE_DESCRIPTION,
|
|
10
|
+
site: context.site,
|
|
11
|
+
items: posts.map((post) => ({
|
|
12
|
+
...post.data,
|
|
13
|
+
link: `/blog/${post.id}/`,
|
|
14
|
+
})),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
Binary file
|
|
File without changes
|