├── .env.example ├── .gitignore ├── .npmrc ├── .stackblitzrc ├── README.md ├── astro.config.mjs ├── package-lock.json ├── package.json ├── public ├── assets │ └── blog │ │ └── introducing-astro.jpg ├── blog.css ├── favicon.ico ├── global.css ├── search.css ├── search.js ├── social.jpg └── social.png ├── src ├── components │ ├── Author.astro │ ├── BaseHead.astro │ ├── BlogHeader.astro │ ├── BlogPost.astro │ ├── BlogPostPreview.astro │ └── Logo.astro ├── layouts │ └── BlogPost.astro ├── lib │ └── typesense.js └── pages │ ├── index.astro │ ├── posts │ ├── astro-2.md │ ├── astro-3.md │ └── introducing-astro.md │ ├── search.astro │ └── search.json.astro └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | TYPESENSE_HOST=xxx.a1.typesense.net 2 | TYPESENSE_PORT=443 3 | TYPESENSE_PROTOCOL=https 4 | TYPESENSE_ADMIN_KEY=xxx 5 | TYPESENSE_SEARCH_KEY=xxx 6 | SEARCH_ENDPOINT=http://localhost:3000/search.json -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist 3 | 4 | # dependencies 5 | node_modules/ 6 | .snowpack/ 7 | 8 | # logs 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # environment variables 14 | .env 15 | .env.production 16 | 17 | # macOS-specific files 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ## force pnpm to hoist 2 | shamefully-hoist = true -------------------------------------------------------------------------------- /.stackblitzrc: -------------------------------------------------------------------------------- 1 | { 2 | "startCommand": "npm start", 3 | "env": { 4 | "ENABLE_CJS_IMPORTS": true 5 | } 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Astro Starter Kit: Blog 2 | 3 | ``` 4 | npm init astro -- --template blog 5 | ``` 6 | 7 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/snowpackjs/astro/tree/latest/examples/blog) 8 | 9 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 10 | 11 | Features: 12 | 13 | - ✅ SEO-friendly setup with canonical URLs and OpenGraph data 14 | - ✅ Full Markdown support 15 | - ✅ RSS 2.0 generation 16 | - ✅ Sitemap.xml generation 17 | 18 | ## 🚀 Project Structure 19 | 20 | Inside of your Astro project, you'll see the following folders and files: 21 | 22 | ``` 23 | / 24 | ├── public/ 25 | │ ├── robots.txt 26 | │ └── favicon.ico 27 | ├── src/ 28 | │ ├── components/ 29 | │ │ └── Tour.astro 30 | │ └── pages/ 31 | │ └── index.astro 32 | └── package.json 33 | ``` 34 | 35 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. 36 | 37 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. 38 | 39 | Any static assets, like images, can be placed in the `public/` directory. 40 | 41 | ## 🧞 Commands 42 | 43 | All commands are run from the root of the project, from a terminal: 44 | 45 | | Command | Action | 46 | | :-------------- | :------------------------------------------ | 47 | | `npm install` | Installs dependencies | 48 | | `npm run dev` | Starts local dev server at `localhost:3000` | 49 | | `npm run build` | Build your production site to `./dist/` | 50 | 51 | ## 👀 Want to learn more? 52 | 53 | Feel free to check [our documentation](https://github.com/snowpackjs/astro) or jump into our [Discord server](https://astro.build/chat). 54 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | // Full Astro Configuration API Documentation: 2 | // https://docs.astro.build/reference/configuration-reference 3 | 4 | // @type-check enabled! 5 | // VSCode and other TypeScript-enabled text editors will provide auto-completion, 6 | // helpful tooltips, and warnings if your exported object is invalid. 7 | // You can disable this by removing "@ts-check" and `@type` comments below. 8 | 9 | // @ts-check 10 | export default /** @type {import('astro').AstroUserConfig} */ ({ 11 | // Enable the Preact renderer to support Preact JSX components. 12 | renderers: ["@astrojs/renderer-preact", "@astrojs/renderer-vue"], 13 | }); 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@example/blog", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "prebuild": "node src/lib/typesense.js", 10 | "preview": "astro preview" 11 | }, 12 | "devDependencies": { 13 | "@astrojs/renderer-preact": "^0.2.2", 14 | "astro": "^0.20.7", 15 | "dotenv": "^10.0.0" 16 | }, 17 | "dependencies": { 18 | "typesense": "^0.15.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/blog/introducing-astro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebelchris/astro-typesense-search/7b698068ed4218265fd5469f1dc24ab4093a53d4/public/assets/blog/introducing-astro.jpg -------------------------------------------------------------------------------- /public/blog.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, 3 | sans-serif, Apple Color Emoji, Segoe UI Emoji; 4 | --font-body: "IBM Plex Sans", var(--font-fallback); 5 | --font-mono: "IBM Plex Mono", Consolas, "Andale Mono WT", "Andale Mono", 6 | "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", 7 | "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, 8 | "Courier New", Courier, monospace; 9 | 10 | --color-white: #fff; 11 | --color-black: #000014; 12 | 13 | --color-gray-50: #f9fafb; 14 | --color-gray-100: #f3f4f6; 15 | --color-gray-200: #e5e7eb; 16 | --color-gray-300: #d1d5db; 17 | --color-gray-400: #9ca3af; 18 | --color-gray-500: #6b7280; 19 | --color-gray-600: #4b5563; 20 | --color-gray-700: #374151; 21 | --color-gray-800: #1f2937; 22 | --color-gray-900: #111827; 23 | 24 | --color-blue: #3894ff; 25 | --color-blue-rgb: 56, 148, 255; 26 | --color-green: #17c083; 27 | --color-green-rgb: 23, 192, 131; 28 | --color-orange: #ff5d01; 29 | --color-orange-rgb: 255, 93, 1; 30 | --color-purple: #882de7; 31 | --color-purple-rgb: 136, 45, 231; 32 | --color-red: #ff1639; 33 | --color-red-rgb: 255, 22, 57; 34 | --color-yellow: #ffbe2d; 35 | --color-yellow-rgb: 255, 190, 45; 36 | } 37 | 38 | :root { 39 | color-scheme: light; 40 | --theme-accent: var(--color-orange); 41 | --theme-accent-rgb: var(--color-orange-rgb); 42 | --theme-accent-opacity: 0.1; 43 | --theme-divider: var(--color-gray-100); 44 | --theme-text: var(--color-gray-800); 45 | --theme-text-light: var(--color-gray-600); 46 | --theme-text-lighter: var(--color-gray-400); 47 | --theme-bg: var(--color-white); 48 | --theme-bg-offset: var(--color-gray-100); 49 | --theme-bg-accent: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); 50 | --theme-code-inline-bg: var(--color-gray-100); 51 | --theme-code-text: var(--color-gray-100); 52 | --theme-code-bg: var(--color-gray-700); 53 | } 54 | 55 | body { 56 | background: var(--theme-bg); 57 | color: var(--theme-text); 58 | } 59 | 60 | :root.theme-dark { 61 | color-scheme: dark; 62 | --theme-accent-opacity: 0.3; 63 | --theme-divider: var(--color-gray-900); 64 | --theme-text: var(--color-gray-200); 65 | --theme-text-light: var(--color-gray-400); 66 | --theme-text-lighter: var(--color-gray-600); 67 | --theme-bg: var(--color-black); 68 | --theme-bg-offset: var(--color-gray-900); 69 | --theme-code-inline-bg: var(--color-gray-800); 70 | --theme-code-text: var(--color-gray-200); 71 | --theme-code-bg: var(--color-gray-900); 72 | } 73 | 74 | ::selection { 75 | color: var(--theme-accent); 76 | background-color: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); 77 | } 78 | 79 | * { 80 | box-sizing: border-box; 81 | margin: 0; 82 | } 83 | 84 | :root { 85 | --user-font-scale: 1rem - 16px; 86 | --max-width: calc(100% - 2rem); 87 | } 88 | 89 | @media (min-width: 50em) { 90 | :root { 91 | --max-width: 40em; 92 | } 93 | } 94 | 95 | body { 96 | display: flex; 97 | flex-direction: column; 98 | min-height: 100vh; 99 | font-family: var(--font-body); 100 | font-size: 1rem; 101 | font-size: clamp( 102 | 0.875rem, 103 | 0.4626rem + 1.0309vw + var(--user-font-scale), 104 | 1.125rem 105 | ); 106 | line-height: 1.625; 107 | } 108 | 109 | body { 110 | width: 100%; 111 | display: grid; 112 | --gutter: 0.5rem; 113 | --doc-padding: 2rem; 114 | } 115 | 116 | .layout { 117 | display: grid; 118 | grid-auto-flow: column; 119 | grid-template-columns: minmax(var(--gutter), 1fr) minmax(0, var(--max-width)) minmax( 120 | var(--gutter), 121 | 1fr 122 | ); 123 | gap: 1em; 124 | } 125 | 126 | .layout > article { 127 | grid-column: 2; 128 | } 129 | 130 | nav ul { 131 | list-style: none; 132 | padding: 0; 133 | } 134 | 135 | /* Typography */ 136 | :is(h1, h2, h3, h4, h5, h6) { 137 | margin-bottom: 1.38rem; 138 | font-weight: 400; 139 | line-height: 1.3; 140 | } 141 | 142 | :is(h1, h2) { 143 | max-width: 40ch; 144 | } 145 | 146 | :is(h2, h3):not(:first-child) { 147 | margin-top: 3rem; 148 | } 149 | 150 | h1 { 151 | font-size: clamp(2.488rem, 1.924rem + 1.41vw, 3.052rem); 152 | } 153 | 154 | h2 { 155 | font-size: clamp(2.074rem, 1.707rem + 0.9175vw, 2.441rem); 156 | } 157 | 158 | h3 { 159 | font-size: clamp(1.728rem, 1.503rem + 0.5625vw, 1.953rem); 160 | } 161 | 162 | h4 { 163 | font-size: clamp(1.44rem, 1.317rem + 0.3075vw, 1.563rem); 164 | } 165 | 166 | h5 { 167 | font-size: clamp(1.2rem, 1.15rem + 0.125vw, 1.25rem); 168 | } 169 | 170 | p { 171 | color: var(--theme-text-light); 172 | } 173 | 174 | small, 175 | .text_small { 176 | font-size: 0.833rem; 177 | } 178 | 179 | a { 180 | color: var(--theme-accent); 181 | font-weight: 400; 182 | text-underline-offset: 0.08em; 183 | text-decoration: none; 184 | align-items: center; 185 | gap: 0.5rem; 186 | } 187 | 188 | a > code:not([class*="language"]) { 189 | position: relative; 190 | color: var(--theme-accent); 191 | background: transparent; 192 | text-underline-offset: var(--padding-block); 193 | } 194 | 195 | a > code:not([class*="language"])::before { 196 | content: ""; 197 | position: absolute; 198 | top: 0; 199 | right: 0; 200 | bottom: 0; 201 | left: 0; 202 | display: block; 203 | background: var(--theme-accent); 204 | opacity: var(--theme-accent-opacity); 205 | border-radius: var(--border-radius); 206 | } 207 | 208 | a:hover, 209 | a:focus { 210 | text-decoration: underline; 211 | } 212 | 213 | a:focus { 214 | outline: 2px solid currentColor; 215 | outline-offset: 0.25em; 216 | } 217 | 218 | strong { 219 | font-weight: 600; 220 | color: inherit; 221 | } 222 | 223 | /* Supporting Content */ 224 | 225 | code:not([class*="language"]) { 226 | --border-radius: 3px; 227 | --padding-block: 0.2rem; 228 | --padding-inline: 0.33rem; 229 | 230 | font-family: var(--font-mono); 231 | font-size: 0.85em; 232 | color: inherit; 233 | background-color: var(--theme-code-inline-bg); 234 | padding: var(--padding-block) var(--padding-inline); 235 | margin: calc(var(--padding-block) * -1) -0.125em; 236 | border-radius: var(--border-radius); 237 | } 238 | 239 | pre > code:not([class*="language"]) { 240 | background-color: transparent; 241 | padding: 0; 242 | margin: 0; 243 | border-radius: 0; 244 | color: inherit; 245 | } 246 | 247 | pre { 248 | position: relative; 249 | background-color: var(--theme-code-bg); 250 | color: var(--theme-code-text); 251 | --padding-block: 1rem; 252 | --padding-inline: 2rem; 253 | padding: var(--padding-block) var(--padding-inline); 254 | padding-right: calc(var(--padding-inline) * 2); 255 | margin-left: calc(50vw - var(--padding-inline)); 256 | transform: translateX(-50vw); 257 | 258 | line-height: 1.414; 259 | width: calc(100vw + (var(--padding-inline) * 2)); 260 | max-width: calc(100% + (var(--padding-inline) * 2)); 261 | overflow-y: hidden; 262 | overflow-x: auto; 263 | } 264 | 265 | @media (min-width: 37.75em) { 266 | pre { 267 | --padding-inline: 1.25rem; 268 | border-radius: 8px; 269 | } 270 | } 271 | 272 | .flex { 273 | display: flex; 274 | align-items: center; 275 | } 276 | 277 | img.cover { 278 | width: 100%; 279 | max-height: 50vh; 280 | object-fit: cover; 281 | } 282 | 283 | blockquote { 284 | font-size: 1.5rem; 285 | --padding-block: 1rem; 286 | --padding-inline: 1.25rem; 287 | --color: var(--theme-divider); 288 | 289 | display: flex; 290 | flex-direction: column; 291 | 292 | padding: var(--padding-block) var(--padding-inline); 293 | margin-left: calc(var(--padding-inline) * -1); 294 | margin-right: calc(var(--padding-inline) * -1); 295 | 296 | background: transparent; 297 | border-left: calc(var(--padding-inline) / 2) solid var(--color); 298 | border-radius: 0; 299 | } 300 | 301 | blockquote .source { 302 | font-weight: 500; 303 | color: var(--color); 304 | font-size: 1rem; 305 | } 306 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebelchris/astro-typesense-search/7b698068ed4218265fd5469f1dc24ab4093a53d4/public/favicon.ico -------------------------------------------------------------------------------- /public/global.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", 3 | Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 4 | --font-mono: "IBM Plex Mono", Consolas, "Andale Mono WT", "Andale Mono", 5 | "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", 6 | "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, 7 | "Courier New", Courier, monospace; 8 | --color-green: #17c083; 9 | } 10 | 11 | * { 12 | box-sizing: border-box; 13 | margin: 0; 14 | } 15 | 16 | html { 17 | display: grid; 18 | width: 100%; 19 | max-width: 100vw; 20 | overflow: hidden; 21 | height: 100%; 22 | background-color: #000014; 23 | } 24 | 25 | html, 26 | body { 27 | padding: 0; 28 | font-size: clamp(14px, calc(1rem + (3vw - 1.2rem)), 20px); 29 | font-family: var(--font-sans); 30 | font-weight: 400; 31 | background-image: radial-gradient( 32 | 87.7% 87.7% at 85.6% 18.14%, 33 | #111827 0%, 34 | #000014 100% 35 | ); 36 | background-repeat: no-repeat; 37 | color: #f3f4f6; 38 | } 39 | 40 | body { 41 | position: relative; 42 | display: grid; 43 | place-items: center; 44 | min-width: 100%; 45 | max-width: 100vw; 46 | min-height: 100vh; 47 | overflow-x: hidden; 48 | } 49 | 50 | .visually-hidden { 51 | clip: rect(0 0 0 0); 52 | clip-path: inset(50%); 53 | height: 1px; 54 | overflow: hidden; 55 | position: absolute; 56 | white-space: nowrap; 57 | width: 1px; 58 | } 59 | 60 | a { 61 | position: relative; 62 | text-decoration: none; 63 | color: var(--color-green); 64 | padding: 0.05em 0.125em; 65 | margin: -0.05em -0.125em; 66 | transition: color 120ms cubic-bezier(0.23, 1, 0.32, 1); 67 | z-index: 0; 68 | display: inline-block; 69 | } 70 | 71 | a:hover, 72 | a:focus { 73 | color: black; 74 | } 75 | 76 | a:hover::before, 77 | a:focus::before { 78 | transform: scaleY(1); 79 | background: var(--color-green); 80 | } 81 | 82 | a:visited { 83 | color: var(--color-green); 84 | } 85 | 86 | a:visited:hover, 87 | a:visited:focus { 88 | color: black; 89 | } 90 | 91 | a::before { 92 | transform-origin: bottom center; 93 | content: ""; 94 | display: block; 95 | position: absolute; 96 | top: 0; 97 | right: 0; 98 | bottom: 0; 99 | left: 0; 100 | inset: 0; 101 | background: var(--color-green); 102 | pointer-events: none; 103 | transform: scaleY(0.05); 104 | transition: transform 120ms cubic-bezier(0.23, 1, 0.32, 1), 105 | background 120ms cubic-bezier(0.23, 1, 0.32, 1); 106 | z-index: -1; 107 | } 108 | -------------------------------------------------------------------------------- /public/search.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, 3 | sans-serif, Apple Color Emoji, Segoe UI Emoji; 4 | --font-body: "IBM Plex Sans", var(--font-fallback); 5 | --font-mono: "IBM Plex Mono", Consolas, "Andale Mono WT", "Andale Mono", 6 | "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", 7 | "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, 8 | "Courier New", Courier, monospace; 9 | 10 | --color-white: #fff; 11 | --color-black: #000014; 12 | 13 | --color-gray-50: #f9fafb; 14 | --color-gray-100: #f3f4f6; 15 | --color-gray-200: #e5e7eb; 16 | --color-gray-300: #d1d5db; 17 | --color-gray-400: #9ca3af; 18 | --color-gray-500: #6b7280; 19 | --color-gray-600: #4b5563; 20 | --color-gray-700: #374151; 21 | --color-gray-800: #1f2937; 22 | --color-gray-900: #111827; 23 | 24 | --color-blue: #3894ff; 25 | --color-blue-rgb: 56, 148, 255; 26 | --color-green: #17c083; 27 | --color-green-rgb: 23, 192, 131; 28 | --color-orange: #ff5d01; 29 | --color-orange-rgb: 255, 93, 1; 30 | --color-purple: #882de7; 31 | --color-purple-rgb: 136, 45, 231; 32 | --color-red: #ff1639; 33 | --color-red-rgb: 255, 22, 57; 34 | --color-yellow: #ffbe2d; 35 | --color-yellow-rgb: 255, 190, 45; 36 | } 37 | 38 | :root { 39 | color-scheme: light; 40 | --theme-accent: var(--color-orange); 41 | --theme-accent-rgb: var(--color-orange-rgb); 42 | --theme-accent-opacity: 0.1; 43 | --theme-divider: var(--color-gray-100); 44 | --theme-text: var(--color-gray-800); 45 | --theme-text-light: var(--color-gray-600); 46 | --theme-text-lighter: var(--color-gray-400); 47 | --theme-bg: var(--color-white); 48 | --theme-bg-offset: var(--color-gray-100); 49 | --theme-bg-accent: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); 50 | --theme-code-inline-bg: var(--color-gray-100); 51 | --theme-code-text: var(--color-gray-100); 52 | --theme-code-bg: var(--color-gray-700); 53 | } 54 | 55 | body { 56 | background: var(--theme-bg); 57 | color: var(--theme-text); 58 | } 59 | 60 | :root.theme-dark { 61 | color-scheme: dark; 62 | --theme-accent-opacity: 0.3; 63 | --theme-divider: var(--color-gray-900); 64 | --theme-text: var(--color-gray-200); 65 | --theme-text-light: var(--color-gray-400); 66 | --theme-text-lighter: var(--color-gray-600); 67 | --theme-bg: var(--color-black); 68 | --theme-bg-offset: var(--color-gray-900); 69 | --theme-code-inline-bg: var(--color-gray-800); 70 | --theme-code-text: var(--color-gray-200); 71 | --theme-code-bg: var(--color-gray-900); 72 | } 73 | 74 | ::selection { 75 | color: var(--theme-accent); 76 | background-color: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); 77 | } 78 | 79 | * { 80 | box-sizing: border-box; 81 | margin: 0; 82 | } 83 | 84 | :root { 85 | --user-font-scale: 1rem - 16px; 86 | --max-width: calc(100% - 2rem); 87 | } 88 | 89 | @media (min-width: 50em) { 90 | :root { 91 | --max-width: 40em; 92 | } 93 | } 94 | 95 | body { 96 | display: flex; 97 | flex-direction: column; 98 | font-family: var(--font-body); 99 | font-size: 1rem; 100 | font-size: clamp( 101 | 0.875rem, 102 | 0.4626rem + 1.0309vw + var(--user-font-scale), 103 | 1.125rem 104 | ); 105 | line-height: 1.625; 106 | } 107 | 108 | body { 109 | width: 100%; 110 | display: grid; 111 | --gutter: 0.5rem; 112 | --doc-padding: 2rem; 113 | } 114 | 115 | .layout { 116 | display: grid; 117 | grid-auto-flow: column; 118 | grid-template-columns: minmax(var(--gutter), 1fr) minmax(0, var(--max-width)) minmax( 119 | var(--gutter), 120 | 1fr 121 | ); 122 | gap: 1em; 123 | } 124 | 125 | .layout > article { 126 | grid-column: 2; 127 | } 128 | 129 | nav ul { 130 | list-style: none; 131 | padding: 0; 132 | } 133 | 134 | /* Typography */ 135 | :is(h1, h2, h3, h4, h5, h6) { 136 | margin-bottom: 1.38rem; 137 | font-weight: 400; 138 | line-height: 1.3; 139 | } 140 | 141 | :is(h1, h2) { 142 | max-width: 40ch; 143 | } 144 | 145 | :is(h2, h3):not(:first-child) { 146 | margin-top: 3rem; 147 | } 148 | 149 | h1 { 150 | font-size: clamp(2.488rem, 1.924rem + 1.41vw, 3.052rem); 151 | } 152 | 153 | h2 { 154 | font-size: clamp(2.074rem, 1.707rem + 0.9175vw, 2.441rem); 155 | } 156 | 157 | h3 { 158 | font-size: clamp(1.728rem, 1.503rem + 0.5625vw, 1.953rem); 159 | } 160 | 161 | h4 { 162 | font-size: clamp(1.44rem, 1.317rem + 0.3075vw, 1.563rem); 163 | } 164 | 165 | h5 { 166 | font-size: clamp(1.2rem, 1.15rem + 0.125vw, 1.25rem); 167 | } 168 | 169 | p { 170 | color: var(--theme-text-light); 171 | } 172 | 173 | small, 174 | .text_small { 175 | font-size: 0.833rem; 176 | } 177 | 178 | a { 179 | color: var(--theme-accent); 180 | font-weight: 400; 181 | text-underline-offset: 0.08em; 182 | text-decoration: none; 183 | align-items: center; 184 | gap: 0.5rem; 185 | } 186 | 187 | a > code:not([class*="language"]) { 188 | position: relative; 189 | color: var(--theme-accent); 190 | background: transparent; 191 | text-underline-offset: var(--padding-block); 192 | } 193 | 194 | a > code:not([class*="language"])::before { 195 | content: ""; 196 | position: absolute; 197 | top: 0; 198 | right: 0; 199 | bottom: 0; 200 | left: 0; 201 | display: block; 202 | background: var(--theme-accent); 203 | opacity: var(--theme-accent-opacity); 204 | border-radius: var(--border-radius); 205 | } 206 | 207 | a:hover, 208 | a:focus { 209 | text-decoration: underline; 210 | } 211 | 212 | a:focus { 213 | outline: 2px solid currentColor; 214 | outline-offset: 0.25em; 215 | } 216 | 217 | strong { 218 | font-weight: 600; 219 | color: inherit; 220 | } 221 | 222 | /* Supporting Content */ 223 | 224 | code:not([class*="language"]) { 225 | --border-radius: 3px; 226 | --padding-block: 0.2rem; 227 | --padding-inline: 0.33rem; 228 | 229 | font-family: var(--font-mono); 230 | font-size: 0.85em; 231 | color: inherit; 232 | background-color: var(--theme-code-inline-bg); 233 | padding: var(--padding-block) var(--padding-inline); 234 | margin: calc(var(--padding-block) * -1) -0.125em; 235 | border-radius: var(--border-radius); 236 | } 237 | 238 | pre > code:not([class*="language"]) { 239 | background-color: transparent; 240 | padding: 0; 241 | margin: 0; 242 | border-radius: 0; 243 | color: inherit; 244 | } 245 | 246 | pre { 247 | position: relative; 248 | background-color: var(--theme-code-bg); 249 | color: var(--theme-code-text); 250 | --padding-block: 1rem; 251 | --padding-inline: 2rem; 252 | padding: var(--padding-block) var(--padding-inline); 253 | padding-right: calc(var(--padding-inline) * 2); 254 | margin-left: calc(50vw - var(--padding-inline)); 255 | transform: translateX(-50vw); 256 | 257 | line-height: 1.414; 258 | width: calc(100vw + (var(--padding-inline) * 2)); 259 | max-width: calc(100% + (var(--padding-inline) * 2)); 260 | overflow-y: hidden; 261 | overflow-x: auto; 262 | } 263 | 264 | @media (min-width: 37.75em) { 265 | pre { 266 | --padding-inline: 1.25rem; 267 | border-radius: 8px; 268 | } 269 | } 270 | 271 | .flex { 272 | display: flex; 273 | align-items: center; 274 | } 275 | 276 | img.cover { 277 | width: 100%; 278 | max-height: 50vh; 279 | object-fit: cover; 280 | } 281 | 282 | blockquote { 283 | font-size: 1.5rem; 284 | --padding-block: 1rem; 285 | --padding-inline: 1.25rem; 286 | --color: var(--theme-divider); 287 | 288 | display: flex; 289 | flex-direction: column; 290 | 291 | padding: var(--padding-block) var(--padding-inline); 292 | margin-left: calc(var(--padding-inline) * -1); 293 | margin-right: calc(var(--padding-inline) * -1); 294 | 295 | background: transparent; 296 | border-left: calc(var(--padding-inline) / 2) solid var(--color); 297 | border-radius: 0; 298 | } 299 | 300 | blockquote .source { 301 | font-weight: 500; 302 | color: var(--color); 303 | font-size: 1rem; 304 | } 305 | ol li { 306 | margin: 2rem 0; 307 | padding-left: 1rem; 308 | } 309 | ol li p { 310 | margin-bottom: 1rem; 311 | } 312 | .ais-SearchBox-form { 313 | display: block; 314 | position: relative; 315 | margin-top: 2rem; 316 | } 317 | .ais-SearchBox-input { 318 | -webkit-appearance: none; 319 | -moz-appearance: none; 320 | appearance: none; 321 | padding: 0.3rem 1.7rem; 322 | width: 100%; 323 | position: relative; 324 | background-color: #fff; 325 | border: 1px solid #c4c8d8; 326 | border-radius: 5px; 327 | } 328 | .ais-SearchBox-loadingIndicator, 329 | .ais-SearchBox-reset, 330 | .ais-SearchBox-submit { 331 | -webkit-appearance: none; 332 | -moz-appearance: none; 333 | appearance: none; 334 | position: absolute; 335 | z-index: 1; 336 | width: 20px; 337 | height: 20px; 338 | top: 50%; 339 | right: 0.3rem; 340 | -webkit-transform: translateY(-50%); 341 | transform: translateY(-50%); 342 | } 343 | .ais-SearchBox-submit { 344 | left: 0.3rem; 345 | } 346 | .ais-SearchBox-reset { 347 | right: 0.3rem; 348 | } 349 | 350 | .ais-ClearRefinements-button, 351 | .ais-CurrentRefinements-delete, 352 | .ais-CurrentRefinements-reset, 353 | .ais-GeoSearch-redo, 354 | .ais-GeoSearch-reset, 355 | .ais-HierarchicalMenu-showMore, 356 | .ais-InfiniteHits-loadMore, 357 | .ais-InfiniteHits-loadPrevious, 358 | .ais-InfiniteResults-loadMore, 359 | .ais-Menu-showMore, 360 | .ais-RangeInput-submit, 361 | .ais-RefinementList-showMore, 362 | .ais-SearchBox-reset, 363 | .ais-SearchBox-submit, 364 | .ais-VoiceSearch-button { 365 | padding: 0; 366 | overflow: visible; 367 | font: inherit; 368 | line-height: normal; 369 | color: inherit; 370 | background: none; 371 | border: 0; 372 | cursor: pointer; 373 | -webkit-user-select: none; 374 | -moz-user-select: none; 375 | -ms-user-select: none; 376 | user-select: none; 377 | } 378 | -------------------------------------------------------------------------------- /public/search.js: -------------------------------------------------------------------------------- 1 | const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({ 2 | server: { 3 | apiKey: TYPESENSE_SEARCH_KEY, 4 | nodes: [ 5 | { 6 | host: TYPESENSE_HOST, 7 | port: TYPESENSE_PORT, 8 | protocol: TYPESENSE_PROTOCOL, 9 | }, 10 | ], 11 | cacheSearchResultsForSeconds: 2 * 60, 12 | }, 13 | additionalSearchParameters: { 14 | queryBy: 'title,description', 15 | }, 16 | }); 17 | const searchClient = typesenseInstantsearchAdapter.searchClient; 18 | const search = instantsearch({ 19 | searchClient, 20 | indexName: 'posts', 21 | }); 22 | search.addWidgets([ 23 | instantsearch.widgets.searchBox({ 24 | container: '#searchbox', 25 | }), 26 | instantsearch.widgets.hits({ 27 | container: '#hits', 28 | templates: { 29 | item: ` 30 |
31 |

{{title}}

32 |

{{ description }}

33 | Read more 34 |
`, 35 | }, 36 | }), 37 | ]); 38 | search.start(); 39 | -------------------------------------------------------------------------------- /public/social.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebelchris/astro-typesense-search/7b698068ed4218265fd5469f1dc24ab4093a53d4/public/social.jpg -------------------------------------------------------------------------------- /public/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebelchris/astro-typesense-search/7b698068ed4218265fd5469f1dc24ab4093a53d4/public/social.png -------------------------------------------------------------------------------- /src/components/Author.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export interface Props { 3 | name: string; 4 | href: string; 5 | } 6 | 7 | const { name, href } = Astro.props; 8 | --- 9 | 10 |
11 |

{name}

12 |
13 | 14 | 19 | -------------------------------------------------------------------------------- /src/components/BaseHead.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export interface Props { 3 | title: string; 4 | description: string; 5 | permalink: string; 6 | } 7 | const { title, description, permalink } = Astro.props; 8 | --- 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {title} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /src/components/BlogHeader.astro: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | 27 | My Blog 28 | 29 |

30 |
31 |
32 | 33 | 90 | -------------------------------------------------------------------------------- /src/components/BlogPost.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Author from "./Author.astro"; 3 | 4 | export interface Props { 5 | title: string; 6 | author: string; 7 | publishDate: string; 8 | heroImage: string; 9 | } 10 | 11 | const { title, author, publishDate, heroImage, alt } = Astro.props; 12 | --- 13 | 14 |
15 |
16 |
17 |
18 | {heroImage && {alt}} 19 |

{publishDate}

20 |

{title}

21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 | 30 | 88 | -------------------------------------------------------------------------------- /src/components/BlogPostPreview.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export interface Props { 3 | post: any; 4 | } 5 | 6 | const { post } = Astro.props; 7 | --- 8 | 9 |
10 |
11 |

{post.publishDate}

12 |

{post.title}

13 |
14 |
15 |

{post.description}

16 | Read more 17 |
18 |
19 | 20 | 59 | -------------------------------------------------------------------------------- /src/components/Logo.astro: -------------------------------------------------------------------------------- 1 | 61 | 62 | 101 | -------------------------------------------------------------------------------- /src/layouts/BlogPost.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Markdown } from "astro/components"; 3 | import BaseHead from "../components/BaseHead.astro"; 4 | import BlogHeader from "../components/BlogHeader.astro"; 5 | import BlogPost from "../components/BlogPost.astro"; 6 | 7 | const { content } = Astro.props; 8 | const { title, description, publishDate, author, heroImage, permalink, alt } = 9 | content; 10 | --- 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/lib/typesense.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const Typesense = require('typesense'); 3 | const fetch = require('node-fetch'); 4 | 5 | (async () => { 6 | // Create a new client 7 | const client = new Typesense.Client({ 8 | nodes: [ 9 | { 10 | host: process.env.TYPESENSE_HOST, 11 | port: process.env.TYPESENSE_PORT, 12 | protocol: process.env.TYPESENSE_PROTOCOL, 13 | }, 14 | ], 15 | apiKey: process.env.TYPESENSE_ADMIN_KEY, 16 | connectionTimeoutSeconds: 2, 17 | }); 18 | 19 | // Delete the old posts collection if it exists 20 | try { 21 | await client.collections('posts').delete(); 22 | } catch (error) { 23 | console.error('Could not delete posts collection'); 24 | } 25 | 26 | // Create a post schema 27 | const postsSchema = { 28 | name: 'posts', 29 | fields: [ 30 | { name: 'title', type: 'string' }, 31 | { name: 'description', type: 'string' }, 32 | { name: 'slug', type: 'string' }, 33 | ], 34 | }; 35 | 36 | // Create post schema 37 | await client.collections().create(postsSchema); 38 | 39 | console.log('made it!'); 40 | console.log(process.env.SEARCH_ENDPOINT); 41 | 42 | // Retrieve data json 43 | const data = fetch(process.env.SEARCH_ENDPOINT).then((response) => 44 | response.json() 45 | ); 46 | 47 | // Loop over each item and create document 48 | data.then((res) => { 49 | for (post of res) { 50 | client.collections('posts').documents().create(post); 51 | } 52 | }); 53 | })().catch((err) => { 54 | console.error(err); 55 | }); 56 | -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // Component Imports 3 | import BaseHead from "../components/BaseHead.astro"; 4 | import BlogHeader from "../components/BlogHeader.astro"; 5 | import BlogPostPreview from "../components/BlogPostPreview.astro"; 6 | 7 | interface MarkdownFrontmatter { 8 | publishDate: number; 9 | } 10 | 11 | // Component Script: 12 | // You can write any JavaScript/TypeScript that you'd like here. 13 | // It will run during the build, but never in the browser. 14 | // All variables are available to use in the HTML template below. 15 | let title = "Example Blog"; 16 | let description = "The perfect starter for your perfect blog."; 17 | let permalink = "https://example.com/"; 18 | 19 | // Data Fetching: List all Markdown posts in the repo. 20 | 21 | let allPosts = Astro.fetchContent("./posts/*.md"); 22 | allPosts = allPosts.sort( 23 | (a, b) => 24 | new Date(b.publishDate).valueOf() - new Date(a.publishDate).valueOf() 25 | ); 26 | 27 | // Full Astro Component Syntax: 28 | // https://docs.astro.build/core-concepts/astro-components/ 29 | --- 30 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 48 | 49 | 50 |
51 |
52 |
53 |

{title}

54 |

{description}

55 |
56 |
57 | {allPosts.map((p) => )} 58 |
59 |
60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /src/pages/posts/astro-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Post number 2" 3 | description: "We're excited to announce Astro as a new way to build static websites and deliver lightning-fast performance without sacrificing a modern developer experience." 4 | publishDate: "Tuesday, June 15 2021" 5 | author: "fred" 6 | heroImage: "/social.jpg" 7 | alt: "Astro" 8 | layout: "../../layouts/BlogPost.astro" 9 | --- 10 | 11 | There's a simple secret to building a faster website — _just ship less_. 12 | 13 | Unfortunately, modern web development has been trending in the opposite direction—towards _more._ More JavaScript, more features, more moving parts, and ultimately more complexity needed to keep it all running smoothly. 14 | 15 | Today I'm excited to publicly share Astro: a new kind of static site builder that delivers lightning-fast performance with a modern developer experience. To design Astro, we borrowed the best parts of our favorite tools and then added a few innovations of our own, including: 16 | 17 | - **Bring Your Own Framework (BYOF):** Build your site using React, Svelte, Vue, Preact, web components, or just plain ol' HTML + JavaScript. 18 | - **100% Static HTML, No JS:** Astro renders your entire page to static HTML, removing all JavaScript from your final build by default. 19 | - **On-Demand Components:** Need some JS? Astro can automatically hydrate interactive components when they become visible on the page. If the user never sees it, they never load it. 20 | - **Fully-Featured:** Astro supports TypeScript, Scoped CSS, CSS Modules, Sass, Tailwind, Markdown, MDX, and any of your favorite npm packages. 21 | - **SEO Enabled:** Automatic sitemaps, RSS feeds, pagination and collections take the pain out of SEO and syndication. 22 | 23 | This post marks the first public beta release of Astro. **Missing features and bugs are still to be expected at this early stage.** There are still some months to go before an official 1.0 release, but there are already several fast sites built with Astro in production today. We would love your early feedback as we move towards a v1.0 release later this year. 24 | 25 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 26 | 27 | ## Getting Started 28 | 29 | Starting a new project in Astro is easy: 30 | 31 | ```shell 32 | # create your project 33 | mkdir new-project-directory 34 | cd new-project-directory 35 | npm init astro 36 | 37 | # install your dependencies 38 | npm install 39 | 40 | # start the dev server and open your browser 41 | npm run dev 42 | ``` 43 | 44 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 45 | 46 | ## How Astro Works 47 | 48 | Astro works a lot like a static site generator. If you have ever used Eleventy, Hugo, or Jekyll (or even a server-side web framework like Rails, Laravel, or Django) then you should feel right at home with Astro. 49 | 50 | In Astro, you compose your website using UI components from your favorite JavaScript web framework (React, Svelte, Vue, etc). Astro renders your entire site to static HTML during the build. The result is a fully static website with all JavaScript removed from the final page. No monolithic JavaScript application required, just static HTML that loads as fast as possible in the browser regardless of how many UI components you used to generate it. 51 | 52 | Of course, sometimes client-side JavaScript is inevitable. Image carousels, shopping carts, and auto-complete search bars are just a few examples of things that require some JavaScript to run in the browser. This is where Astro really shines: When a component needs some JavaScript, Astro only loads that one component (and any dependencies). The rest of your site continues to exist as static, lightweight HTML. 53 | 54 | In other full-stack web frameworks this level of per-component optimization would be impossible without loading the entire page in JavaScript, delaying interactivity. In Astro, this kind of [partial hydration](https://addyosmani.com/blog/rehydration/) is built into the tool itself. 55 | 56 | You can even [automatically defer components](https://codepen.io/jonneal/full/ZELvMvw) to only load once they become visible on the page with the `client:visible` directive. 57 | 58 | This new approach to web architecture is called [islands architecture](https://jasonformat.com/islands-architecture/). We didn't coin the term, but Astro may have perfected the technique. We are confident that an HTML-first, JavaScript-only-as-needed approach is the best solution for the majority of content-based websites. 59 | 60 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 61 | 62 | ## Embracing the Pit of Success 63 | 64 | > A well-designed system makes it easy to do the right things and annoying (but not impossible) to do the wrong things

– Jeff Atwood

[Falling Into The Pit of Success](https://blog.codinghorror.com/falling-into-the-pit-of-success/)
65 | 66 | Poor performance is often framed as a failure of the developer, but we respectfully disagree. In many cases, poor performance is a failure of tooling. It should be difficult to build a slow website. 67 | 68 | Astro's main design principle is to lead developers into what [Rico Mariani](https://twitter.com/ricomariani) dubbed "the pit of success". It is our goal to build every site "fast by default" while also delivering a familiar, modern developer experience. 69 | 70 | By building your site to static HTML by default, Astro makes it difficult (but never impossible 😉) to build a slow site. 71 | 72 | ## Long-Term Sustainability 73 | 74 | Astro is built by the team of open source developers behind [Snowpack](https://snowpack.dev) and [Skypack](https://skypack.dev), with additional contributions from the community. 75 | 76 | **Astro is and always will be free.** It is an open source project released under the [MIT license](https://github.com/snowpackjs/astro/blob/main/LICENSE). 77 | 78 | We care deeply about building a more sustainable future for open source software. At the same time, we need to support Astro's development long-term. This requires money (donations alone aren't enough.) 79 | 80 | We're inspired by the early success of projects like [Tailwind](https://tailwindcss.com/), [Rome](https://rome.tools/), [Remix](https://remix.run/), [Ionic](https://ionicframework.com/), and others who are experimenting with long-term financial sustainability on top of Open Source. Over the next year we'll be exploring how we can create a sustainable business to support a 100% free, open source Astro for years to come. 81 | 82 | If your company is as excited about Astro as we are, [we'd love to hear from you.](https://astro.build/chat) 83 | 84 | Finally, I'd like to give a **HUGE** thanks to the 300+ developers who joined our earliest private beta. Your feedback has been essential in shaping Astro into the tool it is today. If you're interested in getting involved (or just following along with development) please [join us on Discord.](https://astro.build/chat) 85 | 86 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 87 | -------------------------------------------------------------------------------- /src/pages/posts/astro-3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Post three" 3 | description: "We're excited to announce Astro as a new way to build static websites and deliver lightning-fast performance without sacrificing a modern developer experience." 4 | publishDate: "Tuesday, June 12 2021" 5 | author: "fred" 6 | heroImage: "/social.jpg" 7 | alt: "Astro" 8 | layout: "../../layouts/BlogPost.astro" 9 | --- 10 | 11 | There's a simple secret to building a faster website — _just ship less_. 12 | 13 | Unfortunately, modern web development has been trending in the opposite direction—towards _more._ More JavaScript, more features, more moving parts, and ultimately more complexity needed to keep it all running smoothly. 14 | 15 | Today I'm excited to publicly share Astro: a new kind of static site builder that delivers lightning-fast performance with a modern developer experience. To design Astro, we borrowed the best parts of our favorite tools and then added a few innovations of our own, including: 16 | 17 | - **Bring Your Own Framework (BYOF):** Build your site using React, Svelte, Vue, Preact, web components, or just plain ol' HTML + JavaScript. 18 | - **100% Static HTML, No JS:** Astro renders your entire page to static HTML, removing all JavaScript from your final build by default. 19 | - **On-Demand Components:** Need some JS? Astro can automatically hydrate interactive components when they become visible on the page. If the user never sees it, they never load it. 20 | - **Fully-Featured:** Astro supports TypeScript, Scoped CSS, CSS Modules, Sass, Tailwind, Markdown, MDX, and any of your favorite npm packages. 21 | - **SEO Enabled:** Automatic sitemaps, RSS feeds, pagination and collections take the pain out of SEO and syndication. 22 | 23 | This post marks the first public beta release of Astro. **Missing features and bugs are still to be expected at this early stage.** There are still some months to go before an official 1.0 release, but there are already several fast sites built with Astro in production today. We would love your early feedback as we move towards a v1.0 release later this year. 24 | 25 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 26 | 27 | ## Getting Started 28 | 29 | Starting a new project in Astro is easy: 30 | 31 | ```shell 32 | # create your project 33 | mkdir new-project-directory 34 | cd new-project-directory 35 | npm init astro 36 | 37 | # install your dependencies 38 | npm install 39 | 40 | # start the dev server and open your browser 41 | npm run dev 42 | ``` 43 | 44 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 45 | 46 | ## How Astro Works 47 | 48 | Astro works a lot like a static site generator. If you have ever used Eleventy, Hugo, or Jekyll (or even a server-side web framework like Rails, Laravel, or Django) then you should feel right at home with Astro. 49 | 50 | In Astro, you compose your website using UI components from your favorite JavaScript web framework (React, Svelte, Vue, etc). Astro renders your entire site to static HTML during the build. The result is a fully static website with all JavaScript removed from the final page. No monolithic JavaScript application required, just static HTML that loads as fast as possible in the browser regardless of how many UI components you used to generate it. 51 | 52 | Of course, sometimes client-side JavaScript is inevitable. Image carousels, shopping carts, and auto-complete search bars are just a few examples of things that require some JavaScript to run in the browser. This is where Astro really shines: When a component needs some JavaScript, Astro only loads that one component (and any dependencies). The rest of your site continues to exist as static, lightweight HTML. 53 | 54 | In other full-stack web frameworks this level of per-component optimization would be impossible without loading the entire page in JavaScript, delaying interactivity. In Astro, this kind of [partial hydration](https://addyosmani.com/blog/rehydration/) is built into the tool itself. 55 | 56 | You can even [automatically defer components](https://codepen.io/jonneal/full/ZELvMvw) to only load once they become visible on the page with the `client:visible` directive. 57 | 58 | This new approach to web architecture is called [islands architecture](https://jasonformat.com/islands-architecture/). We didn't coin the term, but Astro may have perfected the technique. We are confident that an HTML-first, JavaScript-only-as-needed approach is the best solution for the majority of content-based websites. 59 | 60 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 61 | 62 | ## Embracing the Pit of Success 63 | 64 | > A well-designed system makes it easy to do the right things and annoying (but not impossible) to do the wrong things

– Jeff Atwood

[Falling Into The Pit of Success](https://blog.codinghorror.com/falling-into-the-pit-of-success/)
65 | 66 | Poor performance is often framed as a failure of the developer, but we respectfully disagree. In many cases, poor performance is a failure of tooling. It should be difficult to build a slow website. 67 | 68 | Astro's main design principle is to lead developers into what [Rico Mariani](https://twitter.com/ricomariani) dubbed "the pit of success". It is our goal to build every site "fast by default" while also delivering a familiar, modern developer experience. 69 | 70 | By building your site to static HTML by default, Astro makes it difficult (but never impossible 😉) to build a slow site. 71 | 72 | ## Long-Term Sustainability 73 | 74 | Astro is built by the team of open source developers behind [Snowpack](https://snowpack.dev) and [Skypack](https://skypack.dev), with additional contributions from the community. 75 | 76 | **Astro is and always will be free.** It is an open source project released under the [MIT license](https://github.com/snowpackjs/astro/blob/main/LICENSE). 77 | 78 | We care deeply about building a more sustainable future for open source software. At the same time, we need to support Astro's development long-term. This requires money (donations alone aren't enough.) 79 | 80 | We're inspired by the early success of projects like [Tailwind](https://tailwindcss.com/), [Rome](https://rome.tools/), [Remix](https://remix.run/), [Ionic](https://ionicframework.com/), and others who are experimenting with long-term financial sustainability on top of Open Source. Over the next year we'll be exploring how we can create a sustainable business to support a 100% free, open source Astro for years to come. 81 | 82 | If your company is as excited about Astro as we are, [we'd love to hear from you.](https://astro.build/chat) 83 | 84 | Finally, I'd like to give a **HUGE** thanks to the 300+ developers who joined our earliest private beta. Your feedback has been essential in shaping Astro into the tool it is today. If you're interested in getting involved (or just following along with development) please [join us on Discord.](https://astro.build/chat) 85 | 86 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 87 | -------------------------------------------------------------------------------- /src/pages/posts/introducing-astro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introducing Astro: Ship Less JavaScript" 3 | description: "We're excited to announce Astro as a new way to build static websites and deliver lightning-fast performance without sacrificing a modern developer experience." 4 | publishDate: "Tuesday, June 8 2021" 5 | author: "fred" 6 | heroImage: "/social.jpg" 7 | alt: "Astro" 8 | layout: "../../layouts/BlogPost.astro" 9 | --- 10 | 11 | There's a simple secret to building a faster website — _just ship less_. 12 | 13 | Unfortunately, modern web development has been trending in the opposite direction—towards _more._ More JavaScript, more features, more moving parts, and ultimately more complexity needed to keep it all running smoothly. 14 | 15 | Today I'm excited to publicly share Astro: a new kind of static site builder that delivers lightning-fast performance with a modern developer experience. To design Astro, we borrowed the best parts of our favorite tools and then added a few innovations of our own, including: 16 | 17 | - **Bring Your Own Framework (BYOF):** Build your site using React, Svelte, Vue, Preact, web components, or just plain ol' HTML + JavaScript. 18 | - **100% Static HTML, No JS:** Astro renders your entire page to static HTML, removing all JavaScript from your final build by default. 19 | - **On-Demand Components:** Need some JS? Astro can automatically hydrate interactive components when they become visible on the page. If the user never sees it, they never load it. 20 | - **Fully-Featured:** Astro supports TypeScript, Scoped CSS, CSS Modules, Sass, Tailwind, Markdown, MDX, and any of your favorite npm packages. 21 | - **SEO Enabled:** Automatic sitemaps, RSS feeds, pagination and collections take the pain out of SEO and syndication. 22 | 23 | This post marks the first public beta release of Astro. **Missing features and bugs are still to be expected at this early stage.** There are still some months to go before an official 1.0 release, but there are already several fast sites built with Astro in production today. We would love your early feedback as we move towards a v1.0 release later this year. 24 | 25 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 26 | 27 | ## Getting Started 28 | 29 | Starting a new project in Astro is easy: 30 | 31 | ```shell 32 | # create your project 33 | mkdir new-project-directory 34 | cd new-project-directory 35 | npm init astro 36 | 37 | # install your dependencies 38 | npm install 39 | 40 | # start the dev server and open your browser 41 | npm run dev 42 | ``` 43 | 44 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides). 45 | 46 | ## How Astro Works 47 | 48 | Astro works a lot like a static site generator. If you have ever used Eleventy, Hugo, or Jekyll (or even a server-side web framework like Rails, Laravel, or Django) then you should feel right at home with Astro. 49 | 50 | In Astro, you compose your website using UI components from your favorite JavaScript web framework (React, Svelte, Vue, etc). Astro renders your entire site to static HTML during the build. The result is a fully static website with all JavaScript removed from the final page. No monolithic JavaScript application required, just static HTML that loads as fast as possible in the browser regardless of how many UI components you used to generate it. 51 | 52 | Of course, sometimes client-side JavaScript is inevitable. Image carousels, shopping carts, and auto-complete search bars are just a few examples of things that require some JavaScript to run in the browser. This is where Astro really shines: When a component needs some JavaScript, Astro only loads that one component (and any dependencies). The rest of your site continues to exist as static, lightweight HTML. 53 | 54 | In other full-stack web frameworks this level of per-component optimization would be impossible without loading the entire page in JavaScript, delaying interactivity. In Astro, this kind of [partial hydration](https://addyosmani.com/blog/rehydration/) is built into the tool itself. 55 | 56 | You can even [automatically defer components](https://codepen.io/jonneal/full/ZELvMvw) to only load once they become visible on the page with the `client:visible` directive. 57 | 58 | This new approach to web architecture is called [islands architecture](https://jasonformat.com/islands-architecture/). We didn't coin the term, but Astro may have perfected the technique. We are confident that an HTML-first, JavaScript-only-as-needed approach is the best solution for the majority of content-based websites. 59 | 60 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 61 | 62 | ## Embracing the Pit of Success 63 | 64 | > A well-designed system makes it easy to do the right things and annoying (but not impossible) to do the wrong things

– Jeff Atwood

[Falling Into The Pit of Success](https://blog.codinghorror.com/falling-into-the-pit-of-success/)
65 | 66 | Poor performance is often framed as a failure of the developer, but we respectfully disagree. In many cases, poor performance is a failure of tooling. It should be difficult to build a slow website. 67 | 68 | Astro's main design principle is to lead developers into what [Rico Mariani](https://twitter.com/ricomariani) dubbed "the pit of success". It is our goal to build every site "fast by default" while also delivering a familiar, modern developer experience. 69 | 70 | By building your site to static HTML by default, Astro makes it difficult (but never impossible 😉) to build a slow site. 71 | 72 | ## Long-Term Sustainability 73 | 74 | Astro is built by the team of open source developers behind [Snowpack](https://snowpack.dev) and [Skypack](https://skypack.dev), with additional contributions from the community. 75 | 76 | **Astro is and always will be free.** It is an open source project released under the [MIT license](https://github.com/snowpackjs/astro/blob/main/LICENSE). 77 | 78 | We care deeply about building a more sustainable future for open source software. At the same time, we need to support Astro's development long-term. This requires money (donations alone aren't enough.) 79 | 80 | We're inspired by the early success of projects like [Tailwind](https://tailwindcss.com/), [Rome](https://rome.tools/), [Remix](https://remix.run/), [Ionic](https://ionicframework.com/), and others who are experimenting with long-term financial sustainability on top of Open Source. Over the next year we'll be exploring how we can create a sustainable business to support a 100% free, open source Astro for years to come. 81 | 82 | If your company is as excited about Astro as we are, [we'd love to hear from you.](https://astro.build/chat) 83 | 84 | Finally, I'd like to give a **HUGE** thanks to the 300+ developers who joined our earliest private beta. Your feedback has been essential in shaping Astro into the tool it is today. If you're interested in getting involved (or just following along with development) please [join us on Discord.](https://astro.build/chat) 85 | 86 | > To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides) 87 | -------------------------------------------------------------------------------- /src/pages/search.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import BaseHead from '../components/BaseHead.astro'; 3 | import BlogHeader from '../components/BlogHeader.astro'; 4 | import dotenv from 'dotenv'; 5 | dotenv.config(); 6 | 7 | let title = 'Search'; 8 | let description = 'Type the words you are searching for 🎱'; 9 | let permalink = 'https://example.com/'; 10 | --- 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |

{title}

23 |

{description}

24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 | 32 | 33 | {``} 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/pages/search.json.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const allPosts = Astro.fetchContent("./posts/*.md"); 3 | const json = JSON.stringify( 4 | allPosts.map((p) => { 5 | return { 6 | title: p.title, 7 | description: p.description, 8 | slug: p.url, 9 | }; 10 | }) 11 | ); 12 | --- 13 | {json} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleResolution": "node" 3 | } 4 | --------------------------------------------------------------------------------