merge in docs site (#705)
This commit is contained in:
parent
fb8bf7ec43
commit
166e22bdf3
51 changed files with 6939 additions and 91 deletions
2
docs/.prettierignore
Normal file
2
docs/.prettierignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
7
docs/.prettierrc
Normal file
7
docs/.prettierrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"endOfLine": "auto",
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 80
|
||||
}
|
17
docs/README.md
Normal file
17
docs/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Astro Docs <img width="19.2" height="25.6" src="https://raw.githubusercontent.com/snowpackjs/astro/main/assets/brand/logo.svg" alt="Astro logo">
|
||||
|
||||
## Contributing
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Every pull request needs to be reviewed by another contributor to the documentation to help with the overall quality of the documentation.
|
||||
|
||||
## Running this project
|
||||
|
||||
- Clone/Fork the project
|
||||
- This project uses yarn to manage dependencies. [Make sure that you have yarn v1 installed.](https://classic.yarnpkg.com/)
|
||||
- Run `yarn install` to install latest dependencies.
|
||||
- Run `yarn start` to start the dev server.
|
||||
- Run `yarn build` to build the final site for production.
|
||||
|
||||
The environment variable `SNOWPACK_PUBLIC_GITHUB_TOKEN` must be set to a personal access token with `public_repo` permissions to prevent rate-limiting.
|
6
docs/astro.config.mjs
Normal file
6
docs/astro.config.mjs
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
buildOptions: {
|
||||
site: 'https://astro-docs-preview.vercel.app/',
|
||||
},
|
||||
renderers: ['@astrojs/renderer-preact'],
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
layout: ~/layouts/Main.astro
|
||||
title: Data Fetching
|
||||
---
|
||||
|
||||
Astro components and pages can fetch remote data to help generate your pages. Astro provides two different tools to pages to help you do this: **fetch()** and **top-level await.**
|
||||
|
||||
### `fetch()`
|
||||
|
||||
Astro pages have access to the global `fetch()` function in their setup script. `fetch()` is a native JavaScript API ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)) that lets you make HTTP requests for things like APIs and resources.
|
||||
|
||||
Even though Astro component scripts run inside of Node.js (and not in the browser) Astro provides this native API so that you can fetch data at page build time.
|
||||
|
||||
```astro
|
||||
---
|
||||
const response = await fetch('http://example.com/movies.json');
|
||||
const data = await response.json();
|
||||
// Remember: Astro component scripts log to the CLI
|
||||
console.log(data);
|
||||
---
|
||||
<!-- Output the result to the page -->
|
||||
<div>{JSON.stringify(data)}</div>
|
||||
```
|
||||
|
||||
### Top-level await
|
||||
|
||||
`await` is another native JavaScript feature that lets you await the response of some asynchronous promise ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)). Astro supports `await` in the top-level of your component script.
|
||||
|
||||
**Important:** These are not yet available inside of non-page Astro components. Instead, do all of your data loading inside of your pages, and then pass them to your components as props.
|
22
docs/package.json
Normal file
22
docs/package.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "@astrojs/docs-template",
|
||||
"version": "0.0.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"lint": "run-p --aggregate-output lint:linkcheck",
|
||||
"lint:linkcheck": "start-test 'yarn start --silent' 3000 'yarn lint:linkcheck:local'",
|
||||
"lint:linkcheck:local": "blc -ro --user-agent 'broken-link-checker/0.7.8' 'http://localhost:3000'",
|
||||
"lint:linkcheck:remote": "blc -ro --user-agent 'broken-link-checker/0.7.8' 'https://astro-docs-preview.vercel.app/'",
|
||||
"format": "prettier -w \"**/*.{css,js,jsx,ts,tsx,md,json}\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@snowpack/plugin-dotenv": "^2.1.0",
|
||||
"astro": "^0.17.2",
|
||||
"broken-link-checker": "^0.7.8",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.3.2",
|
||||
"start-server-and-test": "^1.12.6"
|
||||
}
|
||||
}
|
155
docs/public/code.css
Normal file
155
docs/public/code.css
Normal file
|
@ -0,0 +1,155 @@
|
|||
.language-css > code,
|
||||
.language-sass > code,
|
||||
.language-scss > code {
|
||||
color: #fd9170;
|
||||
}
|
||||
|
||||
[class*="language-"] .namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.atrule {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.attr-name {
|
||||
color: #ffcb6b;
|
||||
}
|
||||
|
||||
.token.attr-value {
|
||||
color: #a5e844;
|
||||
}
|
||||
|
||||
.token.attribute {
|
||||
color: #a5e844;
|
||||
}
|
||||
|
||||
.token.boolean {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.builtin {
|
||||
color: #ffcb6b;
|
||||
}
|
||||
|
||||
.token.cdata {
|
||||
color: #80cbc4;
|
||||
}
|
||||
|
||||
.token.char {
|
||||
color: #80cbc4;
|
||||
}
|
||||
|
||||
.token.class {
|
||||
color: #ffcb6b;
|
||||
}
|
||||
|
||||
.token.class-name {
|
||||
color: #f2ff00;
|
||||
}
|
||||
|
||||
.token.comment {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.constant {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.deleted {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.token.doctype {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.hexcode {
|
||||
color: #f2ff00;
|
||||
}
|
||||
|
||||
.token.id {
|
||||
color: #c792ea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.important {
|
||||
color: #c792ea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: #80cbc4;
|
||||
}
|
||||
|
||||
.token.keyword {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.number {
|
||||
color: #fd9170;
|
||||
}
|
||||
|
||||
.token.operator {
|
||||
color: #89ddff;
|
||||
}
|
||||
|
||||
.token.prolog {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.property {
|
||||
color: #80cbc4;
|
||||
}
|
||||
|
||||
.token.pseudo-class {
|
||||
color: #a5e844;
|
||||
}
|
||||
|
||||
.token.pseudo-element {
|
||||
color: #a5e844;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #89ddff;
|
||||
}
|
||||
|
||||
.token.regex {
|
||||
color: #f2ff00;
|
||||
}
|
||||
|
||||
.token.selector {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.token.string {
|
||||
color: #a5e844;
|
||||
}
|
||||
|
||||
.token.symbol {
|
||||
color: #c792ea;
|
||||
}
|
||||
|
||||
.token.tag {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.token.unit {
|
||||
color: #fd9170;
|
||||
}
|
||||
|
||||
.token.url {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.token.variable {
|
||||
color: #ff6666;
|
||||
}
|
11
docs/public/favicon.svg
Normal file
11
docs/public/favicon.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="256" height="256" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
#flame { fill: #FF5D01; }
|
||||
#a { fill: #000014; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#a { fill: #fff; }
|
||||
}
|
||||
</style>
|
||||
<path id="a" fill-rule="evenodd" clip-rule="evenodd" d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z" />
|
||||
<path id="flame" fill-rule="evenodd" clip-rule="evenodd" d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
378
docs/public/index.css
Normal file
378
docs/public/index.css
Normal file
|
@ -0,0 +1,378 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:root {
|
||||
--user-font-scale: 1rem - 16px;
|
||||
--max-width: calc(100% - 2rem);
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
:root {
|
||||
--max-width: 46em;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
font-family: var(--font-body);
|
||||
font-size: 1rem;
|
||||
font-size: clamp(
|
||||
0.875rem,
|
||||
0.4626rem + 1.0309vw + var(--user-font-scale),
|
||||
1.125rem
|
||||
);
|
||||
line-height: 1.625;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content main > * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
:is(h1, h2, h3, h4, h5, h6) {
|
||||
margin-bottom: 1.38rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
:is(h1, h2) {
|
||||
max-width: 40ch;
|
||||
}
|
||||
|
||||
:is(h2, h3):not(:first-child) {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: clamp(1.2rem, 1.15rem + 0.125vw, 1.25rem);
|
||||
}
|
||||
|
||||
p,
|
||||
.content ul {
|
||||
color: var(--theme-text-light);
|
||||
}
|
||||
|
||||
small,
|
||||
.text_small {
|
||||
font-size: 0.833rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--theme-text-accent);
|
||||
font-weight: 400;
|
||||
text-underline-offset: 0.08em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
a > code:not([class*='language']) {
|
||||
position: relative;
|
||||
color: var(--theme-text-accent);
|
||||
background: transparent;
|
||||
text-underline-offset: var(--padding-block);
|
||||
}
|
||||
|
||||
a > code:not([class*='language'])::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
background: var(--theme-accent);
|
||||
opacity: var(--theme-accent-opacity);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:focus {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 0.25em;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Supporting Content */
|
||||
|
||||
code:not([class*='language']) {
|
||||
--border-radius: 3px;
|
||||
--padding-block: 0.2rem;
|
||||
--padding-inline: 0.33rem;
|
||||
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.85em;
|
||||
color: var(--theme-code-inline-text);
|
||||
background-color: var(--theme-code-inline-bg);
|
||||
padding: var(--padding-block) var(--padding-inline);
|
||||
margin: calc(var(--padding-block) * -1) -0.125em;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
pre > code:not([class*='language']) {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre {
|
||||
position: relative;
|
||||
background-color: var(--theme-code-bg);
|
||||
color: var(--theme-code-text);
|
||||
--padding-block: 1rem;
|
||||
--padding-inline: 2rem;
|
||||
padding: var(--padding-block) var(--padding-inline);
|
||||
padding-right: calc(var(--padding-inline) * 2);
|
||||
|
||||
line-height: 1.414;
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 37.75em) {
|
||||
pre {
|
||||
--padding-inline: 1.25rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 2rem 0;
|
||||
padding: 1.25em 1.5rem;
|
||||
border-left: 3px solid var(--theme-text-light);
|
||||
background-color: var(--theme-bg-offset);
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
header button {
|
||||
background-color: var(--theme-bg);
|
||||
}
|
||||
|
||||
header button:hover,
|
||||
header button:focus {
|
||||
outline: var(--theme-text) solid 1px;
|
||||
}
|
||||
|
||||
header button:active,
|
||||
header button[aria-pressed='true'] {
|
||||
background: var(--theme-text);
|
||||
color: var(--theme-bg);
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
gap: 0.25em;
|
||||
padding: 0.33em 0.67em;
|
||||
border: 0;
|
||||
background: var(--theme-bg);
|
||||
display: flex;
|
||||
font-size: 1rem;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
border-radius: 99em;
|
||||
color: var(--theme-text);
|
||||
background-color: var(--theme-bg);
|
||||
}
|
||||
|
||||
#theme-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
padding: 0.33em 0.67em;
|
||||
border-radius: 99em;
|
||||
background-color: var(--theme-bg);
|
||||
}
|
||||
|
||||
#theme-toggle > label:focus-within {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||
}
|
||||
|
||||
#theme-toggle > label {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
opacity: 0.5;
|
||||
transition: transform 120ms ease-out, opacity 120ms ease-out;
|
||||
}
|
||||
|
||||
#theme-toggle > label:hover,
|
||||
#theme-toggle > label:focus {
|
||||
transform: scale(1.125);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#theme-toggle .checked {
|
||||
color: var(--theme-accent);
|
||||
transform: scale(1.125);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[name='theme-toggle'] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
height: calc(100vh - 3.5rem);
|
||||
top: 3.5rem;
|
||||
}
|
||||
.sidebar-nav-inner {
|
||||
height: 100%;
|
||||
padding: 2rem 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
h2.heading {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
padding: 0.1rem 1rem;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.header-link {
|
||||
font-size: 1rem;
|
||||
padding: 0.1rem 0 0.1rem 1rem;
|
||||
border-left: 4px solid var(--theme-divider);
|
||||
}
|
||||
|
||||
.header-link:hover,
|
||||
.header-link:focus {
|
||||
border-left-color: var(--color-gray-300);
|
||||
}
|
||||
.header-link:focus-within {
|
||||
color: var(--theme-text-light);
|
||||
border-left-color: var(--color-gray-600);
|
||||
}
|
||||
|
||||
.header-link.depth-3 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
.header-link.depth-4 {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.header-link a {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.edit-on-github {
|
||||
text-decoration: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--theme-divider);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--theme-text-lighter);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--theme-text-light);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
/* Scrollbar - End */
|
||||
|
||||
/* Screenreader Only Text */
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
/* Screenreader Only Text - End */
|
||||
|
||||
:target {
|
||||
scroll-margin-top: 4rem;
|
||||
}
|
83
docs/public/theme.css
Normal file
83
docs/public/theme.css
Normal file
|
@ -0,0 +1,83 @@
|
|||
:root {
|
||||
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
|
||||
sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
--font-body: system-ui, var(--font-fallback);
|
||||
--font-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
|
||||
--color-white: #fff;
|
||||
--color-black: #000014;
|
||||
|
||||
--color-gray-50: #f9fafb;
|
||||
--color-gray-100: #f3f4f6;
|
||||
--color-gray-200: #e5e7eb;
|
||||
--color-gray-300: #d1d5db;
|
||||
--color-gray-400: #9ca3af;
|
||||
--color-gray-500: #6b7280;
|
||||
--color-gray-600: #4b5563;
|
||||
--color-gray-700: #374151;
|
||||
--color-gray-800: #1f2937;
|
||||
--color-gray-900: #111827;
|
||||
--color-gray-950: #090e18;
|
||||
|
||||
--color-blue: #3894ff;
|
||||
--color-blue-dark: #1c5fac;
|
||||
--color-blue-rgb: 56, 148, 255;
|
||||
--color-green: #17c083;
|
||||
--color-green-rgb: 23, 192, 131;
|
||||
--color-orange: #ff5d01;
|
||||
--color-orange-rgb: 255, 93, 1;
|
||||
--color-purple: #882de7;
|
||||
--color-purple-rgb: 136, 45, 231;
|
||||
--color-red: #ff1639;
|
||||
--color-red-rgb: 255, 22, 57;
|
||||
--color-yellow: #ffbe2d;
|
||||
--color-yellow-rgb: 255, 190, 45;
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--theme-accent: var(--color-blue);
|
||||
--theme-accent-rgb: var(--color-blue-rgb);
|
||||
--theme-accent-opacity: 0.1;
|
||||
--theme-divider: var(--color-gray-100);
|
||||
--theme-text: var(--color-gray-800);
|
||||
--theme-text-light: var(--color-gray-600);
|
||||
--theme-text-lighter: var(--color-gray-400);
|
||||
--theme-text-accent: var(--color-blue);
|
||||
--theme-bg: var(--color-white);
|
||||
--theme-bg-hover: var(--color-gray-50);
|
||||
--theme-bg-offset: var(--color-gray-100);
|
||||
--theme-bg-accent: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity));
|
||||
--theme-code-inline-bg: var(--color-gray-100);
|
||||
--theme-code-inline-text: var(--theme-text);
|
||||
--theme-code-bg: var(--color-gray-700);
|
||||
--theme-code-text: var(--color-gray-100);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--theme-bg);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
color-scheme: dark;
|
||||
--theme-accent-opacity: 0.3;
|
||||
--theme-divider: var(--color-gray-900);
|
||||
--theme-text: var(--color-gray-200);
|
||||
--theme-text-light: var(--color-gray-300);
|
||||
--theme-text-lighter: var(--color-gray-600);
|
||||
--theme-text-accent: var(--color-white);
|
||||
--theme-bg: var(--color-gray-800);
|
||||
--theme-bg-hover: var(--color-gray-600);
|
||||
--theme-bg-offset: var(--color-gray-950);
|
||||
--theme-code-inline-bg: var(--color-gray-600);
|
||||
--theme-code-inline-text: var(--color-white);
|
||||
--theme-code-bg: var(--color-gray-950);
|
||||
--theme-code-text: var(--color-white);
|
||||
}
|
||||
|
||||
::selection {
|
||||
color: var(--theme-text-accent);
|
||||
background-color: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity));
|
||||
}
|
12
docs/public/theme.js
Normal file
12
docs/public/theme.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
(() => {
|
||||
const root = document.documentElement;
|
||||
if (
|
||||
localStorage.theme === 'dark' ||
|
||||
(!('theme' in localStorage) &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
root.classList.add('theme-dark');
|
||||
} else {
|
||||
root.classList.remove('theme-dark');
|
||||
}
|
||||
})();
|
7
docs/snowpack.config.mjs
Normal file
7
docs/snowpack.config.mjs
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
alias: {
|
||||
components: './src/components',
|
||||
'~': './src',
|
||||
},
|
||||
plugins: ['@snowpack/plugin-dotenv'],
|
||||
};
|
16
docs/src/components/ArticleFooter.astro
Normal file
16
docs/src/components/ArticleFooter.astro
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
import AvatarList from './AvatarList.astro';
|
||||
const { path } = Astro.props;
|
||||
---
|
||||
|
||||
<footer>
|
||||
<AvatarList path={path} />
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
footer {
|
||||
margin-top: auto;
|
||||
padding: 2rem 0;
|
||||
border-top: 3px solid var(--theme-divider);
|
||||
}
|
||||
</style>
|
20
docs/src/components/AstroLogo.astro
Normal file
20
docs/src/components/AstroLogo.astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
const {size} = Astro.props;
|
||||
---
|
||||
<svg class="logo" width={size} height={size} viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
#flame {
|
||||
/* fill: #ff5d01; */
|
||||
fill: #3894ff;
|
||||
}
|
||||
#a {
|
||||
/* fill: #000014; */
|
||||
fill: #3894ff;
|
||||
}
|
||||
</style>
|
||||
<title>Logo</title>
|
||||
<path id="a" fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z" />
|
||||
<path id="flame" fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z" />
|
||||
</svg>
|
151
docs/src/components/AvatarList.astro
Normal file
151
docs/src/components/AvatarList.astro
Normal file
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
// fetch all commits for just this page's path
|
||||
const { path } = Astro.props;
|
||||
const url = `https://api.github.com/repos/snowpackjs/astro-docs/commits?path=${path}`;
|
||||
const commitsURL = `https://github.com/snowpackjs/astro-docs/commits/main/${path}`;
|
||||
|
||||
async function getCommits(url) {
|
||||
try {
|
||||
const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN;
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.'
|
||||
);
|
||||
}
|
||||
|
||||
const auth = `Basic ${Buffer.from(token, "binary").toString("base64")}`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: auth,
|
||||
"User-Agent": "astro-docs/1.0",
|
||||
},
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Request to fetch commits failed. Reason: ${res.statusText}
|
||||
Message: ${data.message}`
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.warn(`[error] /src/components/AvatarList.astro
|
||||
${e?.message ?? e}`);
|
||||
return new Array();
|
||||
}
|
||||
}
|
||||
|
||||
function removeDups(arr) {
|
||||
if (!arr) {
|
||||
return new Array();
|
||||
}
|
||||
let map = new Map();
|
||||
|
||||
for (let item of arr) {
|
||||
let author = item.author;
|
||||
// Deduplicate based on author.id
|
||||
map.set(author.id, { login: author.login, id: author.id });
|
||||
}
|
||||
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
const data = await getCommits(url);
|
||||
const unique = removeDups(data);
|
||||
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
|
||||
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
|
||||
|
||||
---
|
||||
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
|
||||
<div class="contributors">
|
||||
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}>
|
||||
|
||||
{recentContributors.map((item) => (
|
||||
<li><a href={`https://github.com/${item.login}`}><img alt={`Contributor ${item.login}`} title={`Contributor ${item.login}`} width="64" height="64" src={`https://avatars.githubusercontent.com/u/${item.id}`}/></a></li>
|
||||
|
||||
))}
|
||||
</ul>
|
||||
{additionalContributors > 0 && <span><a href={commitsURL}>{`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`}</a></span>}
|
||||
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-list {
|
||||
--avatar-size: 2.5rem;
|
||||
--avatar-count: 3;
|
||||
|
||||
display: grid;
|
||||
list-style: none;
|
||||
/* Default to displaying most of the avatar to
|
||||
enable easier access on touch devices, ensuring
|
||||
the WCAG touch target size is met or exceeded */
|
||||
grid-template-columns: repeat(
|
||||
var(--avatar-count),
|
||||
max(44px, calc(var(--avatar-size) / 1.15))
|
||||
);
|
||||
/* `padding` matches added visual dimensions of
|
||||
the `box-shadow` to help create a more accurate
|
||||
computed component size */
|
||||
padding: 0.08em;
|
||||
font-size: var(--avatar-size);
|
||||
}
|
||||
|
||||
@media (any-hover: hover) and (any-pointer: fine) {
|
||||
.avatar-list {
|
||||
/* We create 1 extra cell to enable the computed
|
||||
width to match the final visual width */
|
||||
grid-template-columns: repeat(
|
||||
calc(var(--avatar-count) + 1),
|
||||
calc(var(--avatar-size) / 1.75)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-list li {
|
||||
width: var(--avatar-size);
|
||||
height: var(--avatar-size);
|
||||
}
|
||||
|
||||
.avatar-list li:hover ~ li a,
|
||||
.avatar-list li:focus-within ~ li a {
|
||||
transform: translateX(33%);
|
||||
}
|
||||
|
||||
.avatar-list img,
|
||||
.avatar-list a {
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-list a {
|
||||
transition: transform 180ms ease-in-out;
|
||||
}
|
||||
|
||||
.avatar-list img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.avatar-list a:focus {
|
||||
outline: 2px solid transparent;
|
||||
/* Double-layer trick to work for dark and light backgrounds */
|
||||
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||
}
|
||||
|
||||
.contributors {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.contributors > * + * {
|
||||
margin-left: .75rem;
|
||||
}
|
||||
</style>
|
65
docs/src/components/DocSidebar.tsx
Normal file
65
docs/src/components/DocSidebar.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import type { FunctionalComponent } from 'preact';
|
||||
import { h } from 'preact';
|
||||
import { useState, useEffect, useRef } from 'preact/hooks';
|
||||
import EditOnGithub from './EditOnGithub';
|
||||
|
||||
const DocSidebar: FunctionalComponent<{ headers: any[]; editHref: string }> = ({
|
||||
headers = [],
|
||||
editHref,
|
||||
}) => {
|
||||
const itemOffsets = useRef([]);
|
||||
const [activeId, setActiveId] = useState<string>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const getItemOffsets = () => {
|
||||
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
|
||||
itemOffsets.current = Array.from(titles).map((title) => ({
|
||||
id: title.id,
|
||||
topOffset: title.getBoundingClientRect().top + window.scrollY,
|
||||
}));
|
||||
};
|
||||
|
||||
getItemOffsets();
|
||||
window.addEventListener('resize', getItemOffsets);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', getItemOffsets);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<nav class="sidebar-nav">
|
||||
<div class="sidebar-nav-inner">
|
||||
<h2 class="heading">On this page</h2>
|
||||
<ul>
|
||||
<li
|
||||
class={`header-link depth-2 ${
|
||||
activeId === 'overview' ? 'active' : ''
|
||||
}`.trim()}
|
||||
>
|
||||
<a href="#overview">Overview</a>
|
||||
</li>
|
||||
{headers
|
||||
.filter(({ depth }) => depth > 1 && depth < 4)
|
||||
.map((header) => (
|
||||
<li
|
||||
class={`header-link depth-${header.depth} ${
|
||||
activeId === header.slug ? 'active' : ''
|
||||
}`.trim()}
|
||||
>
|
||||
<a href={`#${header.slug}`}>{header.text}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<h2 class="heading">More</h2>
|
||||
<ul>
|
||||
<li class={`header-link depth-2`}>
|
||||
<EditOnGithub href={editHref} />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocSidebar;
|
25
docs/src/components/EditOnGithub.tsx
Normal file
25
docs/src/components/EditOnGithub.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import type { FunctionalComponent } from 'preact';
|
||||
import { h } from 'preact';
|
||||
|
||||
const EditOnGithub: FunctionalComponent<{ href: string }> = ({ href }) => {
|
||||
return (
|
||||
<a class="edit-on-github" href={href}>
|
||||
<svg
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
height="1em"
|
||||
width="1em"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 438.549 438.549"
|
||||
stroke="none"
|
||||
>
|
||||
<g>
|
||||
<path d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 0 1-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
<span>Edit on GitHub</span>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditOnGithub;
|
44
docs/src/components/MenuToggle.tsx
Normal file
44
docs/src/components/MenuToggle.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import type { FunctionalComponent } from 'preact';
|
||||
import { h, Fragment } from 'preact';
|
||||
import { useState, useEffect } from 'preact/hooks';
|
||||
|
||||
const MenuToggle: FunctionalComponent = () => {
|
||||
const [sidebarShown, setSidebarShown] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
if (sidebarShown) {
|
||||
body.classList.add('mobile-sidebar-toggle');
|
||||
} else {
|
||||
body.classList.remove('mobile-sidebar-toggle');
|
||||
}
|
||||
}, [sidebarShown]);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={sidebarShown ? 'true' : 'false'}
|
||||
id="menu-toggle"
|
||||
onClick={() => setSidebarShown(!sidebarShown)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Toggle sidebar</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default MenuToggle;
|
48
docs/src/components/Note.astro
Normal file
48
docs/src/components/Note.astro
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
const { type = 'tip', title } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class={`note type-${type}`}>
|
||||
{title && <label>{title}</label>}
|
||||
<slot />
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
.note {
|
||||
--padding-block: 1rem;
|
||||
--padding-inline: 1.25rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding: var(--padding-block) var(--padding-inline);
|
||||
margin-left: calc(var(--padding-inline) * -1);
|
||||
margin-right: calc(var(--padding-inline) * -1);
|
||||
|
||||
background: var(--theme-bg-offset);
|
||||
border-left: calc(var(--padding-inline) / 2) solid var(--color);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.note label {
|
||||
font-weight: 500;
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
/* .note :global(a) {
|
||||
color: var(--color);
|
||||
} */
|
||||
|
||||
.note.type-tip {
|
||||
--color: var(--color-green);
|
||||
--color-rgb: var(--color-green-rgb);
|
||||
}
|
||||
.note.type-warning {
|
||||
--color: var(--color-yellow);
|
||||
--color-rgb: var(--color-yellow-rgb);
|
||||
}
|
||||
.note.type-error {
|
||||
--color: var(--color-red);
|
||||
--color-rgb: var(--color-red-rgb);
|
||||
}
|
||||
</style>
|
69
docs/src/components/SiteSidebar.astro
Normal file
69
docs/src/components/SiteSidebar.astro
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
import { sidebar } from '../config.ts';
|
||||
const {currentPage} = Astro.props;
|
||||
---
|
||||
|
||||
|
||||
<nav>
|
||||
<ul class="nav-groups">
|
||||
{sidebar.map(category => (
|
||||
<li>
|
||||
<div class="nav-group">
|
||||
<h2 class="nav-group-title">{category.text}</h2>
|
||||
<ul>
|
||||
{category.children.map(child => (
|
||||
<li class={`nav-link ${currentPage === child.link ? 'is-active' : ''}`}><a href={`${Astro.site.pathname}${child.link}`}>{child.text}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
nav {
|
||||
position: sticky;
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
height: calc(100vh - 3.5rem);
|
||||
top: 3.5rem;
|
||||
}
|
||||
.nav-groups {
|
||||
height: 100%;
|
||||
padding: 2rem 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.nav-groups > li + li {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.nav-group-title {
|
||||
font-size: 1.0rem;
|
||||
font-weight: 700;
|
||||
padding: 0.1rem 2rem;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-link a {
|
||||
font-size: 1.0rem;
|
||||
margin: 1px;
|
||||
padding: 0.3rem 2rem;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
.nav-link a:hover,
|
||||
.nav-link a:focus {
|
||||
background-color: var(--theme-bg-hover);
|
||||
}
|
||||
|
||||
.nav-link.is-active a {
|
||||
color: var(--theme-text-accent);
|
||||
background-color: var(--theme-bg-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
</style>
|
97
docs/src/components/ThemeToggle.tsx
Normal file
97
docs/src/components/ThemeToggle.tsx
Normal file
|
@ -0,0 +1,97 @@
|
|||
import type { FunctionalComponent } from 'preact';
|
||||
import { h, Fragment } from 'preact';
|
||||
import { useState, useEffect } from 'preact/hooks';
|
||||
|
||||
const themes = ['system', 'light', 'dark'];
|
||||
|
||||
const icons = [
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 5a2 2 0 012-2h10a2 2 0 012 2v8a2 2 0 01-2 2h-2.22l.123.489.804.804A1 1 0 0113 18H7a1 1 0 01-.707-1.707l.804-.804L7.22 15H5a2 2 0 01-2-2V5zm5.771 7H5V5h10v7H8.771z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>,
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>,
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
||||
</svg>,
|
||||
];
|
||||
|
||||
const ThemeToggle: FunctionalComponent = () => {
|
||||
const [theme, setTheme] = useState(themes[0]);
|
||||
|
||||
useEffect(() => {
|
||||
const user = localStorage.getItem('theme');
|
||||
if (!user) return;
|
||||
setTheme(user);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (theme === 'system') {
|
||||
localStorage.removeItem('theme');
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
root.classList.add('theme-dark');
|
||||
} else {
|
||||
root.classList.remove('theme-dark');
|
||||
}
|
||||
} else {
|
||||
localStorage.setItem('theme', theme);
|
||||
if (theme === 'light') {
|
||||
root.classList.remove('theme-dark');
|
||||
} else {
|
||||
root.classList.add('theme-dark');
|
||||
}
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
<div id="theme-toggle">
|
||||
{themes.map((t, i) => {
|
||||
const icon = icons[i];
|
||||
const checked = t === theme;
|
||||
return (
|
||||
<label className={checked ? 'checked' : ''}>
|
||||
{icon}
|
||||
<input
|
||||
type="radio"
|
||||
name="theme-toggle"
|
||||
checked={checked}
|
||||
value={t}
|
||||
title={`Use ${t} theme`}
|
||||
aria-label={`Use ${t} theme`}
|
||||
onChange={() => setTheme(t)}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeToggle;
|
67
docs/src/config.ts
Normal file
67
docs/src/config.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
export const sidebar = [
|
||||
{
|
||||
text: 'Setup',
|
||||
link: '',
|
||||
children: [
|
||||
{ text: 'Installation', link: 'installation' },
|
||||
{ text: 'Quickstart', link: 'quick-start' },
|
||||
{ text: 'Examples', link: 'examples' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Basics',
|
||||
link: 'core-concepts',
|
||||
children: [
|
||||
{ text: 'Project Structure', link: 'core-concepts/project-structure' },
|
||||
{ text: 'Components', link: 'core-concepts/astro-components' },
|
||||
{ text: 'Pages', link: 'core-concepts/astro-pages' },
|
||||
{ text: 'Layouts', link: 'core-concepts/layouts' },
|
||||
{ text: 'Collections', link: 'core-concepts/collections' },
|
||||
{ text: 'Partial Hydration', link: 'core-concepts/component-hydration' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Guides',
|
||||
link: 'guides',
|
||||
children: [
|
||||
{ text: 'Styling & CSS', link: 'guides/styling' },
|
||||
{ text: 'Data Fetching', link: 'guides/data-fetching' },
|
||||
{ text: 'Markdown', link: 'guides/markdown-content' },
|
||||
{ text: 'Supported Imports', link: 'guides/imports' },
|
||||
// To be written when https://github.com/snowpackjs/astro/issues/501 is completed
|
||||
// { text: 'Pagination', link: 'guides/pagination' },
|
||||
{ text: 'Deploy a Website', link: 'guides/deploy' },
|
||||
{ text: 'Publish a Component', link: 'guides/publish-to-npm' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Reference',
|
||||
link: 'reference',
|
||||
children: [
|
||||
{ text: 'Built-In Components', link: 'reference/builtin-components' },
|
||||
{ text: 'API Reference', link: 'reference/api-reference' },
|
||||
{ text: 'CLI Reference', link: 'reference/cli-reference' },
|
||||
{
|
||||
text: 'Configuration Reference',
|
||||
link: 'reference/configuration-reference',
|
||||
},
|
||||
{ text: 'Renderer Reference', link: 'reference/renderer-reference' },
|
||||
],
|
||||
},
|
||||
// To add once rest of the site is complete
|
||||
// see https://github.com/snowpackjs/astro-docs/issues/9
|
||||
// {
|
||||
// text: 'Integrations',
|
||||
// link: 'integrations',
|
||||
// children: [
|
||||
// { text: 'Deploy Astro', link: 'integrations/deploy-astro' },
|
||||
// { text: 'Data Sources / CMS', link: 'integrations/data-sources-cms' },
|
||||
// { text: 'State Management', link: 'integrations/state-management' },
|
||||
// {
|
||||
// text: 'Styles & CSS Libraries',
|
||||
// link: 'integrations/styles-and-css-libraries',
|
||||
// },
|
||||
// { text: 'Developer Tools', link: 'integrations/developer-tools' },
|
||||
// ],
|
||||
// },
|
||||
];
|
248
docs/src/layouts/Main.astro
Normal file
248
docs/src/layouts/Main.astro
Normal file
|
@ -0,0 +1,248 @@
|
|||
---
|
||||
import ArticleFooter from '../components/ArticleFooter.astro';
|
||||
import SiteSidebar from '../components/SiteSidebar.astro';
|
||||
import ThemeToggle from '../components/ThemeToggle.tsx';
|
||||
import DocSidebar from '../components/DocSidebar.tsx';
|
||||
import MenuToggle from '../components/MenuToggle.tsx';
|
||||
|
||||
const { content } = Astro.props;
|
||||
const headers = content?.astro?.headers;
|
||||
const currentPage = Astro.request.url.pathname;
|
||||
const currentFile = currentPage === '/' ? 'src/pages/index.md' : `src/pages${currentPage.replace(/\/$/, "")}.md`;
|
||||
const githubEditUrl = `https://github.com/snowpackjs/astro-docs/blob/main/${currentFile}`;
|
||||
---
|
||||
|
||||
<html lang="{content.lang ?? 'en-us'}">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{content.title}</title>
|
||||
|
||||
<link rel="stylesheet" href="/theme.css" />
|
||||
<link rel="stylesheet" href="/code.css" />
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<script src="/theme.js" />
|
||||
<link rel="icon"
|
||||
type="image/svg+xml"
|
||||
href="/favicon.svg">
|
||||
|
||||
<style>
|
||||
body {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 3.5rem 1fr;
|
||||
--gutter: 0.5rem;
|
||||
--doc-padding: 2rem;
|
||||
}
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
height: 56px;
|
||||
width: 100%;
|
||||
background-color: var(--theme-bg-offset);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns:
|
||||
minmax(var(--gutter), 1fr)
|
||||
minmax(0, var(--max-width))
|
||||
minmax(var(--gutter), 1fr);
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.menu-and-logo {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
#site-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
color: var(--theme-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#site-title:hover,
|
||||
#site-title:focus {
|
||||
color: var(--theme-text-light);
|
||||
}
|
||||
|
||||
#site-title h1 {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
max-width: 82em;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.layout :global(> *) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
height: calc(100vh - 3.5rem);
|
||||
max-height: 100vh;
|
||||
position: sticky;
|
||||
top: 3.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#sidebar-site {
|
||||
position: fixed;
|
||||
background-color: var(--theme-bg);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#article {
|
||||
padding: var(--doc-padding) var(--gutter);
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 75ch;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content > main {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
display: none;
|
||||
}
|
||||
.theme-toggle-wrapper {
|
||||
display: none;
|
||||
}
|
||||
#sidebar-site {
|
||||
display: none;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) {
|
||||
overflow: hidden;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) #sidebar-site {
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 60em) {
|
||||
#sidebar-site {
|
||||
display: flex;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) {
|
||||
overflow: initial;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) #sidebar-site {
|
||||
display: flex;
|
||||
}
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
}
|
||||
.layout {
|
||||
grid-template-columns:
|
||||
20rem
|
||||
minmax(0, var(--max-width));
|
||||
}
|
||||
#article {
|
||||
grid-column: 2;
|
||||
}
|
||||
#sidebar-site {
|
||||
position: sticky;
|
||||
}
|
||||
#sidebar-content {
|
||||
/* display: flex; */
|
||||
grid-column: 3;
|
||||
}
|
||||
.theme-toggle-wrapper {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 82em) {
|
||||
.layout {
|
||||
grid-template-columns:
|
||||
20rem
|
||||
minmax(0, var(--max-width))
|
||||
18rem;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#sidebar-site {
|
||||
grid-column: 1;
|
||||
}
|
||||
#article {
|
||||
grid-column: 2;
|
||||
}
|
||||
#sidebar-content {
|
||||
display: flex;
|
||||
grid-column: 3;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<nav class="nav-wrapper">
|
||||
<div class="menu-and-logo flex">
|
||||
<div class="menu-toggle">
|
||||
<MenuToggle client:idle/>
|
||||
</div>
|
||||
<a id="site-title" href="/">
|
||||
<h1>Astro Documentation</h1>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div />
|
||||
|
||||
<div class="theme-toggle-wrapper">
|
||||
<ThemeToggle client:idle />
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="layout">
|
||||
<aside class="sidebar" id="sidebar-site">
|
||||
<SiteSidebar currentPage={currentPage.slice(1)} />
|
||||
</aside>
|
||||
<div id="article">
|
||||
<article class="content">
|
||||
<main>
|
||||
<h1 class="content-title" id="overview">{content.title}</h1>
|
||||
<slot />
|
||||
</main>
|
||||
<ArticleFooter path={currentFile} />
|
||||
</article>
|
||||
</div>
|
||||
<aside class="sidebar" id="sidebar-content">
|
||||
<DocSidebar client:idle headers={headers} editHref={githubEditUrl} />
|
||||
</aside>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
240
docs/src/pages/blog/island-architecture.md
Normal file
240
docs/src/pages/blog/island-architecture.md
Normal file
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
layout: ~/layouts/Main.astro
|
||||
title: Island Architecture
|
||||
draft: true
|
||||
---
|
||||
<!--
|
||||
@aFuzzyBear: I have been spending most the day learning more about Island Architecture, wrote plenty of notes, listened to Fred K Schott's interview on Speakeasy(https://www.youtube.com/watch?v=mgkwZqVkrwo) and the interview with Jason Lengstrof (https://www.youtube.com/watch?v=z15YLsLMtu4)
|
||||
Figured I might give writing this a wee go,
|
||||
|
||||
I wanted to take this from the direction of it being more of a critique of the past and present state of affairs in web dev
|
||||
Post structure:
|
||||
1)Start with an introduction to Islands Arch
|
||||
2)Talk about the different Architectures that can be used in Web-dev
|
||||
3)MVC/StaticSites - SPA's
|
||||
4)Frameworks, get some external links onto the page
|
||||
4)Moving to ESM
|
||||
5)Benefits of ESM
|
||||
6)
|
||||
|
||||
-->
|
||||
|
||||
<!-- Intro -->
|
||||
|
||||
> "No man is an island. However, Web Components should be"
|
||||
|
||||
The concept behind Island architecture comes from [Jason Miller](https://twitter.com/_developit), The creator of [Preact](https://preactjs.com/) and a Google, DevRel Engineer.
|
||||
|
||||
In the summer of 2020, he managed to formulated his thoughts of how web architecture should be, in the idyllic sense, and placed them onto his [blog post](https://jasonformat.com/islands-architecture/).
|
||||
|
||||
His seminal post outlines and discusses the general concept of 'islands' as an architectural design process that could be used in Web Development, allowing for better improvements in overall site performance, SEO, UX, and everywhere else. His given explanation describing this new paradigm, was extraordinarily succinct:
|
||||
|
||||
> "The general idea of an *“Islands”* architecture is deceptively simple: Render HTML pages on the server, and inject placeholders or slots around highly dynamic regions. These placeholders/slots contain the server-rendered HTML output from their corresponding widget. They denote regions that can then be "hydrated" on the client into small self-contained widgets, reusing their server-rendered initial HTML."-Jason Miller
|
||||
|
||||
To develop a better understanding of what Jason meant with his proposal, let's quickly explore the backdrop, before we explain 'Island Architecture' and how it is applied into Astro as our primary ethos.
|
||||
|
||||
## Programming Paradigms
|
||||
|
||||
Think of a simple webpage. On which are many different types of components that are shown on this page, components that are shared across the site, others contain fixed content, some are a bit more elaborate that may perhaps use different state's or need to fetch multiple data streams from external sources.
|
||||
|
||||
Such an site would would have very few actual 'moving' pieces, or *dynamic* elements. For the most part the content tends to be fixed, and static.
|
||||
|
||||
In order to allow for dynamism and interactivity we are often left making overly complex solutions to deliver the slightest form of action on the application.
|
||||
|
||||
Complexity becomes inherent in the design process of the application. As a result, developers have to adopt some dogma, that comes from certain architectural design styles and patterns.
|
||||
|
||||
Given the [catalogue of patterns](https://en.wikipedia.org/wiki/List_of_software_architecture_styles_and_patterns) that are available, utilizing the right architecture for the application often comes from hard-to-obtain experience.
|
||||
|
||||
Web developers tend to gravitate towards tried and tested practices, and none fit the requirements better than the [Model-View-Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) (**MVC**) design pattern.
|
||||
|
||||
Where the **Model** contains the data structures and logic that governs the use of the data in the application. **Views** are the visual representation of the data that the user sees, and the **Controller** connects the views to their relevant data *Models* based on their interactions with the User.
|
||||
|
||||
This design pattern works well for our [client-server](https://en.wikipedia.org/wiki/Client%E2%80%93server_model) based applications. Since the models are placed on the *servers*, the views that are sent back over the wire tend to be static *documents*, controllers are sent along with the static files to facilitate the behaviours that web developers created for their application, in the form of *scripts*.
|
||||
|
||||
## Rise of the Frameworks
|
||||
|
||||
A vast swathe of libraries, frameworks and tooling rose up to meet the challenges of providing a Developer Experience (DX) that would let them create their applications, *'freely'*.
|
||||
|
||||
Helping to abstract away much of the complexity needed in implementing architectural design decisions into their application.
|
||||
|
||||
The likes of; [ASP.NET](https://dotnet.microsoft.com/learn/aspnet/what-is-aspnet-core) and [Blazor](https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor) for [.NET](https://dotnet.microsoft.com/), [Ruby On Rails](https://rubyonrails.org/), [Laravel](https://laravel.com/) & [Symphony](https://symfony.com/) for [PHP](https://www.php.net/), are examples of the MVC patterns seen in other server-side programming languages.
|
||||
|
||||
For along time, JavaScript was solely restricted to the Browser, then [Node.js](https://nodejs.org/en/) appeared. Node.js is a standalone JavaScript runtime built on the Chrome V8 engine.
|
||||
|
||||
This was a seismic shift that occurred in Web Development, by allowing JavaScript to escape the browser and operate on the server, developers could use JS on both; Front & Back-ends, when developing their applications.
|
||||
|
||||
Within the new JavaScript + Node ecosystem, JS MVC frameworks began to appear, e.g: [BackboneJS](https://backbonejs.org/), [ExpressJS](https://expressjs.com/), [Ember](https://emberjs.com/), [MeteorJS](https://www.meteor.com/), to name but a few.
|
||||
|
||||
This pattern of statically generated content on the server was becoming a bit of a performance bottleneck.
|
||||
|
||||
Where some asset-heavy page would take longer to render on the server than a lighter page.
|
||||
|
||||
This would block subsequent requests being made to the server, and more crucially responses being sent back from the server.
|
||||
|
||||
Server performance and optimisation only addressed the problem so far, but with larger payloads and pages being sent more frequently, something had to be done.
|
||||
|
||||
Frameworks, rose again to the challenge of delivering a better User Experience (UX) began to ship [Single Page Applications](https://en.wikipedia.org/wiki/Single-page_application) (**SPA**) to the client.
|
||||
|
||||
SPA's became a fast and effective ways to sending feature-rich applications to the client without the load being placed on the server.
|
||||
|
||||
Instead rendering the application would now be carried out wholly on the client device. Thus allowing the Server to send a single, simple, page to the client.
|
||||
|
||||
There are many benefits in providing a SPA to Clients. SPA's never needs a page refresh, since all the files (HTML/CSS/JS) had already been sent over the wire.
|
||||
|
||||
This only required the End-User's web browser to then read and render the application to the screen.
|
||||
|
||||
But SPA's came with their own hidden cost that comes with abstracting away the complexity. Recognising the many issues with SPA's from a holistic DX to a seamless UX/UI.
|
||||
|
||||
Frameworks began to appear in the ecosystem that allowed developers to build even more advanced Single-Page-Applications.
|
||||
|
||||
Some of these were developed by industry leaders, such as Google with their [Angular Project](https://angularjs.org/), [React](https://reactjs.org/) which was open sourced by Facebook. Or by the JS community themselves driving changes with [Preact](https://preactjs.com/), [Vue](https://vuejs.org/) and [Svelte](https://svelte.dev/), [Webpack](https://webpack.js.org/) & [Babel](https://babeljs.io/setup)
|
||||
|
||||
## The Status Quo
|
||||
|
||||
Its slightly hubris to suggest that the web development ecosystem had at all settled for any period of time, well at least long enough for a Status Quo to coalesce.
|
||||
|
||||
However, given the vibrancy and versatility of the ecosystem, a status quo had indeed began to take hold.
|
||||
|
||||
Rooted in the deepest annals of the developers psyche, was the slow conformity towards embracing UI frameworks to build the whole site as applications instead of the dynamic components that it was meant for.
|
||||
|
||||
Everything ended up being sent to the Client. From Rendering to Routing, bundled payload sizes drastically increased, and client devices were asked to do a lot more.
|
||||
|
||||
By placing the onus on the client, Server stress was indeed lessened. But there was a cost to this status quo.
|
||||
|
||||
The End-User experience was drastically suffering, for their devices now became the bottleneck, unable to execute the massive payloads that were being sent back from the server.
|
||||
|
||||
As demonstrated, JavaScript and its community are quick to change in certain places and slow in others. The gradual adoption of [EcmaScript Modules](https://tc39.es/ecma262/#sec-modules)(**ESM**) as a standard to the JavaScript spec was a complete sea-change to the ecosystem.
|
||||
|
||||
Prior to the formalisation of ESM, module usage in JS were often limited to libraries and were difficult to use outside the browser.
|
||||
|
||||
Using community developed conventions, helped push the goal of a modular ecosystem with [CommonJS](https://en.wikipedia.org/wiki/CommonJS)(**CJS**).
|
||||
|
||||
Node v12 shipped with ESM Modules as part of the standard in node. Signalling the start of something entirely new.
|
||||
|
||||
## The Great Migration
|
||||
|
||||
ESM adoption was indeed slow, the gradual migration from `require()` to `import()` took a while.
|
||||
|
||||
Now developing in an ESM world, allows for certain advantages to be exploited.
|
||||
|
||||
This wanting exploitation of new features have given way for another influx of new libraries, frameworks, tooling and a whole suite of new methods of writing JS.
|
||||
|
||||
We are now experiencing new tools in the ecosystem that feature ESM as defaults.
|
||||
|
||||
By doing so we can take full advantage of unbundled developer environments, allowing for projects to start-up in the tens of milliseconds, instead of whole seconds and full minutes.
|
||||
|
||||
Using ESM in the Browser, tools can build once and cache forever. Tree-shaking and code optimisations can occur, more frequently and with greater efficacy. Reducing massive bundle sizes down to a few hundred Kilobytes.
|
||||
|
||||
Tools like [Snowpack](https://www.snowpack.dev/) and [Vite](https://vitejs.dev/) introduce an whole new experience that developers were previously denied in their development process and that is speed.
|
||||
|
||||
With cut-edge DX features like [HMR](https://npm.io/package/esm-hmr) has quickly became the industry de facto, and build times reduced by a factor of 100x.
|
||||
|
||||
This new generation of ESM tools is extremely encouraging for web developers.
|
||||
|
||||
## A Brave New World
|
||||
|
||||
Into this new age ESM world, we have had a dearth of innovation from the established frameworks to address some of the root issues that plagued web development over its time.
|
||||
|
||||
Basic questions of : Websites or WebApp's were still unresolved. Where to render the site, on the server or on the client, perhaps a bit of both? What determines the need for dynamic content and what specifies content to be static?
|
||||
|
||||
Witnessing frameworks slowly go full circle and return to Server-Side-Rendering (*SSR*) their applications was in part only allowed to be considered in an ESM world, however it was bit of an admission of culpability of sorts.
|
||||
|
||||
By inadvertently admitting that the current model is flawed, opened up the space for a new form of discourse to enter, and help redefine the ecosystem moving forward.
|
||||
|
||||
SSR frameworks such as [Next.js](https://nextjs.org/), [Nuxt.js](https://nuxtjs.org/), [SvelteKit](https://kit.svelte.dev/), did help address some of the underling questions, within the current paradigm.
|
||||
|
||||
Developing methods and techniques to deliver production-stable SSR along with tooling and support for the developer.
|
||||
|
||||
But in a new age, retaining previously disputed tenants only aided the lack of innovation in this new dawn.
|
||||
|
||||
Jason Miller's formulations of an 'Island'-styled approach only augments the discussion with fresh new ideas about Website and Application development.
|
||||
|
||||
## The Golden Isles and its many Islands
|
||||
|
||||
In the introduction we placed a quote from Jason, describing the general concept of Island architecture. Let's revisit his words, since we have a better understanding of the context in which this is being proposed.
|
||||
|
||||
Jason asks us to think of a Island architecture as a static HTML document. One that is rendered entirely on the server.
|
||||
|
||||
The document contains multiple separate embedded applications, that are injected into placeholders or '*slots*', which form dynamic regions on the page.
|
||||
|
||||
The Server renders HTML outputs form each of these dynamic components, and places them onto the static document being sent back down to the End-User.
|
||||
|
||||
These slots, of dynamic regions, can then be '*hydrated*'. [Hydration](https://en.wikipedia.org/wiki/Hydration_(web_development)) is a process that allows for Client-Sided JS to convert and make static HTML, dynamic, reusing their initial server-rendered HTML.
|
||||
|
||||
This 'micro' architecture is similar to both 'micro-frontends' and 'micro-services'. Both share the concept of breaking applications into small indivisible units. But the problem is that a lot of the small modular units are rarely composed in HTML.
|
||||
|
||||
With Island-Architecture, he proposes a form of progressive enhancement for the dynamic components by using a technique known as *Partial Hydration*.
|
||||
|
||||
Lets look at this following analogy:
|
||||
|
||||
On our Static page, we have an image carousel. Such carousel needs to have some form of interactivity to load the next image after a certain amount of time has elapsed, along with navigation and pagination buttons on the carousel.
|
||||
|
||||
To do this we would need to implement some behaviour on our carousel.
|
||||
|
||||
In the traditional sense, we might be using a React Component to help create the aforementioned experience. In order to do this we would have too include the React-runtime plugin as a top-level `<script>` within our HTML document.
|
||||
|
||||
This means for our page, we need to wait for React to be fetched and downloaded, then parsed and executed, have it wait for the page to display the carousel before we receive the behaviour and functionality we expect from our small dynamic component.
|
||||
|
||||
Instead of this laborious process, one would simply render the carousel in HTML on the server and have a dedicated `<script>` that is emitted when the component for the carousel is displayed.
|
||||
|
||||
This would then load the functionality for the carousel in-place, transforming it instantly into a dynamic image slide show, with navigation.
|
||||
|
||||
## Island Hydration
|
||||
|
||||
By now the idea of Island-architecture must be settling in, and one must be thinking, this is just [Progressive Hydration](https://en.wikipedia.org/wiki/Hydration_(web_development)#Progressive_rehydration), and you wouldn't be overly off mark.
|
||||
|
||||
Progressive Hydration that is used in frameworks like: Angluar, React, Preact, Vue. Are individual components, which are loaded and then initialised over a period of time.
|
||||
|
||||
Using scheduling processes, and accounting for things like viewport visibility, content value, probability of interaction etc. They can abstract away the intricacies and delivery this form of hydration for developers.
|
||||
|
||||
By using Island styled components, this form of hydration essentially comes for **free**.
|
||||
|
||||
Since the larger dynamic components on a page are being initialised separately, not progressively. The difference lets individual regions on the page to become interactive without the page requiring to first load anything.
|
||||
|
||||
This expands further, as it doesn't need any form of ['Top-down Rendering'](https://developers.google.com/web/fundamentals/performance/rendering).
|
||||
|
||||
Since there is no outer `<div id='root'>` element that needs to be initialised before the inner contents can be exposed.
|
||||
|
||||
Every region of the page is an isolated unit, an island, on its own, connected to others by the HTML page. With such an approach the benefits do begin to stack up.
|
||||
|
||||
A key benefit is seen with the site performance. Since isolation is inherent, if a single issue affects a component, it wouldn't affect the other *islands* on the page.
|
||||
|
||||
## Exploring the Island
|
||||
|
||||
As we explore further into the Island, we can see immediate trade differences between framework produced SSR solutions and those that could be provided by using Island Architecture.
|
||||
|
||||
Quickly wandering back to the Status Quo for a brief interlude. We use SSR with SPA's to help tackle the downside of SPA's and its SEO. Appealing to the search engines in this manner has another negative affect on the UX.
|
||||
|
||||
>"...visitors are left waiting for the actual functionality of a page to arrive while staring at a frustratingly fake version of that page." - Jason Miller
|
||||
|
||||
There are other issues that stem from traditional SSR, and being idly unawares of such performance pitfalls, gives rise to an orchestra of potential problems.
|
||||
|
||||
Further compounded with misconceptions on implementations and utilisations of solid SSR techniques, this practice is increasingly prominent amongst the Status Quoticians.
|
||||
|
||||
The one most obvious drawback with SSR is the amount of work JS has to do during the initial page load, is far excessive than is necessary, and is extremely inefficient use of resources.
|
||||
|
||||
We find with our "Islands" model, that with Server rendering is a fundamental part of how pages are delivered to the browser.
|
||||
|
||||
The responded HTML, would still contain all the rendered content that the user requested. With some islands yet to engage their client-sided interactivity. The document sent should contain all the content that the User would need.
|
||||
|
||||
An example of this would be a product page for a e-commerce business. A product page, using the Islands model would contain that products description, price etc, Having the dynamic components becoming interactive on demand.
|
||||
|
||||
We also discover that with the Islands model we have better accessibility and discoverability of our elements and the contents within.
|
||||
|
||||
Less code is eventually shipped from each island which is a massive cost-saving benefit.
|
||||
|
||||
However the conceptual idea of using Islands from a Web developers viewpoint is that, we get to come full circle and begin to deliver lightening fast user experiences without having the previous trade-offs and penalties that came from previous design models.
|
||||
|
||||
They're plenty of more important discoveries yet to be made when exploring the Island Architecture model in more detail.
|
||||
|
||||
Jason finished his post with the following:
|
||||
|
||||
> "It's possible...that adopting a model like this requires more up-front design thinking. There are far few batteries-included options available ...Who knows, maybe we can fix that." - August 2020
|
||||
|
||||
## Astrolands
|
||||
|
||||
<!-- Conclusion, final words. Here tie in Astro -->
|
||||
|
||||
Here at Astro, we fully embrace the principles ideas behind Jason's 'Island Architecture'. As a result, we have been hard at work trying to apply this new innovative concept into Web Development and the JS ecosystem.
|
||||
|
||||
We would like to take this time to encourage you to start exploring how Astro accomplishes this. And experience how easy it is to adopt as an architectural design philosophy.
|
|
@ -26,7 +26,7 @@ For example, this three-line file is a valid Astro component:
|
|||
</div>
|
||||
```
|
||||
|
||||
An Astro component represents some snippet of HTML in your project. This can be a reusable component, or an entire page of HTML including `<html>`, `<head>` and `<body>` elements. See our guide on [Astro Pages](/guides/astro-pages) to learn how to build your first full HTML page with Astro.
|
||||
An Astro component represents some snippet of HTML in your project. This can be a reusable component, or an entire page of HTML including `<html>`, `<head>` and `<body>` elements. See our guide on [Astro Pages](/core-concepts/astro-pages) to learn how to build your first full HTML page with Astro.
|
||||
|
||||
**Every Astro component must include an HTML template.** While you can enhance your component in several ways (see below) at the end of the day its the HTML template that dictates what your rendered Astro component will look like.
|
||||
|
||||
|
@ -53,7 +53,7 @@ For best results, you should only have one `<style>` tag per-Astro component. Th
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
...;
|
||||
...
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -197,7 +197,7 @@ const { greeting = 'Hello', name } = Astro.props;
|
|||
|
||||
Slots become even more powerful when using **named slots**. Rather than a single `<slot>` element which renders _all_ children, named slots allow you to specify multiple places where children should be placed.
|
||||
|
||||
> **Note** The `slot` attribute is not restricted to plain HTML, components can use `slot` as well!
|
||||
> **Note:** The `slot` attribute is not restricted to plain HTML, components can use `slot` as well!
|
||||
|
||||
```astro
|
||||
<!-- Example: MyComponent.astro -->
|
||||
|
@ -212,7 +212,7 @@ Slots become even more powerful when using **named slots**. Rather than a single
|
|||
</main>
|
||||
<footer>
|
||||
<!-- children with the `slot="footer"` attribute will go here -->
|
||||
<slot name="footer">
|
||||
<slot name="footer" />
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
@ -308,7 +308,6 @@ Astro provides a `<slot />` component so that you can control where any children
|
|||
| User-Defined Components | `<Capitalized>` | `<Capitalized>` |
|
||||
| Expression Syntax | `{}` | `{}` |
|
||||
| Spread Attributes | `{...props}` | `{...props}` |
|
||||
| Children | `<slot>` (with named slot support) | `children` |
|
||||
| Boolean Attributes | `autocomplete` === `autocomplete={true}` | `autocomplete` === `autocomplete={true}` |
|
||||
| Inline Functions | `{items.map(item => <li>{item}</li>)}` | `{items.map(item => <li>{item}</li>)}` |
|
||||
| IDE Support | WIP - [VS Code][code-ext] | Phenomenal |
|
||||
|
@ -331,7 +330,7 @@ It’s important to note that Astro **won’t** transform HTML references for yo
|
|||
|
||||
Since `src/pages/about.astro` will build to `/about/index.html`, you may not have expected that image to live at `/about/thumbnail.png`. So to fix this, choose either of two options:
|
||||
|
||||
### Option 1: Absolute URLs
|
||||
#### Option 1: Absolute URLs
|
||||
|
||||
```html
|
||||
<!-- ✅ Correct: references public/thumbnail.png -->
|
||||
|
@ -340,7 +339,7 @@ Since `src/pages/about.astro` will build to `/about/index.html`, you may not hav
|
|||
|
||||
The recommended approach is to place files within `public/*`. This references a file it `public/thumbnail.png`, which will resolve to `/thumbnail.png` at the final build (since `public/` ends up at `/`).
|
||||
|
||||
### Option 2: Asset import references
|
||||
#### Option 2: Asset import references
|
||||
|
||||
```astro
|
||||
---
|
|
@ -208,3 +208,4 @@ export async function createCollection() {
|
|||
- API Reference: [collection](/reference/api-reference#collections-api)
|
||||
- API Reference: [createCollection()](/reference/api-reference#createcollection)
|
||||
- API Reference: [Creating an RSS feed](/reference/api-reference#rss-feed)
|
||||
|
|
@ -51,6 +51,8 @@ Besides the obvious performance benefits of sending less JavaScript down to the
|
|||
|
||||
![diagram](https://res.cloudinary.com/wedding-website/image/upload/v1596766231/islands-architecture-1.png)
|
||||
|
||||
|
||||
|
||||
## Hydrate Interactive Components
|
||||
|
||||
Astro renders every component on the server **at build time**. To hydrate components on the client **at runtime**, you may use any of the following `client:*` directives. A directive is a component attribute (always with a `:`) which tells Astro how your component should be rendered.
|
||||
|
@ -66,26 +68,22 @@ import MyReactComponent from '../components/MyReactComponent.jsx';
|
|||
```
|
||||
|
||||
### `<MyComponent client:load />`
|
||||
|
||||
Hydrate the component on page load.
|
||||
|
||||
### `<MyComponent client:idle />`
|
||||
|
||||
Hydrate the component as soon as main thread is free (uses [requestIdleCallback()][mdn-ric]).
|
||||
|
||||
### `<MyComponent client:visible />`
|
||||
|
||||
Hydrate the component as soon as the element enters the viewport (uses [IntersectionObserver][mdn-io]). Useful for content lower down on the page.
|
||||
|
||||
### `<MyComponent client:media={QUERY} />`
|
||||
|
||||
Hydrate the component as soon as the browser matches the given media query (uses [matchMedia][mdn-mm]). Useful for sidebar toggles, or other elements that should only display on mobile or desktop devices.
|
||||
|
||||
## Can I Hydrate Astro Components?
|
||||
|
||||
[Astro components](./astro-components) (`.astro` files) are HTML-only templating components with no client-side runtime. If you try to hydrate an Astro component with a `client:` modifier, you will get an error.
|
||||
|
||||
To make your Astro component interactive, you will need to convert it to the frontend framework of your choice: React, Svelte, Vue, etc. If you have no preference, we reccomend React or Preact as most similar to Astro's syntax.
|
||||
To make your Astro component interactive, you will need to convert it to the frontend framework of your choice: React, Svelte, Vue, etc. If you have no preference, we recommend React or Preact as most similar to Astro's syntax.
|
||||
|
||||
Alternatively, you could add a `<script>` tag to your Astro component HTML template and send JavaScript to the browser that way. While this is fine for the simple stuff, we recommend a frontend framework for more complex interactive components.
|
||||
|
|
@ -54,10 +54,12 @@ import BaseLayout from '../layouts/BaseLayout.astro'
|
|||
</BaseLayout>
|
||||
```
|
||||
|
||||
|
||||
## Nesting Layouts
|
||||
|
||||
You can nest layouts when you want to create more specific page types without copy-pasting. It is common in Astro to have one generic `BaseLayout` and then many more specific layouts (`PostLayout`, `ProductLayout`, etc.) that reuse and build on top of it.
|
||||
|
||||
|
||||
```astro
|
||||
---
|
||||
// src/layouts/PostLayout.astro
|
||||
|
@ -124,7 +126,6 @@ Layouts are essential for Markdown files. Markdown files can declare a layout in
|
|||
title: Blog Post
|
||||
layout: ../layouts/PostLayout.astro
|
||||
---
|
||||
|
||||
This blog post will be **rendered** inside of the `<PostLayout />` layout.
|
||||
```
|
||||
|
|
@ -10,7 +10,6 @@ Astro includes an opinionated folder layout for your project. Every Astro projec
|
|||
- `package.json` - A project manifest.
|
||||
|
||||
The easiest way to set up your new project is with `npm init astro`. Check out our [Installation Guide](/quick-start) for a walkthrough of how to set up your project automatically (with `npm init astro`) or manually.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
|
@ -29,10 +28,10 @@ The src folder is where most of your project source code lives. This includes:
|
|||
|
||||
- [Astro Components](/core-concepts/astro-components)
|
||||
- [Pages](/core-concepts/astro-pages)
|
||||
- [Markdown](/core-concepts/astro-pages)
|
||||
- [Layouts](/core-concepts/astro-pages)
|
||||
- [Layouts](/core-concepts/layouts)
|
||||
- [Frontend JS Components](/core-concepts/component-hydration)
|
||||
- [Styling (CSS, Sass)](/guides/styling)
|
||||
- [Markdown](/guides/markdown-content)
|
||||
|
||||
Astro has complete control over how these files get processed, optimized, and bundled in your final site build. Some files (like Astro components) never make it to the browser directly and are instead rendered to HTML. Other files (like CSS) are sent to the browser but may be bundled with other CSS files depending on how your site uses.
|
||||
|
64
docs/src/pages/guides/data-fetching.md
Normal file
64
docs/src/pages/guides/data-fetching.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
layout: ~/layouts/Main.astro
|
||||
title: Data Fetching
|
||||
---
|
||||
|
||||
Astro components and pages can fetch remote data to help generate your pages. Astro provides two different tools to pages to help you do this: **fetch()** and **top-level await.**
|
||||
|
||||
## `fetch()`
|
||||
|
||||
Astro pages have access to the global `fetch()` function in their setup script. `fetch()` is a native JavaScript API ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)) that lets you make HTTP requests for things like APIs and resources.
|
||||
|
||||
Even though Astro component scripts run inside of Node.js (and not in the browser) Astro provides this native API so that you can fetch data at page build time.
|
||||
|
||||
```astro
|
||||
---
|
||||
// Movies.astro
|
||||
const response = await fetch('https://example.com/movies.json');
|
||||
const data = await response.json();
|
||||
// Remember: Astro component scripts log to the CLI
|
||||
console.log(data);
|
||||
---
|
||||
<!-- Output the result to the page -->
|
||||
<div>{JSON.stringify(data)}</div>
|
||||
```
|
||||
|
||||
## Top-level await
|
||||
|
||||
`await` is another native JavaScript feature that lets you await the response of some asynchronous promise ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)). Astro supports `await` in the top-level of your component script.
|
||||
|
||||
**Important:** These are not yet available inside of non-page Astro components. Instead, do all of your data loading inside of your pages, and then pass them to your components as props.
|
||||
|
||||
## Using `fetch()` outside of Astro Components
|
||||
|
||||
If you want to use `fetch()` in a non-astro component, use the [`node-fetch`](https://github.com/node-fetch/node-fetch) library:
|
||||
|
||||
```tsx
|
||||
// Movies.tsx
|
||||
import fetch from 'node-fetch';
|
||||
import type { FunctionalComponent } from 'preact';
|
||||
import { h } from 'preact';
|
||||
|
||||
const data = fetch('https://example.com/movies.json').then((response) =>
|
||||
response.json()
|
||||
);
|
||||
|
||||
// Components that are build-time rendered also log to the CLI.
|
||||
// If you loaded this component with a directive, it would log to the browser console.
|
||||
console.log(data);
|
||||
|
||||
const Movies: FunctionalComponent = () => {
|
||||
// Output the result to the page
|
||||
return <div>{JSON.stringify(data)}</div>;
|
||||
};
|
||||
|
||||
export default Movies;
|
||||
```
|
||||
|
||||
If you load a component using `node-fetch` [interactively](/core-concepts/component-hydration), with `client:load`, `client:visible`, etc., you'll need to either not use `node-fetch` or switch to an [isomorphic](https://en.wikipedia.org/wiki/Isomorphic_JavaScript) library that will run both at build time and on the client, as the [`node-fetch` README.md](https://github.com/node-fetch/node-fetch#motivation) reccomends:
|
||||
|
||||
> Instead of implementing XMLHttpRequest in Node.js to run browser-specific [Fetch polyfill](https://github.com/github/fetch), why not go from native http to fetch API directly? Hence, node-fetch, minimal code for a window.fetch compatible API on Node.js runtime.
|
||||
>
|
||||
> See Jason Miller's [isomorphic-unfetch](https://www.npmjs.com/package/isomorphic-unfetch) or Leonardo Quixada's [cross-fetch](https://github.com/lquixada/cross-fetch) for isomorphic usage (exports node-fetch for server-side, whatwg-fetch for client-side).
|
||||
|
||||
> Quoted from https://github.com/node-fetch/node-fetch#motivation
|
|
@ -20,6 +20,8 @@ The following guides are based on some shared assumptions:
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Building The App
|
||||
|
||||
You may run `npm run build` command to build the app.
|
||||
|
@ -63,7 +65,6 @@ By default, the build output will be placed at `dist/`. You may deploy this `dis
|
|||
|
||||
cd -
|
||||
```
|
||||
|
||||
> You can also run the above script in your CI setup to enable automatic deployment on each push.
|
||||
|
||||
### GitHub Actions
|
|
@ -7,11 +7,11 @@ Astro comes with out-of-the-box Markdown support powered by the expansive [remar
|
|||
|
||||
## Remark and Rehype Plugins
|
||||
|
||||
In addition to [custom components inside the `<Markdown>` component](#markdown-component), Astro comes with [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants), and syntax highlighting via [Prism](https://prismjs.com/) pre-enabled.
|
||||
In addition to custom components inside the [`<Markdown>` component](/guides/markdown-content#markdown-component), Astro comes with [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants), and syntax highlighting via [Prism](https://prismjs.com/) pre-enabled.
|
||||
|
||||
Also, Astro supports third-party plugins for Markdown. You can provide your plugins in `astro.config.mjs`.
|
||||
|
||||
> **Note** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired.
|
||||
> **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired.
|
||||
|
||||
## Add a markdown plugin in Astro
|
||||
|
||||
|
@ -166,11 +166,11 @@ const expressions = 'Lorem ipsum';
|
|||
- Rich component support like any `.astro` file!
|
||||
- Recursive Markdown support (Component children are also processed as Markdown)
|
||||
|
||||
<MyFancyCodePreview:visible>
|
||||
<MyFancyCodePreview client:visible>
|
||||
```jsx
|
||||
const object = { someOtherValue };
|
||||
```
|
||||
</MyFancyCodePreview:visible>
|
||||
</MyFancyCodePreview client:visible>
|
||||
</Markdown>
|
||||
</Layout>
|
||||
````
|
|
@ -492,7 +492,7 @@ Also please check out the [Stylelint][stylelint] project to whip your styles int
|
|||
[css-modules]: https://github.com/css-modules/css-modules
|
||||
[css-treeshaking]: https://css-tricks.com/how-do-you-remove-unused-css-from-a-site/
|
||||
[fouc]: https://en.wikipedia.org/wiki/Flash_of_unstyled_content
|
||||
[layout-isolated]: https://visly.app/blogposts/layout-isolated-components
|
||||
[layout-isolated]: https://web.archive.org/web/20210227162315/https://visly.app/blogposts/layout-isolated-components
|
||||
[issues]: https://github.com/snowpackjs/astro/issues
|
||||
[magic-number]: https://css-tricks.com/magic-numbers-in-css/
|
||||
[material-ui]: https://material.io/components
|
251
docs/src/pages/index.astro
Normal file
251
docs/src/pages/index.astro
Normal file
|
@ -0,0 +1,251 @@
|
|||
---
|
||||
import SiteSidebar from '../components/SiteSidebar.astro';
|
||||
import AstroLogo from '../components/AstroLogo.astro';
|
||||
import ThemeToggle from '../components/ThemeToggle.tsx';
|
||||
import MenuToggle from '../components/MenuToggle.tsx';
|
||||
---
|
||||
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Astro Documentation</title>
|
||||
<link rel="stylesheet" href="/theme.css" />
|
||||
<link rel="stylesheet" href="/code.css" />
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<script src="/theme.js" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
|
||||
<style>
|
||||
body {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 3.5rem 1fr;
|
||||
--gutter: 0.5rem;
|
||||
--doc-padding: 2rem;
|
||||
}
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
height: 56px;
|
||||
width: 100%;
|
||||
background-color: var(--theme-bg-offset);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns:
|
||||
minmax(var(--gutter), 1fr)
|
||||
minmax(0, var(--max-width))
|
||||
minmax(var(--gutter), 1fr);
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.menu-and-logo {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
#site-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
color: var(--theme-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#site-title:hover,
|
||||
#site-title:focus {
|
||||
color: var(--theme-text-light);
|
||||
}
|
||||
|
||||
#site-title h1 {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
max-width: 82em;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.layout :global(> *) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
height: calc(100vh - 3.5rem);
|
||||
max-height: 100vh;
|
||||
position: sticky;
|
||||
top: 3.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#sidebar-site {
|
||||
position: fixed;
|
||||
background-color: var(--theme-bg);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
|
||||
#article {
|
||||
padding: var(--doc-padding) var(--gutter);
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(data:font/woff;base64,d09GRgABAAAAAAigAA0AAAAACqQAAQABAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABMAAAADQAAAA0kw2CAk9TLzIAAAFkAAAAYAAAAGB1F9HrU1RBVAAAAcQAAAA2AAAANuQoygBjbWFwAAAB/AAAAFQAAABUAPMBf2dhc3AAAAJQAAAACAAAAAgAAAAQZ2x5ZgAAAlgAAAQ6AAAFYr8pubRoZWFkAAAGlAAAADYAAAA2ATWcDmhoZWEAAAbMAAAAJAAAACQKsQEqaG10eAAABvAAAAAaAAAAGggEAvRsb2NhAAAHDAAAABoAAAAaB+0GtW1heHAAAAcoAAAAIAAAACAAKwE6bmFtZQAAB0gAAAE4AAACaDSWWWJwb3N0AAAIgAAAACAAAAAg/20AZQABAAAACgAyADIABERGTFQAHmN5cmwAGmdyZWsAGmxhdG4AGgAAAAAABAAAAAD//wAAAAAABATNAlgABQAABZoFMwAAAR8FmgUzAAAD0QBmAgAAAAAAAAkAAAAAAAAAAAABAAAAAAAAAAAAAAAAR09PRwBAACAAdAhi/dUAAAhiAisgAAGfTwEAAAQ6BbAAAAAgAAEAAQABAAgAAgAAABQAAQAAACQAAndnaHQBAAAAaXRhbAELAAEAAgADAAEAAgERAAAAAAABAAAAAAAAAAIAAAADAAAAFAADAAEAAAAUAAQAQAAAAAwACAACAAQAIABhAGkAcAB0//8AAAAgAGEAaQBsAHL////h/6H/mv+Y/5cAAQAAAAAAAAAAAAAAAAABAAH//wAPeJx1lF1s21QUx++1nbRN8+XE14kTx4nj1k7r5qOxnXRJlyZp0o+sH9NaVq2DrgOpqJStEoO1o5UQIB5gmhCiUB5Qn8bQ3kB7GWiI7WXaQOIBZRIPSLyBxNgkPh4mlbrctMBSJKz7cO7x8T2/c/7HFxBgffcXapiaAAYYBeC0aMiyQeuyIstS1NpitSJRz2QzGS3N+lgWob+dTGOnpRtvsizbGW3EG/uBGrI2QsgB2IrQUH/hyumlj3O5w5BkEFtN6JPBQOCj858NVIey6d6L09qs3FnwU07zj+4iYtlQKLIwsuGIh8NjdPe5o/C7uUvJZDKbTF4YFDQPwwb8vmJXRe2OvzVbXVHVFEPT8YCQvYxorxGWiz4ucMsXpz0IEKAOADVm+R60gSAAU0ikRSQaIg330DHovxXWYcn8klw1vzF/FHg+z+dLJDlejGa9DEvl7u0s1+vkAmSjfS63xWapZbIVxuPVAYDgDs5wwgpwhqbz78Bx8xr5jnnLCu5tX63XLT04chJHruAe5wAoSbRGZ5paire6bvzX81iAFvkfGyZ+eGBxtDkiyBuxt9t/olztdsGLbbvzgRSJHE/HykHU4WwLeHwFZfxMmMpt3yYNh7/VbrfZ7Wr4z99I0eYgnWxbq81md2DH76R9Zk2RJcbjVPyc4vR6JgYblW1g3hrmDQNwTjxIKx5gU6QNSLpkHz+spid5XoBEpjf95rHiC6mQxrp/Jgmuy+VlmAA3U95ZILZevKzrqY4oo4U/wAot7d6n5nEWDmiNDjbNlGE0JbEYByaQafikvYlbqpSLX1xYvVEqVirF8g1sFcsVSIQEYa5UnhNC+BHmiuVTghAiFLRyt1abmqrV7q6g89icnsbmRVRdS6YymVRyrYqG1xMNM7GO2TbNeWoas4VAFrOJNPs/cLgDsBlJae7WJiSYbn9srm9hK2P09WUyW8/qJzsFnbU9JD4P8PxsQSk12u7qDvr7OwZOhPigOU8AJDlZ/3Rt9KuX2Je/Hh05yjJulT+z8xANreN/gXa5e4LwW6HH7XDqCQwLIIxhvWYwLcLzhbEURaKbZPPKMvn28vUy0f4rJD25mPTkIX05K0eepyYWT3Kb27eJd5PDGNfhgLDd3dD/DazMBD4P3wil5uKkZo32urC/DigkNt8eex/sL/KY3xecycdnpGgP9ahUKFxfXfq0UKiU+/NXnh6aDQQR5+MmjfzxIGIhUTp8+JOzi1fz+YFCX/bDU0eeEQQfVDiV9rIexJSTg6+l9YFetWd1ZOxsTNHodt5Dq1wgQXuRwCEtVHslmTCMRHx1sLqoxA55nQLt6WrU9iqubchSBhKuTaQlpNHNl5lifVyuQeMfmnjd3NndzWrpS08knlLVI3zQYwjhwbA6EuB4+J65ZCmbj26a4Ln3U72JttZWv/uaxUZZWhjON9kP79/8C/efFZQAAAABAAAAAwAAqqqrX18PPPUACwgAAAAAAMTwES4AAAAA2tg/q/wF/dUGRwhiAAAACQACAAAAAAAAAAEAAAhi/dUAAATN/AX+hgZHAAEAAAAAAAAAAAAAAAAAAAABBM0AAAAAAHwA1ADIAE8AlABrAJcBKACFAIEAAAAAAAAAAABsAJ0AsgEKAT0BiwHiAgoCeAKxAAAAAQAAAAwAsQAWAIcABQABAAAAAAAAAAAAAAAAAAMAAXicjZDNSsNAFIW/tFWQloI7cZWFSBVaq+JG3dQiRfCPWnRdY4yRtglJivoKPoRP4cIH8wE8mY41IIJc7sy5M+ecO3OBKq+UcSpLwLuzabFDwylZXKLOp8VlDvmwuFLgLLDKm8WLrPNscZ0BazPsQI0Vi6vCNYuXheCciIQxQ0ackJk9xOMGX3vAg87yzIjZZ0vxZKIlZqz0dOuryl0C3c7UPhNSralOTuXb5VidrrQ22RG7TV+KW2WmPFNOlE0xfL0l5EjViDuuVSdyCQ3DZddo8/hBB/S4UPSE/ufaVx0wFR7Kvahx5yr3l6qrPeZFiu+5uPpLm232hAZmDu6fbpfSRTyK4xllR/3zyUbmfy6N+ZRTO+dAfXLGVH4tqSK9Jj+NFIFe5HNv3DMz5aTQd2y7bnwB/ANcKwADAAAAAAAA/2oAZAAAAAEAAAAAAAAAAAAAAAAAAAAA) format('woff');
|
||||
}
|
||||
|
||||
.npm-init-snippet {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 1.6rem;
|
||||
background-color: var(--theme-code-inline-bg);
|
||||
color: var(--theme-text);
|
||||
border-radius: 6px;
|
||||
padding: 4px 14px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content > main {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
display: none;
|
||||
}
|
||||
.theme-toggle-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sidebar-site {
|
||||
display: none;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) {
|
||||
overflow: hidden;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) #sidebar-site {
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 60em) {
|
||||
#sidebar-site {
|
||||
display: flex;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) {
|
||||
overflow: initial;
|
||||
}
|
||||
:global(.mobile-sidebar-toggle) #sidebar-site {
|
||||
display: flex;
|
||||
}
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
}
|
||||
.layout {
|
||||
grid-template-columns:
|
||||
20rem
|
||||
minmax(0, 1fr);
|
||||
}
|
||||
#article {
|
||||
grid-column: 2;
|
||||
}
|
||||
#sidebar-site {
|
||||
position: sticky;
|
||||
}
|
||||
#sidebar-nav {
|
||||
display: flex;
|
||||
}
|
||||
.theme-toggle-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 82em) {
|
||||
.layout {
|
||||
grid-template-columns:
|
||||
20rem
|
||||
minmax(0, var(--max-width))
|
||||
18rem;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#sidebar-nav {
|
||||
grid-column: 1;
|
||||
}
|
||||
#article {
|
||||
grid-column: 2/4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="mobile-sidebar-hidden">
|
||||
<header>
|
||||
<nav class="nav-wrapper">
|
||||
<div class="menu-and-logo flex">
|
||||
<div class="menu-toggle">
|
||||
<MenuToggle client:idle/>
|
||||
</div>
|
||||
<a id="site-title" href="/">
|
||||
<h1>Astro Documentation</h1>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div />
|
||||
|
||||
<div class="theme-toggle-wrapper">
|
||||
<ThemeToggle client:idle />
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="layout">
|
||||
<aside class="sidebar" id="sidebar-site">
|
||||
<SiteSidebar currentPage="" />
|
||||
</aside>
|
||||
<div id="article">
|
||||
<article class="content">
|
||||
<AstroLogo size={160} />
|
||||
<div class="npm-init-snippet">
|
||||
npm init astro
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -25,7 +25,7 @@ npm run build
|
|||
|
||||
To deploy your Astro site to production, upload the contents of the `/dist` folder (generated by running `npm run build`) to your favorite hosting provider.
|
||||
|
||||
[Read more about deploying Astro in the Deploy guide](/guides/deploy)
|
||||
[Read more about deploying Astro in the Deploy guide.](/guides/deploy)
|
||||
|
||||
## Start your project
|
||||
|
|
@ -65,7 +65,6 @@ const data = Astro.fetchContent('../pages/post/*.md'); // returns an array of po
|
|||
`Astro.site` returns a `URL` made from `buildOptions.site` in your Astro config. If undefined, this will return a URL generated from `localhost`.
|
||||
|
||||
## Collections API
|
||||
|
||||
### `collection` prop
|
||||
|
||||
```jsx
|
||||
|
@ -177,3 +176,4 @@ export default function () {
|
|||
```
|
||||
|
||||
[canonical]: https://en.wikipedia.org/wiki/Canonical_link_element
|
||||
|
|
@ -17,9 +17,9 @@ import { Markdown } from 'astro/components';
|
|||
```
|
||||
|
||||
See our [Markdown Guide](/guides/markdown-content) for more info.
|
||||
|
||||
<!-- TODO: We should move some of the specific component info here. -->
|
||||
|
||||
|
||||
## `<Prism />`
|
||||
|
||||
```astro
|
|
@ -9,7 +9,7 @@ title: CLI Reference
|
|||
|
||||
Runs the Astro development server. This starts an HTTP server that responds to requests for pages stored in `src/pages` (or which folder is specified in your [configuration](/reference/configuration-reference)).
|
||||
|
||||
See the [dev server](./dev.md) docs for more information on how the dev server works.
|
||||
See the [dev server](/reference/dev) docs for more information on how the dev server works.
|
||||
|
||||
**Flags**
|
||||
|
4773
docs/yarn.lock
Normal file
4773
docs/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue