Bring project over into monorepo

This commit is contained in:
Chris Swithinbank 2023-06-14 17:50:31 +02:00 committed by Tony Sullivan
parent 60684fad72
commit 07ccbe03a6
40 changed files with 1289 additions and 0 deletions

21
examples/social-feed/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

View file

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

View file

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

View file

@ -0,0 +1,46 @@
# Astro Starter Kit: Social Feed
```
npm create astro@latest -- --template social-feed
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/social-feed)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/s/github/withastro/astro/tree/latest/examples/social-feed)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :--------------------- | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:3000` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View file

@ -0,0 +1,6 @@
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
site: 'https://www.example.com',
});

View file

@ -0,0 +1,17 @@
{
"name": "@example/social-feed",
"type": "module",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/rss": "^2.4.3",
"astro": "^2.6.4"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
<path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
<path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
<defs>
<linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#000"/>
<stop offset="1" stop-color="#000" stop-opacity="0"/>
</linearGradient>
</defs>
<style>
@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}
</style>
</svg>

After

Width:  |  Height:  |  Size: 873 B

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,53 @@
---
import settings from '../settings';
import Icon from './Icon.astro';
---
<footer>
<div class="row">
<p>
Copyright © {new Date().getFullYear()}
{settings.name}
</p>
<p>
Designed & Developed with<Icon icon="heart" size="1.75em" />
<span class="sr-only">love</span>
</p>
<p><a href="/rss.xml"><Icon icon="rss-alt" size="1.75em" />RSS</a></p>
</div>
<div class="row">
<a href={settings.social.twitter}>Twitter</a>
<a href={settings.social.twitch}>Twitch</a>
<a href={settings.social.github}>GitHub</a>
<a href={settings.social.devto}>DEV</a>
<a href={settings.social.codepen}>Codepen</a>
</div>
</footer>
<style>
footer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: auto;
border-top: 3px solid var(--theme-shade-subtle);
border-radius: var(--theme-radius-xl);
padding: 1.5rem;
gap: 1rem;
color: var(--theme-gray-200);
font-size: var(--theme-text-sm);
}
.row {
display: flex;
flex-wrap: wrap;
gap: 0 1.5rem;
justify-content: center;
}
a {
color: inherit;
text-decoration: none;
}
</style>

View file

@ -0,0 +1,31 @@
---
import settings from '../settings';
import ThemeToggle from './ThemeToggle.astro';
---
<header>
<a class="site-name" href="/">{settings.username}</a>
<ThemeToggle />
</header>
<style>
header {
display: flex;
justify-content: space-between;
align-items: center;
}
.site-name {
font-size: var(--theme-text-lg);
font-weight: 700;
font-family: var(--theme-font-brand);
text-decoration: none;
color: transparent;
background: var(--theme-gradient-main);
background-clip: text;
}
.site-name:hover {
text-decoration: 1px solid underline var(--theme-accent-dark);
}
</style>

View file

@ -0,0 +1,32 @@
---
import { iconPaths } from './IconPaths';
export interface Props {
icon: keyof typeof iconPaths;
color?: string;
size?: string;
}
const { icon, color, size } = Astro.props;
const iconPath = iconPaths[icon];
---
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 256 256"
aria-hidden="true"
stroke="currentcolor"
fill="currentcolor"
set:html={iconPath}
/>
<style define:vars={{ color, size }}>
svg {
color: var(--color, inherit);
vertical-align: middle;
width: var(--size, 1em);
height: var(--size, 1em);
}
</style>

View file

@ -0,0 +1,33 @@
/**
* Want to add more icons?
* 1. Find the icon you want as an SVG.
* 2. Scale it to 256×256px.
* 3. Paste the SVG code in your editor.
* 4. Remove the `<svg>` wrapper so you only have elements like `<path>`, `<circle>`, `<rect>` etc.
* 5. Remove any `stroke="{color}"` attributes
* 6. Replace any `fill="{color}"` attributes with `stroke="none"`
* (or add `stroke="none"` on shapes with no `fill` or `stroke` specified).
*/
export const iconPaths = {
'arrow-right': `<path d="m117.5 69.6 7-7c2.9-3 7.6-3 10.6 0l60.7 60.7c3 3 3 7.7 0 10.6L135 194.6c-3 3-7.7 3-10.6 0l-7-6.9c-3-3-2.9-7.8.2-10.7l37.6-35.9H65.5a7.5 7.5 0 0 1-7.5-7.5v-10c0-4.1 3.4-7.5 7.5-7.5h89.8l-37.6-35.8a7.4 7.4 0 0 1-.2-10.7Z"/>`,
'arrow-left': `<path d="m138.5 187-7 7c-2.9 3-7.6 3-10.6 0l-60.7-60.7c-3-3-3-7.7 0-10.6L121 62c3-3 7.7-3 10.6 0l7 7c3 2.9 2.9 7.7-.2 10.6l-37.6 35.9h89.8c4.1 0 7.5 3.3 7.5 7.5v10c0 4.2-3.4 7.5-7.5 7.5h-89.8l37.6 35.9a7.4 7.4 0 0 1 .2 10.7Z"/>`,
'rss-alt': `<path d="M71.8 153.01a28.65 28.65 0 1 0 40.49 40.5 28.65 28.65 0 0 0 0-40.5 29.41 29.41 0 0 0-40.49 0Zm27.02 27.03a9.55 9.55 0 0 1-13.56 0 9.55 9.55 0 0 1 0-13.56 9.55 9.55 0 0 1 13.56 0 9.54 9.54 0 0 1 0 13.56Zm-6.78-73.62a9.55 9.55 0 1 0 0 19.1 47.74 47.74 0 0 1 47.75 47.74 9.55 9.55 0 1 0 19.1 0 66.84 66.84 0 0 0-66.85-66.84Zm0-38.2a9.55 9.55 0 1 0 0 19.1 85.94 85.94 0 0 1 85.94 85.94 9.55 9.55 0 1 0 19.1 0A105.04 105.04 0 0 0 92.04 68.22Z"/>`,
'link-h': `<path d="M96.9 128.25a7.78 7.78 0 0 0 7.77 7.77h46.66a7.78 7.78 0 1 0 0-15.55h-46.66a7.77 7.77 0 0 0-7.78 7.78Zm15.55 23.32H89.12a23.33 23.33 0 0 1 0-46.65h23.33a7.78 7.78 0 1 0 0-15.55H89.12a38.88 38.88 0 0 0 0 77.76h23.33a7.78 7.78 0 1 0 0-15.56Zm54.43-62.2h-23.33a7.78 7.78 0 1 0 0 15.55h23.33a23.33 23.33 0 0 1 0 46.65h-23.33a7.77 7.77 0 1 0 0 15.56h23.33a38.88 38.88 0 1 0 0-77.76Z"/>`,
'location-point': `<path d="M193.8 110.2a66.1 66.1 0 1 0-112.5 53.1l41.3 41.3a7.8 7.8 0 0 0 11 0l41-41.3a65.8 65.8 0 0 0 19.2-53.1Zm-30 42.1L128 188.1l-35.8-35.8a50.5 50.5 0 0 1-7.5-61.9A51 51 0 0 1 128 65.8a50.3 50.3 0 0 1 50.3 45.8 50.5 50.5 0 0 1-14.5 40.7ZM128 82a35 35 0 1 0 0 70 35 35 0 0 0 0-70Zm0 54.4a19.4 19.4 0 1 1 0-38.9 19.4 19.4 0 0 1 0 38.9Z"/>`,
user: `<path d="M156.9 133.5a46.7 46.7 0 1 0-57.7 0 77.8 77.8 0 0 0-48.4 63.6 7.8 7.8 0 0 0 15.5 1.7 62.2 62.2 0 0 1 123.7 0 7.8 7.8 0 0 0 7.8 7h.8a7.8 7.8 0 0 0 6.9-8.6 77.8 77.8 0 0 0-48.6-63.7ZM128 128a31.1 31.1 0 1 1 0-62.2 31.1 31.1 0 0 1 0 62.2Z"/>`,
heart: `<path d="M187.84 74.61A46.17 46.17 0 0 0 128 70.16a46.17 46.17 0 0 0-62.29 6.86 45.56 45.56 0 0 0 2.45 62.27l54.63 54.32a7.32 7.32 0 0 0 8.03 1.6c.9-.37 1.7-.92 2.39-1.6l54.63-54.32a45.68 45.68 0 0 0 13.48-32.34 45.48 45.48 0 0 0-13.48-32.34Zm-10.34 54.4L128 178.15l-49.5-49.14a31.15 31.15 0 0 1-6.8-33.89 31.24 31.24 0 0 1 11.47-14 31.51 31.51 0 0 1 17.33-5.34c8.26.02 16.17 3.3 22 9.11a7.34 7.34 0 0 0 10.41 0 31.42 31.42 0 0 1 42.74 1.6 31.05 31.05 0 0 1 1.26 42.52h.59Z"/>`,
'moon-stars': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="20" d="M216 112V64m24 24h-48m-24-64v32m16-16h-32m65 113A92 92 0 0 1 103 39h0a92 92 0 1 0 114 114Z"/>`,
sun: `<circle cx="128" cy="128" r="60" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="20"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="20" d="M128 36V16M63 63 49 49m-13 79H16m47 65-14 14m79 13v20m65-47 14 14m13-79h20m-47-65 14-14"/>`,
'twitter-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M128 88c0-22 18.5-40.3 40.5-40a40 40 0 0 1 36.2 24H240l-32.3 32.3A127.9 127.9 0 0 1 80 224c-32 0-40-12-40-12s32-12 48-36c0 0-64-32-48-120 0 0 40 40 88 48Z"/>`,
'codepen-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m232 101-104 59-104-59 100.1-56.8a8.3 8.3 0 0 1 7.8 0Z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m232 165-100.1 56.8a8.3 8.3 0 0 1-7.8 0L24 165l104-59Zm0-64v64M24 101v64m104-5v62.8m0-179.6V106"/>`,
'github-logo': `<g stroke-linecap="round" stroke-linejoin="round"><path fill="none" stroke-width="14.7" d="M55.7 167.2c13.9 1 21.3 13.1 22.2 14.6 4.2 7.2 10.4 9.6 18.3 7.1l1.1-3.4a60.3 60.3 0 0 1-25.8-11.9c-12-10.1-18-25.6-18-46.3"/><path fill="none" stroke-width="16" d="M61.4 205.1a24.5 24.5 0 0 1-3-6.1c-3.2-7.9-7.1-10.6-7.8-11.1l-1-.6c-2.4-1.6-9.5-6.5-7.2-13.9 1.4-4.5 6-7.2 12.3-7.2h.8c4 .3 7.6 1.5 10.7 3.2-9.1-10.1-13.6-24.3-13.6-42.3 0-11.3 3.5-21.7 10.1-30.4A46.7 46.7 0 0 1 65 67.3a8.3 8.3 0 0 1 5-4.7c2.8-.9 13.3-2.7 33.2 9.9a105 105 0 0 1 50.5 0c19.9-12.6 30.4-10.8 33.2-9.9 2.3.7 4.1 2.4 5 4.7 5 12.7 4 23.2 2.6 29.4 6.7 8.7 10 18.9 10 30.4 0 42.6-25.8 54.7-43.6 58.7 1.4 4.1 2.2 8.8 2.2 13.7l-.1 23.4v2.3"/><path fill="none" stroke-width="16" d="M160.9 185.7c1.4 4.1 2.2 8.8 2.2 13.7l-.1 23.4v2.3A98.6 98.6 0 1 0 61.4 205c-1.4-2.1-11.3-17.5-11.8-17.8-2.4-1.6-9.5-6.5-7.2-13.9 1.4-4.5 6-7.2 12.3-7.2h.8c4 .3 7.6 1.5 10.7 3.2-9.1-10.1-13.6-24.3-13.6-42.3 0-11.3 3.5-21.7 10.1-30.4A46.4 46.4 0 0 1 65 67.3a8.3 8.3 0 0 1 5-4.7c2.8-.9 13.3-2.7 33.2 9.9a105 105 0 0 1 50.5 0c19.9-12.6 30.4-10.8 33.2-9.9 2.3.7 4.1 2.4 5 4.7 5 12.7 4 23.2 2.6 29.4 6.7 8.7 10 18.9 10 30.4.1 42.6-25.8 54.7-43.6 58.6z"/><path fill="none" stroke-width="18.7" d="m170.1 203.3 17.3-12 17.2-18.7 9.5-26.6v-27.9l-9.5-27.5" /><path fill="none" stroke-width="22.7" d="m92.1 57.3 23.3-4.6 18.7-1.4 29.3 5.4m-110 32.6-8 16-4 21.4.6 20.3 3.4 13" /><path fill="none" stroke-width="13.3" d="M28.8 133a100 100 0 0 0 66.9 94.4v-8.7c-22.4 1.8-33-11.5-35.6-19.8-3.4-8.6-7.8-11.4-8.5-11.8"/></g>`,
'twitch-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M165 200h-42a8 8 0 0 0-5 2l-46 38v-40H48a8 8 0 0 1-8-8V48a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8v108a8 8 0 0 1-3 6l-43 36a8 8 0 0 1-5 2Zm3-112v48m-48-48v48"/>`,
'youtube-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m160 128-48-32v64l48-32z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M24 128c0 30 3 47 5 56a16 16 0 0 0 10 11c34 13 89 13 89 13s56 0 89-13a16 16 0 0 0 10-11c2-9 5-26 5-56s-3-47-5-56a16 16 0 0 0-10-11c-33-13-89-13-89-13s-55 0-89 13a16 16 0 0 0-10 11c-2 9-5 26-5 56Z"/>`,
'dribbble-logo': `<circle cx="128" cy="128" r="96" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M71 205a160 160 0 0 1 137-77l16 1m-36-76a160 160 0 0 1-124 59 165 165 0 0 1-30-3"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M86 42a161 161 0 0 1 74 177"/>`,
'discord-logo': `<circle stroke="none" cx="96" cy="144" r="12"/><circle stroke="none" cx="160" cy="144" r="12"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M74 80a175 175 0 0 1 54-8 175 175 0 0 1 54 8m0 96a175 175 0 0 1-54 8 175 175 0 0 1-54-8"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m155 182 12 24a8 8 0 0 0 9 4c25-6 46-16 61-30a8 8 0 0 0 3-8L206 59a8 8 0 0 0-5-5 176 176 0 0 0-30-9 8 8 0 0 0-9 5l-8 24m-53 108-12 24a8 8 0 0 1-9 4c-25-6-46-16-61-30a8 8 0 0 1-3-8L50 59a8 8 0 0 1 5-5 176 176 0 0 1 30-9 8 8 0 0 1 9 5l8 24"/>`,
'linkedin-logo': `<rect width="184" height="184" x="36" y="36" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" rx="8"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M120 112v64m-32-64v64m32-36a28 28 0 0 1 56 0v36"/><circle stroke="none" cx="88" cy="80" r="12"/>`,
'instagram-logo': `<circle cx="128" cy="128" r="40" fill="none" stroke-miterlimit="10" stroke-width="16"/><rect width="184" height="184" x="36" y="36" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" rx="48"/><circle cx="180" cy="76" r="12" stroke="none" />`,
'tiktok-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M168 106a96 96 0 0 0 56 18V84a56 56 0 0 1-56-56h-40v128a28 28 0 1 1-40-25V89a68 68 0 1 0 80 67Z"/>`,
'devto-logo': `<path fill-rule="evenodd" d="M37 33c-2.2.5-4 2-4.7 4.2l-.3.8v181.8l.3.8c.7 2 2 3.3 4 4l.8.3H219l.7-.3c2-.7 3.3-2 4-4l.3-.8V38l-.3-.8c-.7-2-2-3.3-4-4l-.8-.3H37Zm43.6 58.3A20.7 20.7 0 0 1 98 109.6c.3 1.9.3 36.7 0 38.6a20.5 20.5 0 0 1-16 17.9c-2.6.5-1.8.5-14.9.6h-12V91h12.2c11 0 12.4 0 13.2.2Zm63.6 6.5v6.8H120v17.6h14.8v13.4H120v17.5h24.2v13.6h-30l-.8-.3a9.3 9.3 0 0 1-6.7-6.7l-.2-.9v-60l.2-.8c1-3.4 3.6-6 7-6.7.8-.2 1.8-.2 15.7-.2h14.8v6.7Zm27 8.6a268210 268210 0 0 1 9.5 36.4 5274.6 5274.6 0 0 0 13.5-51.6H209l-8.8 33a527.2 527.2 0 0 1-9.3 34.2 15 15 0 0 1-6.5 7.5c-1.3.6-2 .7-3.7.7-1.2 0-1.6 0-2.2-.2-3.2-.8-5.8-3.3-8-7.7l-.7-1.5-8.7-32.9-8.7-33c0-.2.3-.2 7.4-.2h7.4l4 15.3ZM68.7 128.8v24.3h9.5l.8-.3a9 9 0 0 0 4.7-3.4 7 7 0 0 0 1-2.4v-35.7l-.1-.8c-.6-2.3-1.9-3.8-4.3-5-1.8-.9-1.9-.9-7-1h-4.6v24.3Z" clip-rule="evenodd"/>`,
'mastodon-logo': `<path d="M219.3 74.8a49.7 49.7 0 0 0-43-40.4c-3.7-.6-17.6-2.5-49.8-2.5h-.3c-32.2 0-39.1 2-42.8 2.5-21.1 3-40.5 17.8-45.2 39a132.2 132.2 0 0 0-2 32.4c.6 15.1.7 30.3 2 45.3 1 10 2.7 20 5 29.8 4.5 18 22.6 33.1 40.3 39.2a108.8 108.8 0 0 0 65.1 1.4c4.7-1.5 10.3-3.2 14.4-6a.5.5 0 0 0 .2-.4v-14.7a.4.4 0 0 0-.4-.4h-.2a158 158 0 0 1-38.1 4.4c-22.1 0-28-10.3-29.8-14.7a45.1 45.1 0 0 1-2.4-12 .4.4 0 0 1 .4 0c12.3 3 24.9 4.4 37.5 4.4h9.1c12.7-.4 26.1-1 38.6-3.5.3 0 .6 0 .9-.2 19.7-3.7 38.5-15.5 40.4-45.3l.3-13.5c0-4 1.3-29.3-.2-44.8Zm-30.4 74.3h-20.7V99c0-10.6-4.5-16-13.6-16-10 0-15 6.4-15 19v27.5h-20.5V102c0-12.6-5-19-15-19-9 0-13.5 5.4-13.5 16v50H69.9V97.4A37 37 0 0 1 78 72c5.6-6.2 13-9.4 22.1-9.4 10.7 0 18.7 4 24 12.1l5.2 8.6 5.2-8.6c5.3-8 13.3-12 24-12 9 0 16.5 3.1 22.1 9.3a36.9 36.9 0 0 1 8.2 25.3V149Z"/>`,
};

View file

@ -0,0 +1,130 @@
---
import type { Page as Props } from 'astro';
import Icon from './Icon.astro';
const { currentPage, lastPage, url } = Astro.props;
const firstPage = 1;
interface Item {
page: number;
url: string;
current: boolean;
}
const makeItem = (page: number): Item => ({
page,
url: page === 1 ? '/' : `/${page}`,
current: page === currentPage,
});
const items: (Item | null)[] = [];
/** The number of pages to show before/after the current page. */
const beforeAfter = 1;
// Get range of pages around current page.
const min = Math.max(
Math.min(currentPage - beforeAfter, lastPage - 2 * beforeAfter - 1),
firstPage
);
const max = Math.min(
Math.max(min + 2 * beforeAfter, firstPage + 2 * beforeAfter + 1),
lastPage
);
// Always include first page.
if (min > firstPage) items.push(makeItem(firstPage));
// Show “…” if the range starts at page 4 or higher.
if (min > firstPage + 2) items.push(null);
// Show page 2 if the range starts at page 3.
if (min === firstPage + 2) items.push(makeItem(firstPage + 1));
// Show an item for pages in range around current page.
for (let i = min; i <= max; i++) items.push(makeItem(i));
// Show “…” if the range ends more than 2 pages before the last page.
if (max < lastPage - 2) items.push(null);
// Show the penultimate page if the range ends 2 pages before the last page.
if (max === lastPage - 2) items.push(makeItem(lastPage - 1));
// Always include last page.
if (max < lastPage) items.push(makeItem(lastPage));
---
{
lastPage > 1 && (
<nav>
<ul>
<li class="pagination-arrow">
{url.prev === undefined ? (
<span>
<Icon icon="arrow-left" />
<span class="sr-only">Previous</span>
</span>
) : (
<a href={url.prev} rel="prev">
<Icon icon="arrow-left" />
<span class="sr-only">Previous</span>
</a>
)}
</li>
{items.map((item) => (
<li class="pagination-item">
{item ? (
<a href={item.url} aria-current={item.current}>
{item.page}
</a>
) : (
<span>…</span>
)}
</li>
))}
<li class="pagination-arrow">
{url.next === undefined ? (
<span>
<span class="sr-only">Next</span>
<Icon icon="arrow-right" />
</span>
) : (
<a href={url.next} rel="next">
<span class="sr-only">Next</span>
<Icon icon="arrow-right" />
</a>
)}
</li>
</ul>
</nav>
)
}
<style>
ul {
display: flex;
justify-content: center;
list-style: none;
gap: 0.5rem;
padding: 0;
}
a {
text-decoration: none;
}
.pagination-item > * {
border: 1.5px solid var(--theme-accent-dark);
border-radius: var(--theme-radius-base);
padding: 0.375rem 0.75rem;
background-color: var(--theme-bg-accent);
font-size: var(--theme-text-sm);
font-weight: 700;
box-shadow: var(--theme-shadow-sm);
}
[aria-current='true'] {
background-color: var(--theme-accent-dark);
color: var(--theme-text-invert);
}
.pagination-arrow > * {
color: var(--theme-accent-dark);
opacity: 0.35;
font-size: 1.75rem;
display: flex;
}
.pagination-arrow > a {
opacity: 1;
}
</style>

View file

@ -0,0 +1,107 @@
---
import Icon from './Icon.astro';
---
<theme-toggle>
<button>
<span class="sr-only">Dark theme</span>
<span class="icon light"><Icon icon="sun" /></span>
<span class="icon dark"><Icon icon="moon-stars" /></span>
</button>
</theme-toggle>
<style>
button {
position: relative;
display: flex;
gap: 0.25rem;
border: 0;
border-radius: var(--theme-radius-full);
padding: 0.1875rem;
background-color: var(--theme-accent-light);
box-shadow: var(--theme-shadow-lg);
cursor: pointer;
}
button::before {
position: absolute;
inset: -0.125rem;
content: '';
border-radius: var(--theme-radius-full);
background: var(--theme-gradient-main);
z-index: -1;
}
.icon {
z-index: 1;
position: relative;
display: flex;
padding: 0.3125rem;
width: 1.625rem;
height: 1.625rem;
font-size: 1rem;
color: var(--theme-accent-dark);
}
.icon.light::before {
content: '';
z-index: -1;
position: absolute;
inset: 0;
background-color: var(--theme-accent-dark);
border-radius: 999rem;
}
:global(.theme-dark) .icon.light::before {
transform: translateX(calc(100% + 0.25rem));
}
:global(.theme-dark) .icon.dark,
:global(html:not(.theme-dark)) .icon.light,
button[aria-pressed='false'] .icon.light {
color: var(--theme-text-invert);
}
@media (prefers-reduced-motion: no-preference) {
.icon,
.icon.light::before {
transition: transform var(--theme-transition),
color var(--theme-transition);
}
}
@media (forced-colors: active) {
.icon.light::before {
background-color: SelectedItem;
}
}
</style>
<script>
class ThemeToggle extends HTMLElement {
constructor() {
super();
const button = this.querySelector('button')!;
/** Set the theme to dark/light mode. */
const setTheme = (dark: boolean) => {
document.documentElement.classList[dark ? 'add' : 'remove'](
'theme-dark'
);
button.setAttribute('aria-pressed', String(dark));
};
// Toggle the theme when a user clicks the button.
button.addEventListener('click', () => setTheme(!this.isDark()));
// Initialize button state to reflect current theme.
setTheme(this.isDark());
}
isDark() {
return document.documentElement.classList.contains('theme-dark');
}
}
customElements.define('theme-toggle', ThemeToggle);
</script>

View file

@ -0,0 +1,162 @@
---
import settings from '../settings';
import Icon from './Icon.astro';
type SocialEntry = [keyof (typeof settings)['social'], string];
const socialLinks = Object.entries(settings.social) as SocialEntry[];
---
<div class="profile">
<div>
<div class="avatar">
<img width="110" height="110" {...settings.avatar} />
</div>
<h1>
{settings.name}
<small>{settings.username}</small>
</h1>
</div>
<div class="bio-sections">
<div class="bio">
<p>🚀 <a href="https://astro.build/">Astro</a> Mascot</p>
<p>😊 The cutest</p>
<p>🎨 Whimsical Speedy Web</p>
</div>
<div class="bio">
{
settings.pronouns && (
<p>
<Icon icon="user" color="var(--theme-accent-dark)" size="1.75rem" />
<span class="sr-only">Pronouns</span>
{settings.pronouns}
</p>
)
}
{
settings.location && (
<p>
<Icon
icon="location-point"
color="var(--theme-accent-dark)"
size="1.75rem"
/>
<span class="sr-only">Location</span>
{settings.location}
</p>
)
}
{
settings.homepage && (
<p>
<Icon
icon="link-h"
color="var(--theme-accent-dark)"
size="1.75rem"
/>
<span class="sr-only">Homepage</span>
<a href={settings.homepage}>
{settings.homepage.replace(/^https?:\/\/(www\.)?/, '')}
</a>
</p>
)
}
<p>
<Icon icon="rss-alt" color="var(--theme-accent-dark)" size="1.75rem" />
<a href="/rss.xml">RSS Feed</a>
</p>
</div>
<ul class="social">
{
socialLinks.map(([key, url]) => (
<li>
<a href={url}>
<Icon icon={`${key}-logo`} size="1.75rem" />
</a>
</li>
))
}
</ul>
</div>
</div>
<style>
.profile {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.avatar {
display: inline-block;
position: relative;
}
.avatar::after {
border-radius: var(--theme-radius-full);
position: absolute;
content: '';
inset: 0;
border: 0.1875rem solid var(--theme-text);
}
.avatar img {
height: auto;
}
h1 {
display: flex;
flex-direction: column;
font-size: var(--theme-text-xl);
}
small {
font-size: var(--theme-text-base);
font-family: var(--theme-font-body);
color: var(--theme-gray-200);
}
.bio-sections {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: flex-start;
gap: 1rem 1.75rem;
}
.bio-sections > :nth-child(2) {
grid-row: span 2;
}
.bio {
font-size: var(--theme-text-sm);
font-weight: 500;
}
.bio > * + * {
margin-top: 0.75rem;
}
.bio :global(svg) {
/* Slightly hacky way to avoid the icon height being included in the box calculation. */
margin: -50% 0;
}
.social {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
list-style: none;
padding: 0;
}
.social a {
color: var(--theme-accent-dark);
}
@media (min-width: 50em) {
.bio-sections {
display: flex;
flex-direction: column;
}
}
</style>

View file

@ -0,0 +1,26 @@
// import { rssSchema } from '@astrojs/rss';
import { defineCollection, z } from 'astro:content';
const posts = defineCollection({
// TODO: Extend rssSchema here — was doing that in my standalone project but seems to be broken in the monorepo.
schema: z
.object({ title: z.string(), description: z.string().optional(), pubDate: z.date() })
.extend({
tags: z.array(z.string()).default([]),
cover: z
.object({
src: z.string(),
// TODO: Support experimental assets instead of plain string schema:
// image().refine(
// (img) => img.width >= 885,
// 'Cover image must be at least 885px wide.'
// )
alt: z.string(),
})
.optional(),
type: z.enum(['article', 'tweet']).default('tweet'),
})
.strict(),
});
export const collections = { posts };

View file

@ -0,0 +1,10 @@
---
title: First post on my new site!
pubDate: 2023-01-01
tags: [keyboards, thoughts]
cover:
src: stock-1.jpg
alt: A laptop with a code editor open
---
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

View file

@ -0,0 +1,4 @@
---
title: Ten for Ten
pubDate: 2023-01-10
---

View file

@ -0,0 +1,4 @@
---
title: Four is more
pubDate: 2023-01-04
---

View file

@ -0,0 +1,4 @@
---
title: Take Five!
pubDate: 2023-01-05
---

View file

@ -0,0 +1,4 @@
---
title: Then We Were Six
pubDate: 2023-01-06
---

View file

@ -0,0 +1,4 @@
---
title: 7th Heaven
pubDate: 2023-01-07
---

View file

@ -0,0 +1,4 @@
---
title: Eight is Great!
pubDate: 2023-01-08
---

View file

@ -0,0 +1,4 @@
---
title: Nine Lives
pubDate: 2023-01-09
---

View file

@ -0,0 +1,8 @@
---
title: Second time lucky
pubDate: 2023-01-02
---
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.

View file

@ -0,0 +1,9 @@
---
title: Three is a magic number
pubDate: 2023-01-03
cover:
src: stock-2.jpg
alt: A backlit multicolored mechanical keyboard
---
Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

View file

@ -0,0 +1,9 @@
import { getCollection } from 'astro:content';
/** Get everything in your posts collection, sorted by date. */
export async function getSortedPosts(order: 'asc' | 'desc' = 'desc') {
const posts = await getCollection('posts');
posts.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime());
if (order === 'asc') posts.reverse();
return posts;
}

View file

@ -0,0 +1,112 @@
---
import settings from '../settings';
import '../style/theme.css';
import '../style/global.css';
import '../style/utilities.css';
import Header from '../components/Header.astro';
import UserProfile from '../components/UserProfile.astro';
import Footer from '../components/Footer.astro';
interface Props {
title?: string;
}
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
const { title = settings.name } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
<!-- Canonical URL -->
<link rel="canonical" href={canonicalURL} />
<!-- RSS Feed Discovery -->
<link
rel="alternate"
type="application/rss+xml"
title="RSS"
href="/rss.xml"
/>
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;700&display=swap"
rel="stylesheet"
/>
<script is:inline>
// This code is inlined in the head to make dark mode instant & blocking.
const getThemePreference = () => {
if (
typeof localStorage !== 'undefined' &&
localStorage.getItem('theme')
) {
return localStorage.getItem('theme');
}
return window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
};
const isDark = getThemePreference() === 'dark';
document.documentElement.classList[isDark ? 'add' : 'remove'](
'theme-dark'
);
if (typeof localStorage !== 'undefined') {
// Watch the document element and persist user preference when it changes.
const observer = new MutationObserver(() => {
const isDark =
document.documentElement.classList.contains('theme-dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class'],
});
}
</script>
</head>
<body class="flex-col">
<div class="flex-col pad">
<Header />
<div class="flex-col wrapper">
<UserProfile />
<main>
<slot />
</main>
</div>
</div>
<Footer />
</body>
<style>
.flex-col {
display: flex;
flex-direction: column;
}
.pad {
gap: 2.5rem;
padding: 1.875rem 1.25rem;
}
.wrapper {
gap: 2.5rem;
margin: 0 auto;
width: 100%;
max-width: 55rem;
}
@media (min-width: 50em) {
.wrapper {
display: grid;
grid-template-columns: 12rem 1fr;
}
}
</style>
</html>

View file

@ -0,0 +1,114 @@
---
import type { GetStaticPathsOptions, Page } from 'astro';
import type { CollectionEntry } from 'astro:content';
import Pagination from '../components/Pagination.astro';
import { getSortedPosts } from '../helpers/getSortedPosts';
import Base from '../layouts/Base.astro';
import settings from '../settings';
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
return paginate(await getSortedPosts(), { pageSize: 3 });
}
interface Props {
page: Page<CollectionEntry<'posts'>>;
}
const { page } = Astro.props;
---
<Base>
<div class="stack">
<!-- <h1>Page {page.currentPage}</h1> -->
<ol>
{
page.data.map((post) => (
<li>
<article class="card">
<header>
<div style="display: flex;gap:0.875rem;align-items:center;">
<img
style="border-radius: var(--theme-radius-full);background-color:var(--theme-shade-subtle);"
width="60"
height="60"
{...settings.avatar}
/>
<div>
<p style="font-family:var(--theme-font-brand);font-weight:700;font-size:var(--theme-text-lg)">
{settings.name}
</p>
<p style="color:var(--theme-gray-200);font-size:var(--theme-text-sm);">
{settings.username} •{' '}
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString('en', {
month: 'short',
day: '2-digit',
year: 'numeric',
})}
</time>
</p>
</div>
</div>
{post.data.tags.length > 0 && (
<ul class="tags">
{post.data.tags.map((tag) => (
<li class="tag">{tag}</li>
))}
</ul>
)}
<h2>
<a href={'/post/' + post.slug}>{post.data.title}</a>
</h2>
</header>
{post.render().then(({ Content }) => (
<Content />
))}
</article>
</li>
))
}
</ol>
<Pagination {...page} />
</div>
</Base>
<style>
.stack {
display: flex;
flex-direction: column;
gap: 2.5rem;
}
ol {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.card {
padding: 1.25rem 1.25rem 1.5rem;
background-color: var(--theme-bg-accent);
border-radius: var(--theme-radius-xl);
box-shadow: var(--theme-shadow-md);
}
header > * + * {
margin-top: 0.625rem;
}
.tags {
list-style: none;
padding: 0;
display: flex;
gap: 0.3125rem;
}
.tag {
padding: 0.25rem 0.5625rem;
border-radius: var(--theme-radius-full);
background-color: var(--theme-accent-dark);
color: var(--theme-text-invert);
font-size: var(--theme-text-sm);
font-weight: 500;
}
.tag::before {
content: '#';
}
</style>

View file

@ -0,0 +1,29 @@
---
import type { CollectionEntry } from 'astro:content';
import { getSortedPosts } from '../../helpers/getSortedPosts';
import Base from '../../layouts/Base.astro';
export async function getStaticPaths() {
const posts = await getSortedPosts();
return posts.map((post, idx) => ({
params: { slug: post.slug },
props: { post, prev: posts[idx - 1], next: posts[idx + 1] },
}));
}
interface Props {
post: CollectionEntry<'posts'>;
prev?: CollectionEntry<'posts'>;
next?: CollectionEntry<'posts'>;
}
const { post, prev, next } = Astro.props;
const { Content } = await post.render();
---
<Base title={post.data.title}>
<h1>{post.data.title}</h1>
<Content />
{prev && <a href={'/post/' + prev.slug}>Previous: {prev.data.title}</a>}
{next && <a href={'/post/' + next.slug}>Next: {next.data.title}</a>}
</Base>

View file

@ -0,0 +1,23 @@
import rss from '@astrojs/rss';
import type { APIContext } from 'astro';
import { getSortedPosts } from '../helpers/getSortedPosts';
import settings from '../settings';
const { title, description } = settings.rss;
export async function get(context: APIContext) {
const posts = await getSortedPosts();
return rss({
// `<title>` field in output xml
title,
// `<description>` field in output xml
description,
// Pull in your project "site" from the endpoint context
// https://docs.astro.build/en/reference/api-reference/#contextsite
site: context.site!.href,
// Array of `<item>`s in output xml
// See "Generating items" section for examples using content collections and glob imports
items: posts.map(({ data, slug }) => ({ ...data, link: `/post/${slug}` })),
stylesheet: '/rss/styles.xsl',
});
}

View file

@ -0,0 +1,24 @@
export default {
name: 'Houston Astro',
username: '@houston',
avatar: {
src: '/avatar.webp',
alt: 'Astro mascot Houston smiling',
},
rss: {
title: 'Houston Astros Feed',
description: 'Stay up-to-date with the latest posts from Houston Astro!',
},
pronouns: 'They/Them',
location: 'Space',
homepage: 'https://astro.build',
social: {
twitter: 'https://twitter.com/astrodotbuild',
twitch: 'https://www.twitch.tv/bholmesdev',
github: 'https://github.com/withastro',
devto: 'https://dev.to/search?q=astro',
codepen: 'https://codepen.io/delucis',
mastodon: 'https://m.webtoo.ls/@astro',
youtube: 'https://www.youtube.com/@astrodotbuild',
},
} as const;

View file

@ -0,0 +1,40 @@
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
}
html,
body {
height: 100%;
}
body {
background-color: var(--theme-bg);
color: var(--theme-text);
font-family: var(--theme-font-body);
-webkit-font-smoothing: antialiased;
line-height: 1.5;
}
img,
picture,
video,
canvas {
display: block;
max-width: 100%;
}
a {
color: var(--theme-text);
}
h1,
h2,
h3,
h4,
h5 {
line-height: 1.2;
font-family: var(--theme-font-brand);
}

View file

@ -0,0 +1,82 @@
:root {
/* Colors */
--theme-bg: #eceaf5;
--theme-bg-accent: #f6f5fb;
--theme-text: #171b26;
--theme-text-invert: #fdfdfd;
--theme-gray-200: #505d84;
--theme-gray-400: #505d84;
--theme-gray-700: #505d84;
--theme-accent-light: #ddd6fc;
--theme-accent-medium: #8577eb;
--theme-accent-dark: #5a48d9;
--theme-shade-subtle: var(--theme-accent-light);
/* Gradients */
--theme-gradient-main: linear-gradient(83.21deg, var(--theme-accent-dark) 6.77%, #c561f6 93.75%);
--theme-gradient-text: linear-gradient(
83.21deg,
var(--theme-accent-dark) 10.42%,
#7a4fe2 76.04%,
#c561f6 100%
);
/* Shadows */
--theme-shadow-sm: 1px 1px 5px rgba(0, 0, 0, 0.1);
--theme-shadow-md: 2px 2px 10px rgba(0, 0, 0, 0.1);
--theme-shadow-lg: 2px 2px 20px rgba(0, 0, 0, 0.2);
/* Type Scale */
--__type-scale-ratio: 1.2;
--theme-text-base: 1rem;
--theme-text-sm: calc(var(--theme-text-base) / var(--__type-scale-ratio)); /*13.3px*/
--theme-text-lg: calc(var(--theme-text-base) * var(--__type-scale-ratio)); /*19.2px*/
--theme-text-xl: calc(var(--theme-text-lg) * var(--__type-scale-ratio)); /*23px*/
--theme-text-2xl: calc(var(--theme-text-xl) * var(--__type-scale-ratio)); /*13.3px*/
--theme-text-3xl: calc(var(--theme-text-2xl) * var(--__type-scale-ratio)); /*27.6px*/
--theme-text-4xl: calc(var(--theme-text-3xl) * var(--__type-scale-ratio)); /*33.2px*/
/* Fonts */
--__font-system: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--theme-font-body: var(--__font-system);
--theme-font-brand: 'Montserrat', var(--__font-system);
/* Corners */
--theme-radius-base: 0.3125rem;
--theme-radius-lg: 0.625rem;
--theme-radius-xl: 1.25rem;
--theme-radius-full: 999rem;
/* Transitions */
--theme-transition: 0.2s ease-in-out;
}
:root.theme-dark {
/* Colors (dark) */
--theme-bg: #141925;
--theme-bg-accent: #202c49;
--theme-text: #fdfdfd;
--theme-text-invert: #171b26;
--theme-gray-200: #c3cadb;
--theme-gray-400: #8490b5;
--theme-gray-700: #3d4663;
--theme-accent-light: #ebd2f8;
--theme-accent-medium: #c779ed;
--theme-accent-dark: #c561f6;
--theme-shade-subtle: var(--theme-bg-accent);
/* Gradients (dark) */
--theme-gradient-main: linear-gradient(83.21deg, var(--theme-accent-dark) 6.25%, #5a48d9 100%);
--theme-gradient-text: linear-gradient(
83.21deg,
var(--theme-accent-dark) 6.25%,
#b45df1 75.52%,
#5a48d9 100%
);
/* Shadows (dark) */
--theme-shadow-sm: 1px 1px 5px rgba(0, 0, 0, 0.1);
--theme-shadow-md: 4px 4px 10px rgba(9, 11, 17, 0.2);
--theme-shadow-lg: 4px 4px 30px rgba(0, 0, 0, 0.6);
}

View file

@ -0,0 +1,11 @@
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}

View file

@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strictest"
}

View file

@ -345,6 +345,15 @@ importers:
specifier: ^3.1.4
version: link:../../packages/astro
examples/social-feed:
dependencies:
'@astrojs/rss':
specifier: ^2.4.3
version: link:../../packages/astro-rss
astro:
specifier: ^2.6.4
version: link:../../packages/astro
examples/ssr:
dependencies:
'@astrojs/node':