├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json └── launch.json ├── README.md ├── algolia.mjs ├── astro.config.mjs ├── complete-algolia.mjs ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── images │ ├── group-photo.png │ └── photos │ ├── bill.png │ ├── christopher.png │ ├── john.png │ ├── tim.png │ └── wolverine.png ├── src ├── components │ ├── Article.astro │ ├── Card.astro │ ├── Counter.svelte │ ├── Figure.svelte │ ├── Nav.astro │ ├── PortableText.svelte │ └── Search.svelte ├── css │ ├── reset.css │ └── styles.css ├── layouts │ ├── Base │ │ ├── Base.astro │ │ └── Head.astro │ ├── BasicPage.astro │ ├── BlogPost.astro │ └── GalleryPage.astro ├── pages │ ├── 404.astro │ ├── about.astro │ ├── basic.md │ ├── blog.astro │ ├── blog │ │ ├── fourth-post.md │ │ ├── quick-seo-tips.md │ │ ├── second-post.md │ │ └── third-post.md │ ├── contact.astro │ ├── gallery.astro │ ├── index.astro │ ├── js-test.astro │ ├── rss.xml.js │ ├── sanity │ │ ├── [slug].astro │ │ └── index.astro │ └── search.astro ├── scss │ └── styles.scss └── utilities │ ├── blog.js │ └── sanity.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | .output/ 4 | 5 | # dependencies 6 | node_modules/ 7 | 8 | # logs 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | pnpm-debug.log* 13 | 14 | 15 | # environment variables 16 | .env 17 | .env.production 18 | 19 | # macOS-specific files 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Expose Astro dependencies for `pnpm` users 2 | shamefully-hoist=true 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to [Astro](https://astro.build) 2 | 3 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/starter) 4 | 5 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 6 | 7 | ## 🚀 Project Structure 8 | 9 | Inside of your Astro project, you'll see the following folders and files: 10 | 11 | ``` 12 | / 13 | ├── public/ 14 | │ └── favicon.ico 15 | ├── src/ 16 | │ ├── components/ 17 | │ │ └── Layout.astro 18 | │ └── pages/ 19 | │ └── index.astro 20 | └── package.json 21 | ``` 22 | 23 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. 24 | 25 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components or layouts. 26 | 27 | Any static assets, like images, can be placed in the `public/` directory. 28 | 29 | ## 🧞 Commands 30 | 31 | All commands are run from the root of the project, from a terminal: 32 | 33 | | Command | Action | 34 | | :---------------- | :------------------------------------------- | 35 | | `npm install` | Installs dependencies | 36 | | `npm run dev` | Starts local dev server at `localhost:3000` | 37 | | `npm run build` | Build your production site to `./dist/` | 38 | | `npm run preview` | Preview your build locally, before deploying | 39 | 40 | ## 👀 Want to learn more? 41 | 42 | Feel free to check [our documentation](https://github.com/withastro/astro) or jump into our [Discord server](https://astro.build/chat). 43 | -------------------------------------------------------------------------------- /algolia.mjs: -------------------------------------------------------------------------------- 1 | import algolia from 'algoliasearch' 2 | 3 | const posts = [ 4 | { 5 | title: 'First Post', 6 | description: 'My first post', 7 | link: '/blog/first-post', 8 | objectID: '1' 9 | }, 10 | { 11 | title: 'Second Post', 12 | description: 'My second post', 13 | link: '/blog/second-post', 14 | objectID: '2' 15 | }, 16 | { 17 | title: 'Third Post', 18 | description: 'My third post', 19 | link: '/blog/third-post', 20 | objectID: '3' 21 | } 22 | ] 23 | 24 | // Initialize Algolia 25 | const client = algolia('WGGTXJI80W', '09757e54248fd87642f464ebf36462f2') 26 | const index = client.initIndex('content') 27 | 28 | index 29 | .saveObjects(posts) 30 | .then(console.log) 31 | .catch(console.log) 32 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config' 2 | 3 | import svelte from '@astrojs/svelte' 4 | 5 | // https://astro.build/config 6 | export default defineConfig({ 7 | site: 'https://astro-demo', 8 | integrations: [svelte()] 9 | }) 10 | -------------------------------------------------------------------------------- /complete-algolia.mjs: -------------------------------------------------------------------------------- 1 | import 'dotenv/config' 2 | import g from 'glob' 3 | import { readFile } from 'fs/promises' 4 | import { promisify } from 'util' 5 | import algoliasearch from 'algoliasearch' 6 | import path from 'path' 7 | import { JSDOM } from 'jsdom' 8 | import crypto from 'crypto' 9 | 10 | const glob = promisify(g) 11 | const ALGOLIA_ID = process.env.ALGOLIA_ID 12 | const ALGOLIA_API_KEY = process.env.ALGOLIA_API_KEY 13 | 14 | const client = algoliasearch(ALGOLIA_ID, ALGOLIA_API_KEY) 15 | 16 | // Indexing for document search 17 | // https://www.algolia.com/blog/engineering/how-to-build-a-helpful-search-for-technical-documentation-the-laravel-example/ 18 | const index = client.initIndex('content') 19 | index.setSettings({ 20 | attributeForDistinct: 'h1', 21 | distinct: true 22 | }) 23 | 24 | // Getting records from HTML Pages 25 | const pages = await glob('./dist/**/index.html') 26 | const records = await createRecordsFromHTML(pages) 27 | 28 | // Remove redundant records 29 | await removeRedundantRecords(records) 30 | 31 | // Save records to Algolia 32 | index 33 | .saveObjects(records) 34 | .then(console.log) 35 | .catch(console.log) 36 | 37 | // ======================== 38 | // Supporting Functions 39 | // ======================== 40 | /** 41 | * Scrapes HTML pages and creates records 42 | * @param {array} pages HTML pages to parse 43 | * @returns 44 | */ 45 | async function createRecordsFromHTML (pages) { 46 | // Improvement: Confirm which textElements are important for the records... And whether `element.textContent` gets all children content as well. 47 | const textElements = [ 48 | 'h1', 49 | 'h2', 50 | 'h3', 51 | 'ul', 52 | 'ol', 53 | // 'div', 54 | 'span', 55 | 'p', 56 | // 'b', 57 | // 'em', 58 | // 'strikethrough' 59 | // 'a', 60 | 'figure' 61 | ].map(value => 'main ' + value) 62 | 63 | pages = pages.map(async (page, index) => { 64 | const pagePath = pages[index] 65 | const permalink = path.join( 66 | pagePath.replace('index.html', '').replace('dist/', '') 67 | ) 68 | 69 | const buffer = await readFile(page) 70 | const html = buffer.toString() 71 | 72 | const { window } = new JSDOM(html) 73 | const document = window.document 74 | 75 | const elements = document.querySelectorAll(textElements) 76 | const stack = [] 77 | let h1, h2, h3, link 78 | 79 | for (const element of elements) { 80 | let content 81 | let record = {} 82 | const tag = element.tagName 83 | if (tag === 'H1') { 84 | h1 = element.textContent 85 | link = permalink 86 | } else if (tag === 'H2') { 87 | h2 = element.textContent 88 | h3 = '' 89 | link = permalink + '#' + element.id 90 | } else if (tag === 'H3') { 91 | h3 = element.textContent 92 | link = permalink + '#' + element.id 93 | } else { 94 | content = element.textContent 95 | } 96 | 97 | // Build the record 98 | if (h1) record.h1 = h1 99 | if (h2) record.h2 = h2 100 | if (h3) record.h3 = h3 101 | if (link) record.link = link 102 | if (content) record.content = content.trim() 103 | record.objectID = quickHash(JSON.stringify(record)) 104 | 105 | stack.push(record) 106 | } 107 | 108 | return stack 109 | }) 110 | 111 | let records = await Promise.all(pages) 112 | records = records.flat() 113 | 114 | return records 115 | } 116 | 117 | // Fastest hash among a few tested ones. 118 | // https://medium.com/@chris_72272/what-is-the-fastest-node-js-hashing-algorithm-c15c1a0e164e 119 | function quickHash (data) { 120 | return crypto 121 | .createHash('sha1') 122 | .update(data) 123 | .digest('base64') 124 | } 125 | 126 | /** 127 | * Gets ID of current records from Algolia 128 | * @returns {array} Array of record IDs 129 | */ 130 | async function getOldRecordIDs () { 131 | let oldRecords = [] 132 | await index.browseObjects({ 133 | query: '', 134 | attributesToRetrieve: 'objectID', 135 | batch: batch => { 136 | oldRecords = oldRecords.concat(batch) 137 | } 138 | }) 139 | 140 | return oldRecords.map(record => record.objectID) 141 | } 142 | 143 | /** 144 | * Removes redundant records from Algolia 145 | * @param {array} newRecords Algolia records 146 | */ 147 | async function removeRedundantRecords (newRecords) { 148 | const newRecordIDs = newRecords.map(record => record.objectID) 149 | const oldRecordIDs = await getOldRecordIDs() 150 | 151 | // Improvement: Pop the ID off both records when checked and true. 152 | // This reduces the amount of records in both arrays to filter through 153 | const redundantRecordIDs = oldRecordIDs.filter( 154 | id => !newRecordIDs.includes(id) 155 | ) 156 | 157 | await index.deleteObjects(redundantRecordIDs) 158 | } 159 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@example/basics", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "preview": "astro preview" 10 | }, 11 | "devDependencies": { 12 | "@astrojs/rss": "^0.2.1", 13 | "@astrojs/svelte": "^0.1.3", 14 | "@portabletext/svelte": "^1.0.1", 15 | "@portabletext/to-html": "^1.0.3", 16 | "@sanity/client": "^3.3.2", 17 | "@sanity/image-url": "^1.0.1", 18 | "algoliasearch": "^4.13.1", 19 | "astro": "^1.0.0-beta.35", 20 | "date-fns": "^2.28.0", 21 | "dotenv": "^16.0.1", 22 | "glob": "^8.0.3", 23 | "jsdom": "^20.0.0", 24 | "postcss-nested": "^5.0.6", 25 | "postcss-preset-env": "^7.7.0", 26 | "postcss-short": "^5.0.0", 27 | "sass": "^1.52.1", 28 | "svelte": "^3.48.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-preset-env'), 4 | // require('postcss-functions')({ 5 | // functions: { 6 | // ...require('./postcss/font.js') 7 | // } 8 | // }), 9 | // require('postcss-mixins'), @mixin 10 | require('postcss-nested'), 11 | // require('postcss-atroot'), @at-root 12 | // require('postcss-conditionals'), //@if 13 | // require('postcss-for'), @for 14 | // require('postcss-each'), @each 15 | require('postcss-short') 16 | // require('postcss-apply'), 17 | // require('postcss-font-magician') 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/favicon.ico -------------------------------------------------------------------------------- /public/images/group-photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/group-photo.png -------------------------------------------------------------------------------- /public/images/photos/bill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/photos/bill.png -------------------------------------------------------------------------------- /public/images/photos/christopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/photos/christopher.png -------------------------------------------------------------------------------- /public/images/photos/john.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/photos/john.png -------------------------------------------------------------------------------- /public/images/photos/tim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/photos/tim.png -------------------------------------------------------------------------------- /public/images/photos/wolverine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zellwk/build-and-deploy-workshop/783ab7049d53f0622d082e46403665b05f396adc/public/images/photos/wolverine.png -------------------------------------------------------------------------------- /src/components/Article.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {readableDate} from '../utilities/blog.js' 3 | const {post} = Astro.props 4 | --- 5 |
6 |

7 | {readableDate(new Date(post.frontmatter.date))} 8 | {post.frontmatter.title} 9 |

10 |
11 | -------------------------------------------------------------------------------- /src/components/Card.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {title} = Astro.props 3 | --- 4 | 5 | 14 | 15 |
16 |

{title}

17 | 18 |
19 | -------------------------------------------------------------------------------- /src/components/Counter.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |

Counter Element

10 |

Count: {count}

11 | 12 | -------------------------------------------------------------------------------- /src/components/Figure.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 11 |
{caption}
12 |
13 | -------------------------------------------------------------------------------- /src/components/Nav.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const pagePath = Astro.canonicalURL.pathname 3 | 4 | let navItems = [ 5 | { contents: 'Home', href: '/', isActive: false }, 6 | { contents: 'About', href: '/about/', isActive: false }, 7 | { contents: 'Contact', href: '/contact/', isActive: false }, 8 | { contents: 'Basic', href: '/basic/', isActive: false }, 9 | { contents: 'Blog', href: '/blog/', isActive: false }, 10 | { contents: 'Gallery', href: '/gallery/', isActive: false }, 11 | { contents: 'JS Test', href: '/js-test/', isActive: false }, 12 | { contents: 'Sanity', href: '/sanity/', isActive: false }, 13 | ] 14 | 15 | navItems = navItems.map(item => { 16 | if (item.href === '/' ){ 17 | if (pagePath === item.href) { 18 | item.isActive = true 19 | } 20 | 21 | return item 22 | } 23 | 24 | if (item.href !== '/') { 25 | if (pagePath.includes(item.href)) { 26 | item.isActive = true 27 | } 28 | } 29 | 30 | return item 31 | }) 32 | --- 33 | 34 | 43 | 44 | 59 | -------------------------------------------------------------------------------- /src/components/PortableText.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /src/components/Search.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |

Search

15 | 16 | 17 | {#each hits as hit} 18 |
19 |

{hit.content || hit.h2 || hit.h1}

20 |

Under this file: {hit.h1}

21 | {hit.link} 22 |
23 | {/each} 24 | -------------------------------------------------------------------------------- /src/css/reset.css: -------------------------------------------------------------------------------- 1 | .reset { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /src/css/styles.css: -------------------------------------------------------------------------------- 1 | @import './reset.css'; 2 | 3 | :root { 4 | --color: red; 5 | } 6 | 7 | p { 8 | max-width: 35rem; 9 | } 10 | 11 | img { 12 | max-width: 100%; 13 | } 14 | -------------------------------------------------------------------------------- /src/layouts/Base/Base.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import '../../css/styles.css' 3 | import Head from './Head.astro' 4 | import Nav from '../../components/Nav.astro' 5 | const props = Astro.props 6 | --- 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 |
21 | This is the default message 22 |
23 | 24 | 25 | 26 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/layouts/Base/Head.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { title, description, imageURL } = Astro.props 3 | const defaultDescription = 'This is a demo site for Astro' 4 | 5 | const pageTitle = title + ' | ' + 'Astro Demo' 6 | const pageDescription = description || defaultDescription 7 | const canonicalURL = Astro.canonicalURL.href 8 | 9 | const OGImageURL = imageURL 10 | ? `${Astro.canonicalURL.origin}/images/${imageURL}` 11 | : `${Astro.canonicalURL.origin}/images/fallback.jpg` 12 | --- 13 | 14 | 15 | 16 | 17 | 18 | { title } 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/layouts/BasicPage.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from './Base/Base.astro' 3 | const props = Astro.props.content 4 | const { title } = props 5 | --- 6 | 7 | 8 |
9 |

{title}

10 | Default Content 11 |
12 | 13 | -------------------------------------------------------------------------------- /src/layouts/BlogPost.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from './Base/Base.astro' 3 | const props = Astro.props.content 4 | const { title } = props 5 | --- 6 | 7 | 8 |
9 |

{title}

10 | Default Content 11 |
12 | 13 | -------------------------------------------------------------------------------- /src/layouts/GalleryPage.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from './Base/Base.astro' 3 | const props = Astro.props 4 | const { title, images } = props 5 | let imageURLs = images.map(image => { 6 | return `/images/photos/${image}` 7 | }) 8 | --- 9 | 10 | 11 |
12 |

{title}

13 | 14 |
15 | {imageURLs.map(url => ( 16 | 17 | ))} 18 |
19 |
20 | 21 | -------------------------------------------------------------------------------- /src/pages/404.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from '../layouts/Base/Base.astro' 3 | --- 4 | 5 | 6 |

404

7 |

Page not found

8 | 9 | -------------------------------------------------------------------------------- /src/pages/about.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from '../layouts/Base/Base.astro' 3 | --- 4 | 5 | 6 |

About Page

7 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo!

8 | 9 | -------------------------------------------------------------------------------- /src/pages/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../layouts/BasicPage.astro' 3 | setup: | 4 | import Card from '../components/Card.astro' 5 | import Counter from '../components/Counter.svelte' 6 | title: Basic Page 7 | --- 8 | 9 | 10 | Content here. 11 | 12 | 13 | 14 | 15 | ## Subtitle Title 16 | 17 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 18 | 19 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 20 | 21 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 22 | -------------------------------------------------------------------------------- /src/pages/blog.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sortPosts} from '../utilities/blog.js' 3 | import Base from '../layouts/Base/Base.astro' 4 | import Article from '../components/Article.astro' 5 | const posts = await Astro.glob('./blog/*.md') 6 | const sorted = sortPosts(posts) 7 | 8 | --- 9 | 10 | 11 |

Blog

12 | 13 | {sorted.map(post => ( 14 |
15 | ))} 16 | 17 | -------------------------------------------------------------------------------- /src/pages/blog/fourth-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/BlogPost.astro' 3 | title: Fourth post 4 | date: 2022-06-20 5 | --- 6 | 7 | Hello world 8 | 9 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 10 | 11 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 12 | 13 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 14 | 15 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 16 | -------------------------------------------------------------------------------- /src/pages/blog/quick-seo-tips.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/BlogPost.astro' 3 | title: Quick SEO Tips 4 | description: Some quick SEO Tips 5 | imageURL: 'somewhere.jpg' 6 | date: 2022-06-17 7 | --- 8 | 9 | {frontmatter.description} 10 | 11 | 1. Make sure there is one h1 element 12 | 2. Make sure there are some subheaders — h2, h3 13 | 3. Do internal links whenever possible 14 | 15 | ## This is a subheader 16 | 17 | And some text inside 18 | 19 | ## This is another subheader 20 | 21 | And some text inside 22 | -------------------------------------------------------------------------------- /src/pages/blog/second-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/BlogPost.astro' 3 | title: Second post 4 | date: 2022-06-18 5 | --- 6 | 7 | Hello world 8 | 9 | Second Post!!!!! 10 | 11 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 12 | 13 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 14 | 15 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 16 | 17 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 18 | -------------------------------------------------------------------------------- /src/pages/blog/third-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/BlogPost.astro' 3 | title: Third post 4 | date: 2022-06-19 5 | --- 6 | 7 | Hello world 8 | 9 | Third Post. 10 | 11 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 12 | 13 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 14 | 15 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 16 | 17 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 18 | -------------------------------------------------------------------------------- /src/pages/contact.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from '../layouts/Base/Base.astro' 3 | --- 4 | 5 | 6 |

Contact Page

7 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo!

8 | 9 |
13 | 18 |

19 | 20 |

21 |

22 | 23 |

24 |

25 | 26 |

27 |

28 | 29 |

30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /src/pages/gallery.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Gallery from '../layouts/GalleryPage.astro' 3 | const title = 'Gallery Page' 4 | const images = [ 5 | 'wolverine.png', 6 | 'john.png', 7 | 'bill.png', 8 | 'christopher.png', 9 | 'tim.png' 10 | ] 11 | --- 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Base from '../layouts/Base/Base.astro' 3 | import Card from '../components/Card.astro' 4 | import { Markdown } from 'astro/components' 5 | --- 6 | 7 | 8 |

Build and Deploy Session 1

9 |

Here is our group photo!

10 | 11 | Group photo from the first session of Build and Deploy 12 | 13 | 14 |

15 | Lorem ipsum, dolor sit amet consectetur adipisicing elit. Recusandae impedit praesentium fuga voluptatibus dolorem facere facilis? Quos tenetur, ducimus ad facilis voluptates maxime eligendi, saepe suscipit labore ipsam veritatis possimus. 16 | 17 |

18 |
19 | 20 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo!

21 | 22 | 23 | ## Write some markdown here 24 | 25 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 26 | 27 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 28 | 29 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam placeat fugit dignissimos cumque nihil neque odit, sit et quasi non quia quae earum ea beatae laboriosam adipisci magni commodi illo! 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/pages/js-test.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Counter from '../components/Counter.svelte' 3 | --- 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/pages/rss.xml.js: -------------------------------------------------------------------------------- 1 | import rss from '@astrojs/rss' 2 | 3 | const importResult = import.meta.globEager('./blog/*.md') 4 | const posts = Object.values(importResult) 5 | 6 | export const get = () => 7 | rss({ 8 | title: 'This is your title', 9 | description: 'This is your description', 10 | site: 'https://astro-demo/', 11 | items: posts.map(post => ({ 12 | title: post.frontmatter.title, 13 | pubDate: post.frontmatter.date, 14 | link: post.url 15 | })) 16 | }) 17 | -------------------------------------------------------------------------------- /src/pages/sanity/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { fetch } from '../../utilities/sanity.js' 3 | import Base from '../../layouts/Base/Base.astro' 4 | import PortableText from '../../components/PortableText.svelte' 5 | 6 | export async function getStaticPaths() { 7 | const query = '*[_type == "blogPost"]' 8 | const posts = await fetch(query) 9 | 10 | const paths = posts.map(post => { 11 | return { 12 | params: { slug: post.slug.current }, 13 | props: {post} 14 | } 15 | }) 16 | 17 | return paths 18 | } 19 | 20 | const { slug } = Astro.params 21 | const { post } = Astro.props 22 | 23 | let tags = [] 24 | if (post.tags) tags = post.tags.map(tag => tag.value) 25 | 26 | // Prev/Next Page Links 27 | const query = '*[_type == "blogPost"]' 28 | const posts = await fetch(query) 29 | 30 | // Sort the post here before finding the index 31 | const postIndex = posts.findIndex(p => { 32 | return p._id === post._id 33 | }) 34 | 35 | const previousPost = posts[postIndex -1] 36 | const nextPost = posts[postIndex + 1] 37 | 38 | const previousPostLink = previousPost 39 | ? `/sanity/${previousPost.slug.current}` 40 | : '' 41 | 42 | const nextPostLink = nextPost 43 | ? `/sanity/${nextPost.slug.current}` 44 | : '' 45 | --- 46 | 47 | 48 |

{post.title}

49 |

Slug: {post.slug.current}

50 |

Tags: {tags.map((tag, index) => { 51 | const link = `/tags/${tag}` 52 | const isLastItem = index === tags.length - 1 53 | 54 | if (isLastItem) { 55 | return ( 56 | {tag} 57 | ) 58 | } 59 | 60 | return ( 61 | {tag} 62 | , 63 | ) 64 | } 65 | 66 | 67 | )}

68 | 69 | 70 | 71 |

Navigation

72 | 73 | 74 | {previousPostLink && ( 75 |

{previousPost.title}

76 | )} 77 | 78 | {nextPostLink && ( 79 |

{nextPost.title}

80 | )} 81 | 82 | -------------------------------------------------------------------------------- /src/pages/sanity/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {fetch} from '../../utilities/sanity.js' 3 | const query = '*[_type == "blogPost"]' 4 | const posts = await fetch(query) 5 | --- 6 | 7 |

Posts from Sanity

8 |
    9 | {posts.map(post => ( 10 |
  • 11 | {post.title} 12 |
  • 13 | 14 | ))} 15 |
16 | -------------------------------------------------------------------------------- /src/pages/search.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Search from '../components/Search.svelte' 3 | --- 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/scss/styles.scss: -------------------------------------------------------------------------------- 1 | body { 2 | p { 3 | color: red; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/utilities/blog.js: -------------------------------------------------------------------------------- 1 | import dateFns from 'date-fns' 2 | 3 | export function sortPosts (posts) { 4 | return posts.sort((a, b) => { 5 | const aDate = new Date(a.frontmatter.date) 6 | const bDate = new Date(b.frontmatter.date) 7 | 8 | return bDate.getTime() - aDate.getTime() 9 | }) 10 | } 11 | 12 | export function readableDate (date) { 13 | return dateFns.format(date, 'MMM do, yyyy') 14 | } 15 | -------------------------------------------------------------------------------- /src/utilities/sanity.js: -------------------------------------------------------------------------------- 1 | import sanityClient from '@sanity/client' 2 | import imageUrlBuilder from '@sanity/image-url' 3 | 4 | const client = sanityClient({ 5 | projectId: 'pa19rq30', 6 | dataset: 'production', 7 | apiVersion: '2022-06-24', 8 | useCdn: true 9 | }) 10 | const imageBuilder = imageUrlBuilder(client) 11 | 12 | export function fetch (query, param = {}) { 13 | return client.fetch(query, param) 14 | } 15 | 16 | export function getImageUrl (source, opts = {}) { 17 | let part = imageBuilder.image(source) 18 | 19 | if (notEmptyObject(opts)) { 20 | Object.entries(opts).forEach(entry => { 21 | const [key, value] = entry 22 | part = part[key](value) // Does things like part.width(200) 23 | }) 24 | } 25 | 26 | return part.url() 27 | } 28 | 29 | function notEmptyObject (obj) { 30 | return Object.keys(obj).length > 0 31 | } 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable top-level await, and other modern ESM features. 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | // Enable node-style module resolution, for things like npm package imports. 7 | "moduleResolution": "node", 8 | // Enable JSON imports. 9 | "resolveJsonModule": true, 10 | // Enable stricter transpilation for better output. 11 | "isolatedModules": true, 12 | // Add type definitions for our Vite runtime. 13 | "types": ["vite/client"] 14 | } 15 | } 16 | --------------------------------------------------------------------------------