WIP: adding the styled layout for blog articles

This commit is contained in:
Tony Sullivan 2023-09-12 16:22:36 -05:00
parent 58b48a9bfe
commit de8fee50fd
17 changed files with 500 additions and 263 deletions

View file

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

View file

@ -12,6 +12,7 @@
},
"dependencies": {
"@astrojs/rss": "^3.0.0",
"astro": "^3.0.1"
"astro": "^3.0.1",
"reading-time": "^1.5.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View file

@ -0,0 +1,17 @@
---
interface Props {
date: Date;
}
const { date } = Astro.props;
---
<time datetime={date.toISOString()}>
{
date.toLocaleDateString('en-us', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
</time>

View file

@ -9,25 +9,26 @@
* (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"/>`,
'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"/>`,
clock: `<path d="M158 118H138V78C138 75.3478 136.946 72.8043 135.071 70.929C133.196 69.0536 130.652 68 128 68C125.348 68 122.804 69.0536 120.929 70.929C119.054 72.8043 118 75.3478 118 78V128C118 130.652 119.054 133.196 120.929 135.071C122.804 136.946 125.348 138 128 138H158C160.653 138 163.195 136.946 165.07 135.071C166.947 133.196 168 130.652 168 128C168 125.348 166.947 122.804 165.07 120.929C163.195 119.054 160.653 118 158 118ZM128 28C108.222 28 88.8878 33.865 72.443 44.853C55.9981 55.8411 43.1808 71.459 35.612 89.7317C28.0434 108.004 26.063 128.111 29.9214 147.509C33.78 166.907 43.3042 184.725 57.2893 198.71C71.2746 212.696 89.093 222.221 108.491 226.078C127.889 229.938 147.996 227.957 166.269 220.387C184.541 212.819 200.158 200.002 211.147 183.557C222.134 167.112 228 147.778 228 128C228 114.868 225.413 101.864 220.387 89.7317C215.363 77.599 207.997 66.5752 198.71 57.2893C189.426 48.0035 178.402 40.6374 166.269 35.612C154.136 30.5866 141.132 28 128 28ZM128 208C112.177 208 96.7104 203.309 83.5544 194.517C70.3984 185.726 60.1446 173.232 54.0896 158.615C48.0347 143.997 46.4504 127.911 49.5371 112.393C52.624 96.8742 60.2432 82.6197 71.4315 71.4315C82.6197 60.2432 96.8742 52.624 112.393 49.5371C127.911 46.4504 143.997 48.0346 158.615 54.0896C173.232 60.1446 185.726 70.3984 194.517 83.5544C203.309 96.7102 208 112.177 208 128C208 149.217 199.571 169.566 184.568 184.568C169.566 199.571 149.217 208 128 208Z" fill="currentColor"/>`,
};

View file

@ -6,15 +6,15 @@ const { currentPage, lastPage, url } = Astro.props;
const firstPage = 1;
interface Item {
page: number;
url: string;
current: boolean;
page: number;
url: string;
current: boolean;
}
const makeItem = (page: number): Item => ({
page,
url: page === 1 ? '/' : `/${page}`,
current: page === currentPage,
page,
url: page === 1 ? '/' : `/${page}`,
current: page === currentPage,
});
const items: (Item | null)[] = [];
@ -23,13 +23,10 @@ const items: (Item | null)[] = [];
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
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.
@ -47,84 +44,84 @@ 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>
)
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);
}
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-accent-light);
font-size: var(--theme-text-sm);
font-weight: 700;
box-shadow: var(--theme-shadow-sm);
}
.pagination-item > [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 > * {
color: var(--theme-accent-dark);
opacity: 0.35;
font-size: 1.75rem;
display: flex;
}
.pagination-arrow > a {
opacity: 1;
}
.pagination-arrow > a {
opacity: 1;
}
</style>

View file

@ -0,0 +1,31 @@
---
interface Props {
tags: string[];
}
const { tags } = Astro.props;
---
<ul class="tags">
{tags.map((tag) => <li class="tag">{tag}</li>)}
</ul>
<style>
.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

@ -1,26 +1,22 @@
// import { rssSchema } from '@astrojs/rss';
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() })
schema: ({ image }) => rssSchema
.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(),
tags: z.array(z.string()).default([]),
cover: z
.object({
src: image().refine(
(img) => img.width >= 885,
'Cover image must be at least 885px wide.'
),
alt: z.string(),
})
.optional(),
type: z.enum(['article', 'note']).default('note'),
})
.strict(),
});
export const collections = { posts };

View file

@ -3,8 +3,26 @@ title: First post on my new site!
pubDate: 2023-01-01
tags: [keyboards, thoughts]
cover:
src: stock-1.jpg
src: ../../assets/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.
Dignissim eu sagittis aliquet magna sagittis. Eu etiam faucibus quis non. Laoreet amet aliquam enim sapien. Cras ac enim nulla morbi ultrices elementum metus neque nulla. Quis mi consectetur donec tempor habitant.
Id at orci nulla nunc. Habitant a amet turpis facilisi purus cursus dui imperdiet. Integer fermentum amet nunc tristique scelerisque feugiat pellentesque phasellus. Feugiat euismod id varius id mattis ac ut. Donec aliquet fusce ut egestas vehicula sagittis.
Mauris vulputate tristique porttitor sed integer felis. In eget sodales lobortis laoreet molestie aliquet est aliquet tortor. Sodales erat rhoncus tellus mattis etiam nunc ornare. Nisi ut tellus elementum gravida dictum diam porta. Nulla porttitor magna duis pretium egestas nisl ornare.
## Heading One
Suscipit id porttitor laoreet purus semper fermentum libero cras magna. Non hendrerit lectus tincidunt condimentum. Sollicitudin pretium at vel nibh tempus proin faucibus donec sed. Habitant et risus auctor platea viverra tellus. Faucibus dapibus neque enim metus porttitor pulvinar pharetra amet sem. Nibh a facilisis pellentesque ut pellentesque. Amet semper ultrices est lacus facilisis pulvinar viverra. Quis velit cursus viverra varius vestibulum. Ultricies interdum id dapibus nunc bibendum vitae varius in. Lorem vel congue in amet et pellentesque sed facilisis. Id amet sed suspendisse tincidunt lacinia sit. Ut libero id ornare cursus porttitor elementum.
## Heading Number Two
Sagittis fames arcu tempor morbi sed mauris eu blandit cras. Risus amet nec auctor nunc pretium commodo. Dictum duis nascetur est molestie ullamcorper sit tempor. Vestibulum dictumst magna cursus aenean vitae ornare amet non.
Dui tortor viverra eu montes. Elit pretium pharetra aliquam pellentesque congue id morbi maecenas. Donec a egestas ipsum sit a ipsum. Quis vestibulum feugiat tincidunt justo tellus turpis. Luctus dignissim porta dictumst ut auctor neque in.
![Close-up of a mechanical keyboard with LED backlighting](../../assets/mechanical-keyboard.png)
Pellentesque faucibus faucibus magna tempus proin amet in viverra. Eros non ipsum justo pellentesque vestibulum morbi proin euismod. Sagittis in amet at aliquet facilisis.

View file

@ -2,7 +2,7 @@
title: Three is a magic number
pubDate: 2023-01-03
cover:
src: stock-2.jpg
src: ../../assets/stock-2.jpg
alt: A backlit multicolored mechanical keyboard
---

View file

@ -0,0 +1,173 @@
---
import { Image } from 'astro:assets';
import type { CollectionEntry } from 'astro:content';
import getReadingTime from 'reading-time';
import Layout, { type Props as LayoutProps } from './Base.astro';
import FormattedDate from '../components/FormattedDate.astro';
import TagList from '../components/TagList.astro';
import Icon from '../components/Icon.astro';
export interface Props extends LayoutProps {
article: CollectionEntry<'posts'>;
next?: CollectionEntry<'posts'>;
prev?: CollectionEntry<'posts'>;
}
const { article, next, prev } = Astro.props;
const { Content, headings } = await article.render();
const readingTime = getReadingTime(article.body).text;
---
<Layout ...Astro.props} wrapperReverse>
<header>
<a href="/" class="back">
<Icon icon="arrow-left" color="var(--theme-accent-dark)" size="1.25rem" />
<span>Back to feed</span>
</a>
{article.data.cover && <Image src={article.data.cover.src} alt={article.data.cover.alt} class="cover" />}
<div class="meta">
<FormattedDate date={article.data.pubDate} />
<span>•</span>
<p>
<Icon icon="clock" size="1rem" />
<span>{readingTime}</span>
</p>
</div>
<h1>{article.data.title}</h1>
{article.data.tags?.length > 0 && (
<TagList tags={article.data.tags} />
)}
</header>
<div class="content">
<Content />
</div>
{headings.length > 0 && (
<aside>
<h3>Table of contents</h3>
<ul>
{headings.map(({ slug, text }) => (
<li>
<a href={`${Astro.url.pathname}#${slug}`}>{text}</a>
</li>
))}
</ul>
</aside>
)}
{(next || prev) && (
<footer>
{prev && <a href={`/post/${prev.slug}`} class="prev">
<Icon icon="arrow-left" size="1.25rem" color="var(--theme-accent-dark)" />
<span>Previous: {prev.data.title}</span>
</a>}
{next && <a href={`/post/${next.slug}`} class="next">
<span>Next: {next.data.title}</span>
<Icon icon="arrow-right" size="1.25rem" color="var(--theme-accent-dark)" />
</a>}
</footer>
)}
</Layout>
<style>
header, footer {
grid-column: 1 / -1;
}
header {
display: flex;
flex-direction: column;
gap: 1rem;
}
.content > :global(* + *) {
margin-block-start: 1em;
}
.content > :global(p:first-child::first-letter) {
float: left;
font-size: 3.5rem;
padding-inline-end: .5rem;
padding-block-start: .35rem;
font-weight: bold;
}
.content :global(img, video, figure) {
margin-inline: auto;
}
.meta {
display: flex;
align-items: center;
gap: 1rem;
font-size: var(--theme-text-sm);
color: var(--theme-gray-200);
}
.meta svg {
margin-block-end: 0.25rem;
}
.back {
text-decoration: none;
font-weight: bold;
}
.back {
display: flex;
align-items: center;
gap: 0.5rem;
margin-inline-start: -4px;
}
.cover {
height: auto;
aspect-ratio: 2.777;
object-fit: cover;
border-radius: 1.25rem;
margin-block-start: 0.5rem;
}
footer {
display: flex;
justify-content: space-between;
}
footer a {
font-weight: 700;
text-decoration: none;
}
.next:first-child {
margin-inline-start: auto;
}
aside {
display: none;
}
aside ul {
list-style: none;
padding: 0;
margin-top: 1.25em;
}
aside ul > * + * {
margin-block-start: 0.75em;
}
aside a {
font-weight: bold;
text-decoration: none;
}
@media (min-width: 50em) {
aside {
display: block;
}
.content > :global(* + *) {
margin-block-start: 1.5em;
}
}
</style>

View file

@ -7,13 +7,14 @@ import Header from '../components/Header.astro';
import UserProfile from '../components/UserProfile.astro';
import Footer from '../components/Footer.astro';
interface Props {
export interface Props {
title?: string;
wrapperReverse?: boolean;
}
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
const { title = settings.name } = Astro.props;
const { title = settings.name, wrapperReverse = false } = Astro.props;
---
<html lang="en">
@ -74,13 +75,10 @@ const { title = settings.name } = Astro.props;
<body class="flex-col">
<div class="flex-col pad">
<Header />
<div class="flex-col wrapper">
<UserProfile />
<main>
<slot />
</main>
</div>
</div>
<div class="flex-col wrapper" class:list={["flex-col wrapper", { reverse: wrapperReverse }]}>
<slot />
</div>
</div>
<Footer />
</body>
@ -95,18 +93,28 @@ const { title = settings.name } = Astro.props;
padding: 1.875rem 1.25rem;
}
.wrapper {
gap: 2.5rem;
margin: 0 auto;
width: 100%;
max-width: 55rem;
}
.flex-col {
display: flex;
flex-direction: column;
}
.wrapper {
gap: 2.5rem;
margin: 0 auto;
width: 100%;
max-width: 55rem;
}
@media (min-width: 50em) {
.wrapper {
display: grid;
grid-template-columns: 12rem 1fr;
}
.wrapper.reverse {
grid-template-columns: 1fr 12rem;
}
}
@media (min-width: 50em) {
.wrapper {
display: grid;
grid-template-columns: 12rem 1fr;
}
}
</style>
</html>

View file

@ -0,0 +1,13 @@
---
import Layout, { type Props as LayoutProps } from './Base.astro';
import UserProfile from '../components/UserProfile.astro';
export interface Props extends LayoutProps {}
---
<Layout {...Astro.props}>
<UserProfile />
<main>
<slot />
</main>
</Layout>

View file

@ -2,113 +2,91 @@
import type { GetStaticPathsOptions, Page } from 'astro';
import type { CollectionEntry } from 'astro:content';
import Pagination from '../components/Pagination.astro';
import TagList from '../components/TagList.astro';
import { getSortedPosts } from '../helpers/getSortedPosts';
import Base from '../layouts/Base.astro';
import Layout from '../layouts/Feed.astro';
import settings from '../settings';
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
return paginate(await getSortedPosts(), { pageSize: 3 });
return paginate(await getSortedPosts(), { pageSize: 3 });
}
interface Props {
page: Page<CollectionEntry<'posts'>>;
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>
<Layout>
<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 && <TagList tags={post.data.tags} />}
<h2>
<a href={'/post/' + post.slug}>{post.data.title}</a>
</h2>
</header>
{post.render().then(({ Content }) => (
<Content />
))}
</article>
</li>
))
}
</ol>
<Pagination {...page} />
</div>
</Layout>
<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: '#';
}
.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;
}
</style>

View file

@ -1,29 +1,26 @@
---
import type { CollectionEntry } from 'astro:content';
import { getSortedPosts } from '../../helpers/getSortedPosts';
import Base from '../../layouts/Base.astro';
import Layout from '../../layouts/Article.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] },
}));
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'>;
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>
<Layout title={post.data.title} article={post} {next} {prev}>
<Content />
</Layout>

View file

@ -26,6 +26,10 @@ canvas {
max-width: 100%;
}
img {
height: auto;
}
a {
color: var(--theme-text);
}

View file

@ -353,6 +353,9 @@ importers:
astro:
specifier: ^3.0.1
version: link:../../packages/astro
reading-time:
specifier: ^1.5.0
version: 1.5.0
examples/ssr:
dependencies: